Auf dieser Seite

Beispiel für den Syntax-Highlighter

Das Beispiel „Syntax-Highlighter“ zeigt, wie man eine einfache Syntaxhervorhebung durchführt.

Texteditor mit Syntaxhervorhebung

Die Anwendung „Syntax-Highlighter“ zeigt C++-Dateien mit benutzerdefinierter Syntaxhervorhebung an.

Das Beispiel besteht aus zwei Klassen:

  • Die Klasse „ Highlighter “ definiert und wendet die Hervorhebungsregeln an.
  • Das Widget „ MainWindow “ ist das Hauptfenster der Anwendung.

Zunächst werden wir die Klasse „ Highlighter “ näher betrachten, um zu sehen, wie Sie die Klasse „ QSyntaxHighlighter “ an Ihre Bedürfnisse anpassen können. Anschließend werfen wir einen Blick auf die relevanten Teile der Klasse „ MainWindow “, um zu sehen, wie Sie Ihre benutzerdefinierte Hervorhebungsklasse in einer Anwendung verwenden können.

Definition der Highlighter-Klasse

class Highlighter : public QSyntaxHighlighter
{
    Q_OBJECT

public:
    Highlighter(QTextDocument *parent = nullptr);

protected:
    void highlightBlock(const QString &text) override;

private:
    struct HighlightingRule
    {
        QRegularExpression pattern;
        QTextCharFormat format;
    };
    QList<HighlightingRule> highlightingRules;

    QRegularExpression commentStartExpression;
    QRegularExpression commentEndExpression;

    QTextCharFormat keywordFormat;
    QTextCharFormat classFormat;
    QTextCharFormat singleLineCommentFormat;
    QTextCharFormat multiLineCommentFormat;
    QTextCharFormat quotationFormat;
    QTextCharFormat functionFormat;
};

Um eine eigene Syntaxhervorhebung bereitzustellen, müssen Sie eine Unterklasse von ` QSyntaxHighlighter` erstellen, die Funktion ` highlightBlock()` neu implementieren und Ihre eigenen Hervorhebungsregeln definieren.

Wir haben uns dafür entschieden, unsere Hervorhebungsregeln mithilfe einer privaten Struktur zu speichern: Eine Regel besteht aus einem „ QRegularExpression “-Muster und einer „ QTextCharFormat “-Instanz. Die verschiedenen Regeln werden dann mithilfe einer „ QList “ gespeichert.

Die Klasse „ QTextCharFormat “ stellt Formatierungsinformationen für Zeichen in einer „ QTextDocument “-Instanz bereit, die die visuellen Eigenschaften des Textes sowie Informationen über dessen Rolle in einem Hypertext-Dokument festlegen. In diesem Beispiel definieren wir lediglich die Schriftstärke und die Farbe mithilfe der Funktionen „ QTextCharFormat::setFontWeight()“ und „ QTextCharFormat::setForeground()“.

Implementierung der Klasse „Highlighter“

Bei der Unterklassifizierung der Klasse „ QSyntaxHighlighter “ müssen Sie den Parameter „parent“ an den Konstruktor der Basisklasse übergeben. „parent“ ist das Textdokument, auf das die Syntaxhervorhebung angewendet wird. In diesem Beispiel haben wir uns außerdem dafür entschieden, unsere Hervorhebungsregeln im Konstruktor zu definieren:

Highlighter::Highlighter(QTextDocument *parent)
    : QSyntaxHighlighter(parent)
{
    HighlightingRule rule;

    keywordFormat.setForeground(Qt::darkBlue);
    keywordFormat.setFontWeight(QFont::Bold);
    const QString keywordPatterns[] = {
        QStringLiteral("\\bchar\\b"), QStringLiteral("\\bclass\\b"), QStringLiteral("\\bconst\\b"),
        QStringLiteral("\\bdouble\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bexplicit\\b"),
        QStringLiteral("\\bfriend\\b"), QStringLiteral("\\binline\\b"), QStringLiteral("\\bint\\b"),
        QStringLiteral("\\blong\\b"), QStringLiteral("\\bnamespace\\b"), QStringLiteral("\\boperator\\b"),
        QStringLiteral("\\bprivate\\b"), QStringLiteral("\\bprotected\\b"), QStringLiteral("\\bpublic\\b"),
        QStringLiteral("\\bshort\\b"), QStringLiteral("\\bsignals\\b"), QStringLiteral("\\bsigned\\b"),
        QStringLiteral("\\bslots\\b"), QStringLiteral("\\bstatic\\b"), QStringLiteral("\\bstruct\\b"),
        QStringLiteral("\\btemplate\\b"), QStringLiteral("\\btypedef\\b"), QStringLiteral("\\btypename\\b"),
        QStringLiteral("\\bunion\\b"), QStringLiteral("\\bunsigned\\b"), QStringLiteral("\\bvirtual\\b"),
        QStringLiteral("\\bvoid\\b"), QStringLiteral("\\bvolatile\\b"), QStringLiteral("\\bbool\\b")
    };
    for (const QString &pattern : keywordPatterns) {
        rule.pattern = QRegularExpression(pattern);
        rule.format = keywordFormat;
        highlightingRules.append(rule);
    }

Zunächst definieren wir eine Schlüsselwortregel, die die gängigsten C++-Schlüsselwörter erkennt. Wir weisen den „ keywordFormat “ eine fette, dunkelblaue Schriftart zu. Für jedes Schlüsselwort ordnen wir das Schlüsselwort und das angegebene Format einem „HighlightingRule“-Objekt zu und fügen das Objekt unserer Liste von Regeln hinzu.

    classFormat.setFontWeight(QFont::Bold);
    classFormat.setForeground(Qt::darkMagenta);
    rule.pattern = QRegularExpression(QStringLiteral("\\bQ[A-Za-z]+\\b"));
    rule.format = classFormat;
    highlightingRules.append(rule);

    quotationFormat.setForeground(Qt::darkGreen);
    rule.pattern = QRegularExpression(QStringLiteral("\".*\""));
    rule.format = quotationFormat;
    highlightingRules.append(rule);

    functionFormat.setFontItalic(true);
    functionFormat.setForeground(Qt::blue);
    rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_]+(?=\\()"));
    rule.format = functionFormat;
    highlightingRules.append(rule);

Anschließend erstellen wir ein Format, das wir auf Qt-Klassennamen anwenden werden. Die Klassennamen werden in einer dunklen Magenta-Farbe und in fetter Schrift dargestellt. Wir geben ein Zeichenfolgenmuster an, bei dem es sich tatsächlich um einen regulären Ausdruck handelt, der alle Qt-Klassennamen erfasst. Anschließend weisen wir dem regulären Ausdruck und dem festgelegten Format ein „HighlightingRule“-Objekt zu und fügen das Objekt unserer Regelliste hinzu.

Mit demselben Ansatz definieren wir auch Hervorhebungsregeln für Anführungszeichen und Funktionen: Die Muster haben die Form regulärer Ausdrücke und werden zusammen mit dem zugehörigen Format in „HighlightingRule“-Objekten gespeichert.

    singleLineCommentFormat.setForeground(Qt::red);
    rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*"));
    rule.format = singleLineCommentFormat;
    highlightingRules.append(rule);

    multiLineCommentFormat.setForeground(Qt::red);

    commentStartExpression = QRegularExpression(QStringLiteral("/\\*"));
    commentEndExpression = QRegularExpression(QStringLiteral("\\*/"));
}

Die Sprache C++ kennt zwei Arten von Kommentaren: den einzeiligen Kommentar (//) und den mehrzeiligen Kommentar (/*...*/ ). Der einzeilige Kommentar lässt sich ganz einfach über eine Hervorhebungsregel ähnlich den vorherigen definieren. Der mehrzeilige Kommentar erfordert jedoch aufgrund des Aufbaus der Klasse „ QSyntaxHighlighter “ besondere Sorgfalt.

Nachdem ein ` QSyntaxHighlighter `-Objekt erstellt wurde, wird dessen Funktion ` highlightBlock()` automatisch aufgerufen, wann immer dies von der Rich-Text-Engine benötigt wird, wodurch der angegebene Textblock hervorgehoben wird. Das Problem tritt auf, wenn sich ein Kommentar über mehrere Textblöcke erstreckt. Wir werden uns bei der Betrachtung der Implementierung der Funktion „ Highlighter::highlightBlock() “ genauer ansehen, wie dieses Problem gelöst werden kann. An dieser Stelle legen wir lediglich die Farbe des mehrzeiligen Kommentars fest.

void Highlighter::highlightBlock(const QString &text)
{
    for (const HighlightingRule &rule : std::as_const(highlightingRules)) {
        QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
        while (matchIterator.hasNext()) {
            QRegularExpressionMatch match = matchIterator.next();
            setFormat(match.capturedStart(), match.capturedLength(), rule.format);
        }
    }

Die Funktion `highlightBlock()` wird automatisch aufgerufen, wann immer dies von der Rich-Text-Engine erforderlich ist, d. h. wenn sich Textblöcke geändert haben.

Zunächst wenden wir die Regeln zur Syntaxhervorhebung an, die wir in der Liste „ highlightingRules “ gespeichert haben. Für jede Regel (d. h. für jedes „HighlightingRule“-Objekt) suchen wir mithilfe der Funktion „ QString::indexOf()“ im angegebenen Textblock nach dem Muster. Wird das Muster zum ersten Mal gefunden, verwenden wir die Funktion ` QRegularExpressionMatch::capturedLength()` (text, length), um die zu formatierende Zeichenkette zu ermitteln. ` QRegularExpressionMatch::capturedLength()` gibt die Länge der zuletzt gefundenen Zeichenkette zurück oder 0, falls keine Übereinstimmung vorliegt.

Zur Durchführung der eigentlichen Formatierung stellt die Klasse „ QSyntaxHighlighter “ die Funktion „ setFormat()“ bereit. Diese Funktion wirkt auf den Textblock, der als Argument an die Funktion „ highlightBlock() “ übergeben wird. Das angegebene Format wird ab der angegebenen Startposition für die angegebene Länge auf den Text angewendet. Die im angegebenen Format festgelegten Formatierungseigenschaften werden zum Zeitpunkt der Anzeige mit den direkt im Dokument gespeicherten Formatierungsinformationen zusammengeführt. Beachten Sie, dass das Dokument selbst durch das über diese Funktion festgelegte Format unverändert bleibt.

Dieser Vorgang wird wiederholt, bis das letzte Vorkommen des Musters im aktuellen Textblock gefunden wird.

    setCurrentBlockState(0);

Um Konstrukte zu verarbeiten, die sich über mehrere Textblöcke erstrecken können (wie z. B. der mehrzeilige Kommentar in C++), ist es notwendig, den Endzustand des vorherigen Textblocks zu kennen (z. B. „im Kommentar“). Innerhalb Ihrer ` highlightBlock() `-Implementierung können Sie den Endzustand des vorherigen Textblocks mithilfe der Funktion ` QSyntaxHighlighter::previousBlockState()` abfragen. Nach dem Parsen des Blocks können Sie den letzten Zustand mit ` QSyntaxHighlighter::setCurrentBlockState()` speichern.

Die Funktion ` previousBlockState()` gibt einen `int`-Wert zurück. Ist kein Status festgelegt, lautet der Rückgabewert -1. Mit der Funktion ` setCurrentBlockState()` können Sie jeden beliebigen Wert festlegen, um einen bestimmten Status zu kennzeichnen. Sobald der Status festgelegt ist, behält ` QTextBlock ` diesen Wert bei, bis er erneut festgelegt wird oder bis der entsprechende Textabsatz gelöscht wird.

In diesem Beispiel haben wir uns dafür entschieden, 0 für den Zustand „nicht im Kommentar“ und 1 für den Zustand „im Kommentar“ zu verwenden. Wenn die gespeicherten Regeln zur Syntaxhervorhebung angewendet werden, setzen wir den aktuellen Blockzustand auf 0.

    int startIndex = 0;
    if (previousBlockState() != 1)
        startIndex = text.indexOf(commentStartExpression);

War der vorherige Blockzustand „im Kommentar“ (previousBlockState() == 1), beginnen wir die Suche nach einem Endausdruck am Anfang des Textblocks. Gibt `previousBlockState()` den Wert 0 zurück, beginnen wir die Suche an der Stelle des ersten Vorkommens eines Startausdrucks.

    while (startIndex >= 0) {
        QRegularExpressionMatch match = commentEndExpression.match(text, startIndex);
        int endIndex = match.capturedStart();
        int commentLength = 0;
        if (endIndex == -1) {
            setCurrentBlockState(1);
            commentLength = text.length() - startIndex;
        } else {
            commentLength = endIndex - startIndex
                            + match.capturedLength();
        }
        setFormat(startIndex, commentLength, multiLineCommentFormat);
        startIndex = text.indexOf(commentStartExpression, startIndex + commentLength);
    }
}

Wird ein Endausdruck gefunden, berechnen wir die Länge des Kommentars und wenden das Format für mehrzeilige Kommentare an. Anschließend suchen wir nach dem nächsten Vorkommen des Startausdrucks und wiederholen den Vorgang. Kann im aktuellen Textblock kein Endausdruck gefunden werden, setzen wir den aktuellen Blockzustand auf 1, d. h. „in comment“.

Damit ist die Implementierung der Klasse „ Highlighter “ abgeschlossen; sie ist nun einsatzbereit.

Definition der Klasse „MainWindow“

Die Verwendung einer Unterklasse von ` QSyntaxHighlighter ` ist einfach: Stellen Sie Ihrer Anwendung lediglich eine Instanz der Klasse zur Verfügung und übergeben Sie ihr das Dokument, auf das die Hervorhebung angewendet werden soll.

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);

public slots:
    void about();
    void newFile();
    void openFile(const QString &path = QString());

private:
    void setupEditor();
    void setupFileMenu();
    void setupHelpMenu();

    QTextEdit *editor;
    Highlighter *highlighter;
};

In diesem Beispiel deklarieren wir einen Zeiger auf eine „ Highlighter “-Instanz, die wir später in der privaten Funktion „ setupEditor() “ initialisieren werden.

Implementierung der Klasse „MainWindow“

Der Konstruktor des Hauptfensters ist unkompliziert. Zunächst richten wir die Menüs ein, dann initialisieren wir den Editor und machen ihn zum zentralen Widget der Anwendung. Schließlich legen wir den Titel des Hauptfensters fest.

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setupFileMenu();
    setupHelpMenu();
    setupEditor();

    setCentralWidget(editor);
    setWindowTitle(tr("Syntax Highlighter"));
}

Wir initialisieren und fügen das ` Highlighter `-Objekt in der privaten Hilfsfunktion `setupEditor()` ein:

void MainWindow::setupEditor()
{
    QFont font;
    font.setFamily("Courier");
    font.setFixedPitch(true);
    font.setPointSize(10);

    editor = new QTextEdit;
    editor->setFont(font);

    highlighter = new Highlighter(editor->document());

    QFile file("mainwindow.h");
    if (file.open(QFile::ReadOnly | QFile::Text))
        editor->setPlainText(file.readAll());
}

Zunächst erstellen wir die Schriftart, die wir im Editor verwenden möchten, dann erstellen wir den Editor selbst, der eine Instanz der Klasse ` QTextEdit ` ist. Bevor wir den Editor mit der Klassendefinitionsdatei ` MainWindow ` initialisieren, erstellen wir eine Instanz von ` Highlighter ` und übergeben das Dokument des Editors als Argument. Dies ist das Dokument, auf das die Hervorhebung angewendet wird. Dann sind wir fertig.

Ein ` QSyntaxHighlighter `-Objekt kann jeweils nur auf ein Dokument angewendet werden, aber du kannst den Highlighter mithilfe der Funktion ` QSyntaxHighlighter::setDocument()` ganz einfach auf ein anderes Dokument anwenden. Die Klasse ` QSyntaxHighlighter ` stellt außerdem die Funktion ` document()` zur Verfügung, die das aktuell festgelegte Dokument zurückgibt.

Beispielprojekt @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.