{"id":1893,"date":"2022-11-29T09:00:00","date_gmt":"2022-11-29T17:00:00","guid":{"rendered":"https:\/\/journal.copperspice.com\/?p=1893"},"modified":"2022-12-12T19:22:25","modified_gmt":"2022-12-13T03:22:25","slug":"source-code-gui-example-34","status":"publish","type":"post","link":"https:\/\/journal.copperspice.com\/?p=1893","title":{"rendered":"Source Code &nbsp;(Gui Example 34)"},"content":{"rendered":"\n<p>The program for this example displays a plain TextEdit widget which contains source code. Portions of the text are highlighted in various colors using the GUI syntax highlighting class.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &lt;QtCore&gt;\n#include &lt;QtGui&gt;\n\n#include &quot;syntax.h&quot;\n\nclass MainWindow : public QMainWindow\n{\n public:\n   MainWindow();\n\n private:\n   Syntax *m_syntaxParser;\n   QString loadText();\n};\n<\/pre><\/div>\n\n\n<p>The MainWindow class declares a private pointer to a Syntax object and a method which is used to load the text displayed in the TextEdit widget. The Syntax class will be created in this example.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [9,37]; title: ; notranslate\" title=\"\">\nMainWindow::MainWindow()\n{\n   setMinimumSize(700, 650);\n\n   QWidget *centralWidget = new QWidget(this);\n   setCentralWidget(centralWidget);\n\n   QPlainTextEdit *textEdit = new QPlainTextEdit();\n   textEdit-&gt;setPlainText(loadText());\n\n   QFont font = textEdit-&gt;font();\n   font.setPointSize(11);\n   textEdit-&gt;setFont(font);\n\n   QPushButton *pb_close = new QPushButton();\n   pb_close-&gt;setText(&quot;Close&quot;);\n\n   QHBoxLayout *layout_text = new QHBoxLayout();\n   layout_text-&gt;setContentsMargins(20, 15, 20, 0);\n   layout_text-&gt;addWidget(textEdit);\n\n   QHBoxLayout *layout_pb = new QHBoxLayout();\n   layout_pb-&gt;addStretch();\n   layout_pb-&gt;addWidget(pb_close);\n   layout_pb-&gt;addStretch();\n\n   QVBoxLayout *layout = new QVBoxLayout();\n   layout-&gt;addLayout(layout_text);\n   layout-&gt;addSpacing(15);\n   layout-&gt;addLayout(layout_pb);\n\n   centralWidget-&gt;setLayout(layout);\n\n   connect(pb_close, &amp;QPushButton::clicked, \n         this, &amp;QWidget::close);\n\n   m_syntaxParser = new Syntax(textEdit-&gt;document());\n   m_syntaxParser-&gt;processSyntax();\n}\n\nQString MainWindow::loadText()\n{\n   QString retval = &quot;sample text&quot;;\n\n   QFile file(&quot;..\/sample.txt&quot;);\n   bool ok = file.open(QIODevice::ReadOnly);\n\n   if (ok) {\n      retval = QString::fromUtf8(file.readAll());\n   }\n\n   return retval;\n}\n<\/pre><\/div>\n\n\n<p>The user interface for this example creates a new QPlainTextEdit and a QPushButton. On line 9 the textEdit is initialized with the contents of the &#8220;sample.txt&#8221; file when <span style=\"color:#6a5acd\" class=\"has-inline-color\">loadText()<\/span> is called. The code for lines 18 though 32 configure the layout of the controls on the main window. <br><br>On line 37 a new Syntax object is created. On the following line is a call to <span style=\"color:#6a5acd\" class=\"has-inline-color\">processSyntax()<\/span>, which is a method of the Syntax class.  <br><br>The purpose of the Syntax class is to define a set of regular expressions which will be used to determine if a given word should be highlighted.  <\/p>\n\n\n\n<h3>Syntax Highlighting<\/h3>\n\n\n\n<p>The QSyntaxHighlighter class is part of the CopperSpice GUI library. It was designed as an abstract class which is used as a base class in a given application. An abstract class contains at least one pure<em> <\/em>virtual method. In order to implement syntax highlighting we will create a new class which inherits from QSyntaxHighlighter. The other requirement is to override the virtual <span style=\"color:#6a5acd\" class=\"has-inline-color\">highlightBlock()<\/span> method in the Syntax class.<br><br>The header file <span style=\"color:#6a5acd\" class=\"has-inline-color\"><strong>syntax.h<\/strong><\/span> contains the declaration for class Syntax. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [17]; title: ; notranslate\" title=\"\">\n\/\/ portion of syntax.h\n\nclass Syntax : public QSyntaxHighlighter\n{\n   CS_OBJECT(Syntax)\n\n public:\n   Syntax(QTextDocument *document);\n   bool processSyntax();\n\n protected:\n   void highlightBlock(const QString &amp;text) override;\n\n private:\n   static QByteArray readJson(QString fileName);\n\n   struct HighlightingRule {\n      QRegularExpression pattern;\n      QTextCharFormat format;\n   };\n\n   QVector&lt;HighlightingRule&gt; highlightingRules;\n};\n<\/pre><\/div>\n\n\n<p>The Syntax header declares a vector to store a structure of rules. Each structure object contains a regular expression and a format indicating how to color the words which match the given regular expression.<br><br>The source <strong><span style=\"color:#6a5acd\" class=\"has-inline-color\">syntax.cpp<\/span><\/strong> contains the implementation for class Syntax.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; first-line: 1; highlight: [14,28,44]; title: ; notranslate\" title=\"\">\n\/\/ portion of syntax.cpp\n\nbool Syntax::processSyntax()\n{\n   QByteArray data = readJson(&quot;..\/syn_cpp.json&quot;);\n\n   QJsonDocument doc  = QJsonDocument::fromJson(data);\n   QJsonObject object = doc.object();\n   QJsonArray list;\n\n   HighlightingRule rule;\n\n   \/\/ keywords\n   list = object.value(&quot;keywords&quot;).toArray();\n\n   rule.format.setFontItalic(false);\n   rule.format.setForeground(QColor(0,0,255));\n\n   for (const auto &amp;item : list) {\n      rule.pattern = QRegularExpression(item.toString());\n      highlightingRules.append(rule);\n   }\n\n   \/\/ ** highlighting rules for other categories\n\n   \/\/ ** special rules for quoted text, single line comments\n  \n   rehighlight();\n\n   return true;\n}\n\nvoid Syntax::highlightBlock(const QString &amp;text)\n{\n   QRegularExpressionMatch match;\n\n   for (auto &amp;rule : highlightingRules) {\n      match = rule.pattern.match(text);\n\n      while (match.hasMatch()) {\n         int index  = match.capturedStart(0) - text.begin();\n         int length = match.capturedLength();\n\n         setFormat(index, length, rule.format);\n\n         \/\/ get new match\n         match = rule.pattern.\n               match(text, match.capturedEnd(0));\n      }\n   }\n}\n<\/pre><\/div>\n\n\n<p>The Syntax cpp file implements two methods. The <span style=\"color:#6a5acd\" class=\"has-inline-color\">processSyntax()<\/span> method reads and parses a json file. It contains a list of regular expression strings which are grouped by different keys. Looking at our code, on line 14 the strings for Keywords are stored in the variable list. <br><br>The strings are used by the <span style=\"color:#6a5acd\" class=\"has-inline-color\">highlightBlock()<\/span> method to decipher if a given word matches a particular regular expression. If a match is found the formatting for the given key is used.  For example, if the word is a keyword like &#8220;constexpr&#8221; or &#8220;return&#8221; then it will be shown in blue as defined on line 17.<br><br>On line 28 is a required call to the base class. The <span style=\"color:#6a5acd\" class=\"has-inline-color\">rehighlight()<\/span> method will run the highlighting process on the entire document. <br><br>The call to <span style=\"color:#6a5acd\" class=\"has-inline-color\">setFormat()<\/span> on line 44 passes the formatting rules to the base class. QSyntaxHighlighter is responsible for updating the document based on the new formatting definitions. <\/p>\n\n\n\n<h3>Build Files<\/h3>\n\n\n\n<p>This example introduces the idea of using multiple source files. The syntax highlighting source was separated into a header file (syntax.h) which contains the class declaration and a source file (syntax.cpp) which contains the implementation.  <br><br>The relevant lines of the build file are shown below. The complete build is available in the zip file.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nlist(APPEND PROJECT_INCLUDES\n   ${CMAKE_CURRENT_SOURCE_DIR}\/syntax.h\n)\n\nlist(APPEND PROJECT_SOURCES\n   ${CMAKE_CURRENT_SOURCE_DIR}\/main.cpp\n   ${CMAKE_CURRENT_SOURCE_DIR}\/syntax.cpp\n)\n\nadd_executable(${PROJECT_NAME} \n   ${PROJECT_INCLUDES} \n   ${PROJECT_SOURCES}\n)\n<\/pre><\/div>\n\n\n<h3>Main Function<\/h3>\n\n\n\n<p>Since the source code for main() has not changed there is no need to show it again. Refer to example 3 or download the full source for this example.<\/p>\n\n\n\n<h3>Running the Example<\/h3>\n\n\n\n<p>To build and run this example use the same CMake build file and commands as we showed for the first example. The only suggested modification is on line 2 of the CMakeLists.txt file, change &#8220;example_1&#8221; to &#8220;example_34&#8221;. <\/p>\n\n\n\n<p><a href=\"https:\/\/download.copperspice.com\/journal\/example_34.zip\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/download.copperspice.com\/journal\/example_34.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The program for this example displays a plain TextEdit widget which contains source code. Portions of the text are highlighted in various colors using the GUI syntax highlighting class.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=\/wp\/v2\/posts\/1893"}],"collection":[{"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1893"}],"version-history":[{"count":68,"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=\/wp\/v2\/posts\/1893\/revisions"}],"predecessor-version":[{"id":2117,"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=\/wp\/v2\/posts\/1893\/revisions\/2117"}],"wp:attachment":[{"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/journal.copperspice.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}