Vor einiger Zeit habe ich etwas über Syntaxhervorhebung in QTextEdit gelernt und die Hervorhebung für HTML-Code geübt. Als Ergebnis ist es mir gelungen, eine ziemlich gute Version der Syntaxhervorhebung von HTML-Code zu erstellen, aber aufgrund der Tatsache, dass die Möglichkeit besteht, dass dieser Code von mir irgendwo nicht verwendet wird, habe ich mich entschlossen, dieses Beispiel für Programmcode zu posten.
Die Hervorhebung der HTML-Syntax in QTextEdit sieht folgendermaßen aus:
Projektstruktur
Das Projekt besteht aus folgenden Dateien:
- HTMLExample.pro - Projektprofil;
- main.cpp - Projektstartdatei;
- mainwindow.h - Header-Datei des Anwendungsfensters;
- mainwindow.cpp - Quellcodedatei des Anwendungsfensters;
- mainwindow.ui - Schnittstellendatei;
- HTMLHighLighter.h - Klassen-Header-Datei zum Hervorheben von HTML-Code;
- HTMLHighLighter.cpp - Klassenquellcodedatei zum Hervorheben von HTML-Code;
main.cpp, HTMLExample.pro - werden standardmäßig erstellt, wir fügen nur QTextEdit zu mainwindow.ui hinzu.
Hauptfenster.h
Hier schließen wir die HTMLHighLighter-Header-Datei ein und deklarieren ihr Objekt.
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "HTMLHighLighter.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; HtmlHighLighter *m_htmlHightLighter; }; #endif // MAINWINDOW_H
Hauptfenster.cpp
Und in dieser Datei setzen wir einfach das HTMLHighLighter -Objekt auf das Dokument des QTextEdit -Objekts.
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); m_htmlHightLighter = new HtmlHighLighter(ui->textEdit->document()); } MainWindow::~MainWindow() { delete ui; }
HTMLHighLighter.h
Ein Merkmal der Hervorhebung der Codesyntax oder nur von Text in QTextEdit besteht darin, dass die Klasse QSyntaxtHighLighter über alle Textblöcke iteriert, in die der Text unterteilt ist (unter Verwendung eines Zeilenumbruchzeichens geteilt) und bestimmt, wie der aktuelle Block hervorgehoben wird von Anfang an abhängig vom Hervorhebungszustand des vorherigen Textblocks.
Das muss natürlich umgesetzt werden. Im Klassenkonstruktor werden die Regeln zum Hervorheben verschiedener Teile des Codes und die Vorlagen, durch die diese Teile des Codes bestimmt werden, initialisiert. Und in der Methode highlightBlock(const QString &text), wird die Textverarbeitungslogik implementiert.
#ifndef HTMLHIGHLIGHTER_H #define HTMLHIGHLIGHTER_H #include <QSyntaxHighlighter> QT_BEGIN_NAMESPACE class QTextDocument; class QTextCharFormat; QT_END_NAMESPACE class HtmlHighLighter : public QSyntaxHighlighter { Q_OBJECT public: explicit HtmlHighLighter(QTextDocument *parent = 0); protected: void highlightBlock(const QString &text) Q_DECL_OVERRIDE; private: // Состояние подсветки, в которой находится текстовый блок на момент его закрытия enum States { None, // Без подсветки Tag, // Подсветка внутри тега Comment, // Внутри комментария Quote // Внутри кавычек, которые внутри тега }; struct HighlightingRule { QRegExp pattern; QTextCharFormat format; }; QVector<HighlightingRule> startTagRules; // Правила форматирования для открывающих тегов QVector<HighlightingRule> endTagRules; // Правила форматирования для закрывающих тегов QRegExp openTag; // Символ открытия тега - "<" QRegExp closeTag; // Символ закрытия тег - ">" QTextCharFormat edgeTagFormat; // Форматирование символов openTag и closeTag QTextCharFormat insideTagFormat; // Форматирование текста внутри тега QRegExp commentStartExpression; // Регулярка начала комментария QRegExp commentEndExpression; // Регулярка закрытия комментария QTextCharFormat multiLineCommentFormat; // Форматирование текста внутри комментария QRegExp quotes; // Регулярное выражение для текста в кавычках внутри тега QTextCharFormat quotationFormat; // Форматирование текста в кавычках внутри тега QTextCharFormat tagsFormat; // Форматирование самих тегов }; #endif // HTMLHIGHLIGHTER_H
HTMLHighLighter.cpp
#include "HTMLHighLighter.h" #include <QTextCharFormat> #include <QBrush> #include <QColor> HtmlHighLighter::HtmlHighLighter(QTextDocument *parent) : QSyntaxHighlighter(parent) { HighlightingRule rule; edgeTagFormat.setForeground(QBrush(QColor("#32a9dd"))); insideTagFormat.setForeground(Qt::blue); insideTagFormat.setFontWeight(QFont::Bold); openTag = QRegExp("<"); closeTag = QRegExp(">"); tagsFormat.setForeground(Qt::darkBlue); tagsFormat.setFontWeight(QFont::Bold); QStringList keywordPatterns; keywordPatterns << "<\\ba\\b" << "<\\babbr\\b" << "<\\bacronym\\b" << "<\\baddress\\b" << "<\\bapplet\\b" << "<\\barea\\b" << "<\\barticle\\b" << "<\\baside\\b" << "<\\baudio\\b" << "<\\bb\\b" << "<\\bbase\\b" << "<\\bbasefont\\b" << "<\\bbdi\\b" << "<\\bbdo\\b" << "<\\bbgsound\\b" << "<\\bblockquote\\b" << "<\\bbig\\b" << "<\\bbody\\b" << "<\\bblink\\b" << "<\\bbr\\b" << "<\\bbutton\\b" << "<\\bcanvas\\b" << "<\\bcaption\\b" << "<\\bcenter\\b" << "<\\bcite\\b" << "<\\bcode\\b" << "<\\bcol\\b" << "<\\bcolgroup\\b" << "<\\bcommand\\b" << "<\\bcomment\\b" << "<\\bdata\\b" << "<\\bdatalist\\b" << "<\\bdd\\b" << "<\\bdel\\b" << "<\\bdetails\\b" << "<\\bdfn\\b" << "<\\bdialog\\b" << "<\\bdir\\b" << "<\\bdiv\\b" << "<\\bdl\\b" << "<\\bdt\\b" << "<\\bem\\b" << "<\\bembed\\b" << "<\\bfieldset\\b" << "<\\bfigcaption\\b" << "<\\bfigure\\b" << "<\\bfont\\b" << "<\\bfooter\\b" << "<\\bform\\b" << "<\\bframe\\b" << "<\\bframeset\\b" << "<\\bh1\\b" << "<\\bh2\\b" << "<\\bh3\\b" << "<\\bh4\\b" << "<\\bh5\\b" << "<\\bh6\\b" << "<\\bhead\\b" << "<\\bheader\\b" << "<\\bhgroup\\b" << "<\\bhr\\b" << "<\\bhtml\\b" << "<\\bi\\b" << "<\\biframe\\b" << "<\\bimg\\b" << "<\\binput\\b" << "<\\bins\\b" << "<\\bisindex\\b" << "<\\bkbd\\b" << "<\\bkeygen\\b" << "<\\blabel\\b" << "<\\blegend\\b" << "<\\bli\\b" << "<\\blink\\b" << "<\\blisting\\b" << "<\\bmain\\b" << "<\\bmap\\b" << "<\\bmarquee\\b" << "<\\bmark\\b" << "<\\bmenu\\b" << "<\\bamenuitem\\b" << "<\\bmeta\\b" << "<\\bmeter\\b" << "<\\bmulticol\\b" << "<\\bnav\\b" << "<\\bnobr\\b" << "<\\bnoembed\\b" << "<\\bnoindex\\b" << "<\\bnoframes\\b" << "<\\bnoscript\\b" << "<\\bobject\\b" << "<\\bol\\b" << "<\\boptgroup\\b" << "<\\boption\\b" << "<\\boutput\\b" << "<\\bp\\b" << "<\\bparam\\b" << "<\\bpicture\\b" << "<\\bplaintext\\b" << "<\\bpre\\b" << "<\\bprogress\\b" << "<\\bq\\b" << "<\\brp\\b" << "<\\brt\\b" << "<\\brtc\\b" << "<\\bruby\\b" << "<\\bs\\b" << "<\\bsamp\\b" << "<\\bscript\\b" << "<\\bsection\\b" << "<\\bselect\\b" << "<\\bsmall\\b" << "<\\bsource\\b" << "<\\bspacer\\b" << "<\\bspan\\b" << "<\\bstrike\\b" << "<\\bstrong\\b" << "<\\bstyle\\b" << "<\\bsub\\b" << "<\\bsummary\\b" << "<\\bsup\\b" << "<\\btable\\b" << "<\\btbody\\b" << "<\\btd\\b" << "<\\btemplate\\b" << "<\\btextarea\\b" << "<\\btfoot\\b" << "<\\bth\\b" << "<\\bthead\\b" << "<\\btime\\b" << "<\\btitle\\b" << "<\\btr\\b" << "<\\btrack\\b" << "<\\btt\\b" << "<\\bu\\b" << "<\\bul\\b" << "<\\bvar\\b" << "<\\bvideo\\b" << "<\\bwbr\\b" << "<\\bxmp\\b"; for (const QString &pattern : keywordPatterns) { rule.pattern = QRegExp(pattern); rule.format = tagsFormat; startTagRules.append(rule); } QStringList keywordPatterns_end; keywordPatterns_end << "<!\\bDOCTYPE\\b" << "</\\ba\\b" << "</\\babbr\\b" << "</\\bacronym\\b" << "</\\baddress\\b" << "</\\bapplet\\b" << "</\\barea\\b" << "</\\barticle\\b" << "</\\baside\\b" << "</\\baudio\\b" << "</\\bb\\b" << "</\\bbase\\b" << "</\\bbasefont\\b" << "</\\bbdi\\b" << "</\\bbdo\\b" << "</\\bbgsound\\b" << "</\\bblockquote\\b" << "</\\bbig\\b" << "</\\bbody\\b" << "</\\bblink\\b" << "</\\bbr\\b" << "</\\bbutton\\b" << "</\\bcanvas\\b" << "</\\bcaption\\b" << "</\\bcenter\\b" << "</\\bcite\\b" << "</\\bcode\\b" << "</\\bcol\\b" << "</\\bcolgroup\\b" << "</\\bcommand\\b" << "</\\bcomment\\b" << "</\\bdata\\b" << "</\\bdatalist\\b" << "</\\bdd\\b" << "</\\bdel\\b" << "</\\bdetails\\b" << "</\\bdfn\\b" << "</\\bdialog\\b" << "</\\bdir\\b" << "</\\bdiv\\b" << "</\\bdl\\b" << "</\\bdt\\b" << "</\\bem\\b" << "</\\bembed\\b" << "</\\bfieldset\\b" << "</\\bfigcaption\\b" << "</\\bfigure\\b" << "</\\bfont\\b" << "</\\bfooter\\b" << "</\\bform\\b" << "</\\bframe\\b" << "</\\bframeset\\b" << "</\\bh1\\b" << "</\\bh2\\b" << "</\\bh3\\b" << "</\\bh4\\b" << "</\\bh5\\b" << "</\\bh6\\b" << "</\\bhead\\b" << "</\\bheader\\b" << "</\\bhgroup\\b" << "</\\bhr\\b" << "</\\bhtml\\b" << "</\\bi\\b" << "</\\biframe\\b" << "</\\bimg\\b" << "</\\binput\\b" << "</\\bins\\b" << "</\\bisindex\\b" << "</\\bkbd\\b" << "</\\bkeygen\\b" << "</\\blabel\\b" << "</\\blegend\\b" << "</\\bli\\b" << "</\\blink\\b" << "</\\blisting\\b" << "</\\bmain\\b" << "</\\bmap\\b" << "</\\bmarquee\\b" << "</\\bmark\\b" << "</\\bmenu\\b" << "</\\bamenuitem\\b" << "</\\bmeta\\b" << "</\\bmeter\\b" << "</\\bmulticol\\b" << "</\\bnav\\b" << "</\\bnobr\\b" << "</\\bnoembed\\b" << "</\\bnoindex\\b" << "</\\bnoframes\\b" << "</\\bnoscript\\b" << "</\\bobject\\b" << "</\\bol\\b" << "</\\boptgroup\\b" << "</\\boption\\b" << "</\\boutput\\b" << "</\\bp\\b" << "</\\bparam\\b" << "</\\bpicture\\b" << "</\\bplaintext\\b" << "</\\bpre\\b" << "</\\bprogress\\b" << "</\\bq\\b" << "</\\brp\\b" << "</\\brt\\b" << "</\\brtc\\b" << "</\\bruby\\b" << "</\\bs\\b" << "</\\bsamp\\b" << "</\\bscript\\b" << "</\\bsection\\b" << "</\\bselect\\b" << "</\\bsmall\\b" << "</\\bsource\\b" << "</\\bspacer\\b" << "</\\bspan\\b" << "</\\bstrike\\b" << "</\\bstrong\\b" << "</\\bstyle\\b" << "</\\bsub\\b" << "</\\bsummary\\b" << "</\\bsup\\b" << "</\\btable\\b" << "</\\btbody\\b" << "</\\btd\\b" << "</\\btemplate\\b" << "</\\btextarea\\b" << "</\\btfoot\\b" << "</\\bth\\b" << "</\\bthead\\b" << "</\\btime\\b" << "</\\btitle\\b" << "</\\btr\\b" << "</\\btrack\\b" << "</\\btt\\b" << "</\\bu\\b" << "</\\bul\\b" << "</\\bvar\\b" << "</\\bvideo\\b" << "</\\bwbr\\b" << "</\\bxmp\\b"; for (const QString &pattern : keywordPatterns_end) { rule.pattern = QRegExp(pattern); rule.format = tagsFormat; endTagRules.append(rule); } multiLineCommentFormat.setForeground(Qt::darkGray); commentStartExpression = QRegExp("<!--"); commentEndExpression = QRegExp("-->"); quotationFormat.setForeground(Qt::darkGreen); quotes = QRegExp("\""); } void HtmlHighLighter::highlightBlock(const QString &text) { setCurrentBlockState(HtmlHighLighter::None); // TAG int startIndex = 0; // Если не находимся внутри тега, if (previousBlockState() != HtmlHighLighter::Tag && previousBlockState() != HtmlHighLighter::Quote) { // То пытаемся найти начало следующего тега startIndex = openTag.indexIn(text); } // Забираем состояние предыдущего текстового блока int subPreviousTag = previousBlockState(); while (startIndex >= 0) { // ищем символ конца тега int endIndex = closeTag.indexIn(text, startIndex); int tagLength; // если конец тега не найден, то устанавливаем состояние блока if (endIndex == -1) { setCurrentBlockState(HtmlHighLighter::Tag); tagLength = text.length() - startIndex; } else { tagLength = endIndex - startIndex + closeTag.matchedLength(); } // Устанавливаем форматирования для тега if (subPreviousTag != HtmlHighLighter::Tag) { // с начала тега и до конца, если предыдущее состояние не равнялось Tag setFormat(startIndex, 1, edgeTagFormat); setFormat(startIndex + 1, tagLength - 1, insideTagFormat); } else { // Если же находимся уже внутри тега с самого начала блока // и до конца тега setFormat(startIndex, tagLength, insideTagFormat); subPreviousTag = HtmlHighLighter::None; } // Форматируем символ конца тега setFormat(endIndex, 1, edgeTagFormat); /// QUOTES /////////////////////////////////////// int startQuoteIndex = 0; // Если не находимся в кавычках с предыдущего блока if (previousBlockState() != HtmlHighLighter::Quote) { // То пытаемся найти начало кавычек startQuoteIndex = quotes.indexIn(text, startIndex); } // Подсвечиваем все кавычки внутри тега while (startQuoteIndex >= 0 && ((startQuoteIndex < endIndex) || (endIndex == -1))) { int endQuoteIndex = quotes.indexIn(text, startQuoteIndex + 1); int quoteLength; if (endQuoteIndex == -1) { // Если закрывающая кавычка не найдена, то устанавливаем состояние Quote для блока setCurrentBlockState(HtmlHighLighter::Quote); quoteLength = text.length() - startQuoteIndex; } else { quoteLength = endQuoteIndex - startQuoteIndex + quotes.matchedLength(); } if ((endIndex > endQuoteIndex) || endIndex == -1) { setFormat(startQuoteIndex, quoteLength, quotationFormat); startQuoteIndex = quotes.indexIn(text, startQuoteIndex + quoteLength); } else { break; } } ////////////////////////////////////////////////// // Снова ищем начало тега startIndex = openTag.indexIn(text, startIndex + tagLength); } // EDGES OF TAGS // Обработка цвета саимх тегов, то есть подсветка слов div, p, strong и т.д. for (const HighlightingRule &rule : startTagRules) { QRegExp expression(rule.pattern); int index = expression.indexIn(text); while (index >= 0) { int length = expression.matchedLength(); setFormat(index + 1, length - 1, rule.format); index = expression.indexIn(text, index + length); } } for (const HighlightingRule &rule : endTagRules) { QRegExp expression(rule.pattern); int index = expression.indexIn(text); while (index >= 0) { int length = expression.matchedLength(); setFormat(index + 1, 1, edgeTagFormat); setFormat(index + 2, length - 2, rule.format); index = expression.indexIn(text, index + length); } } // COMMENT int startCommentIndex = 0; // Если предыдущее состояние тега не является комментарием if (previousBlockState() != HtmlHighLighter::Comment) { // то пытаемся найти начало комментария startCommentIndex = commentStartExpression.indexIn(text); } // Если комментарий найден while (startCommentIndex >= 0) { // Ищем конец комментария int endCommentIndex = commentEndExpression.indexIn(text, startCommentIndex); int commentLength; // Если конец не найден if (endCommentIndex == -1) { // То устанавливаем состояние Comment // Принцип аналогичен, что и для обычных тегов setCurrentBlockState(HtmlHighLighter::Comment); commentLength = text.length() - startCommentIndex; } else { commentLength = endCommentIndex - startCommentIndex + commentEndExpression.matchedLength(); } setFormat(startCommentIndex, commentLength, multiLineCommentFormat); startCommentIndex = commentStartExpression.indexIn(text, startCommentIndex + commentLength); } }
Добрый день. Подскажите, как будет выглядеть метод , если вместо используется ?
Половина слов из предыдущего комментария куда-то исчезло. Суть: вместо QRegExp используется QRegularExport. Как в этом случае будет выглядеть highlightBlock?
Вы хотели сказать QRegularExpression?