Sur cette page

Exemple de mise en évidence de la syntaxe

L'exemple de l'outil de mise en évidence de la syntaxe montre comment effectuer une mise en évidence simple de la syntaxe.

Éditeur de texte avec mise en évidence de la syntaxe

L'application Syntax Highlighter affiche des fichiers C++ avec une coloration syntaxique personnalisée.

L'exemple se compose de deux classes :

  • La classe Highlighter définit et applique les règles de mise en évidence.
  • Le widget MainWindow est la fenêtre principale de l'application.

Nous allons d'abord examiner la classe Highlighter pour voir comment vous pouvez personnaliser la classe QSyntaxHighlighter en fonction de vos préférences, puis nous examinerons les parties pertinentes de la classe MainWindow pour voir comment vous pouvez utiliser votre classe de surlignage personnalisée dans une application.

Définition de la classe de surlignage

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;
};

Pour fournir votre propre surbrillance syntaxique, vous devez sous-classer QSyntaxHighlighter, réimplémenter la fonction highlightBlock() et définir vos propres règles de surbrillance.

Nous avons choisi de stocker nos règles de coloration dans une structure privée : Une règle se compose d'un motif QRegularExpression et d'une instance QTextCharFormat. Les différentes règles sont ensuite stockées à l'aide d'une structure QList.

La classe QTextCharFormat fournit des informations de formatage pour les caractères dans une QTextDocument spécifiant les propriétés visuelles du texte, ainsi que des informations sur son rôle dans un document hypertexte. Dans cet exemple, nous définirons uniquement le poids et la couleur de la police à l'aide des fonctions QTextCharFormat::setFontWeight() et QTextCharFormat::setForeground().

Mise en œuvre de la classe de surligneur

Lorsque vous sous-classez la classe QSyntaxHighlighter, vous devez passer le paramètre parent au constructeur de la classe de base. Le parent est le document texte sur lequel la coloration syntaxique sera appliquée. Dans cet exemple, nous avons également choisi de définir nos règles de coloration dans le constructeur :

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);
    }

Tout d'abord, nous définissons une règle de mot-clé qui reconnaît les mots-clés C++ les plus courants. Nous donnons à l'adresse keywordFormat une police de caractères bleue foncée et grasse. Pour chaque mot-clé, nous assignons le mot-clé et le format spécifié à un objet HighlightingRule et nous ajoutons cet objet à notre liste de règles.

    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);

Nous créons ensuite un format que nous appliquerons aux noms de classes Qt. Les noms de classe seront rendus avec une couleur magenta foncé et un style gras. Nous spécifions une chaîne de caractères qui est en fait une expression régulière capturant tous les noms de classes Qt. Nous assignons ensuite l'expression régulière et le format spécifié à un objet HighlightingRule et l'ajoutons à notre liste de règles.

Nous définissons également des règles de mise en évidence pour les citations et les fonctions en utilisant la même approche : Les motifs ont la forme d'expressions régulières et sont stockés dans des objets HighlightingRule avec le format associé.

    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("\\*/"));
}

Le langage C++ comporte deux variantes de commentaires : Le commentaire d'une seule ligne (//) et le commentaire de plusieurs lignes (/*...*/ ). Le commentaire d'une seule ligne peut facilement être défini à l'aide d'une règle de mise en évidence similaire aux précédentes. Mais le commentaire multiligne nécessite une attention particulière en raison de la conception de la classe QSyntaxHighlighter.

Après la création d'un objet QSyntaxHighlighter, sa fonction highlightBlock() sera appelée automatiquement chaque fois que le moteur de texte riche en aura besoin, pour mettre en évidence le bloc de texte donné. Le problème apparaît lorsqu'un commentaire s'étend sur plusieurs blocs de texte. Nous examinerons de plus près la manière dont ce problème peut être résolu lorsque nous passerons en revue l'implémentation de la fonction Highlighter::highlightBlock(). À ce stade, nous spécifions uniquement la couleur du commentaire multiligne.

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);
        }
    }

La fonction highlightBlock() est appelée automatiquement chaque fois que le moteur de texte riche en a besoin, c'est-à-dire lorsque des blocs de texte ont été modifiés.

Nous appliquons d'abord les règles de mise en évidence de la syntaxe que nous avons stockées dans la liste highlightingRules. Pour chaque règle (c'est-à-dire pour chaque objet HighlightingRule), nous recherchons le motif dans le bloc de texte donné à l'aide de la fonction QString::indexOf(). Lorsque la première occurrence du motif est trouvée, nous utilisons la fonction QRegularExpressionMatch::capturedLength() pour déterminer la chaîne qui sera formatée. QRegularExpressionMatch::capturedLength() renvoie la longueur de la dernière chaîne correspondante, ou 0 s'il n'y a pas eu de correspondance.

Pour effectuer le formatage proprement dit, la classe QSyntaxHighlighter fournit la fonction setFormat(). Cette fonction opère sur le bloc de texte transmis en tant qu'argument à la fonction highlightBlock(). Le format spécifié est appliqué au texte à partir de la position de départ donnée et pour la longueur donnée. Les propriétés de formatage définies dans le format donné sont fusionnées au moment de l'affichage avec les informations de formatage stockées directement dans le document. Notez que le document lui-même n'est pas modifié par le format défini par cette fonction.

Ce processus est répété jusqu'à ce que la dernière occurrence du motif dans le bloc de texte actuel soit trouvée.

    setCurrentBlockState(0);

Pour traiter les constructions qui peuvent s'étendre sur plusieurs blocs de texte (comme le commentaire multiligne C++), il est nécessaire de connaître l'état final du bloc de texte précédent (par exemple, "dans le commentaire"). Dans votre implémentation de highlightBlock(), vous pouvez demander l'état final du bloc de texte précédent à l'aide de la fonction QSyntaxHighlighter::previousBlockState(). Après avoir analysé le bloc, vous pouvez enregistrer le dernier état à l'aide de la fonction QSyntaxHighlighter::setCurrentBlockState().

La fonction previousBlockState() renvoie une valeur int. Si aucun état n'est défini, la valeur renvoyée est -1. Vous pouvez désigner n'importe quelle autre valeur pour identifier un état donné en utilisant la fonction setCurrentBlockState(). Une fois l'état défini, le site QTextBlock conserve cette valeur jusqu'à ce qu'elle soit définie à nouveau ou jusqu'à ce que le paragraphe de texte correspondant soit supprimé.

Dans cet exemple, nous avons choisi d'utiliser 0 pour représenter l'état "pas dans le commentaire" et 1 pour l'état "dans le commentaire". Lorsque les règles de mise en évidence de la syntaxe sont appliquées, l'état actuel du bloc est initialisé à 0.

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

Si l'état précédent du bloc était "en commentaire" (previousBlockState() == 1), nous commençons la recherche d'une expression de fin au début du bloc de texte. Si previousBlockState() renvoie 0, nous commençons la recherche à l'emplacement de la première occurrence d'une expression de début.

    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);
    }
}

Lorsqu'une expression de fin est trouvée, nous calculons la longueur du commentaire et appliquons le format de commentaire multiligne. Nous recherchons ensuite la prochaine occurrence de l'expression de début et répétons le processus. Si aucune expression de fin ne peut être trouvée dans le bloc de texte actuel, nous fixons l'état du bloc actuel à 1, c'est-à-dire "dans le commentaire".

Ceci complète l'implémentation de la classe Highlighter; elle est maintenant prête à l'emploi.

Définition de la classe MainWindow

L'utilisation d'une sous-classe de QSyntaxHighlighter est simple ; il suffit de fournir à votre application une instance de la classe et de lui transmettre le document sur lequel vous souhaitez appliquer la mise en évidence.

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;
};

Dans cet exemple, nous déclarons un pointeur vers une instance de Highlighter que nous initialiserons plus tard dans la fonction privée setupEditor().

Mise en œuvre de la classe MainWindow

Le constructeur de la fenêtre principale est simple. Nous commençons par mettre en place les menus, puis nous initialisons l'éditeur et en faisons le widget central de l'application. Enfin, nous définissons le titre de la fenêtre principale.

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

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

Nous initialisons et installons l'objet Highlighter dans la fonction de commodité privée setupEditor() :

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());
}

Nous créons d'abord la police que nous voulons utiliser dans l'éditeur, puis nous créons l'éditeur lui-même, qui est une instance de la classe QTextEdit. Avant d'initialiser l'éditeur avec le fichier de définition de la classe MainWindow, nous créons une instance de Highlighter en passant le document de l'éditeur comme argument. Il s'agit du document auquel la mise en évidence sera appliquée. Ensuite, nous avons terminé.

Un objet QSyntaxHighlighter ne peut être installé que sur un seul document à la fois, mais vous pouvez facilement réinstaller le surligneur sur un autre document à l'aide de la fonction QSyntaxHighlighter::setDocument(). La classe QSyntaxHighlighter fournit également la fonction document() qui renvoie le document actuellement défini.

Exemple de projet @ 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.