En esta página

Ejemplo de resaltado de sintaxis

El ejemplo del Resaltador de sintaxis muestra cómo realizar un resaltado de sintaxis sencillo.

Editor de texto con resaltado de sintaxis

La aplicación Syntax Highlighter muestra archivos C++ con resaltado de sintaxis personalizado.

El ejemplo consta de dos clases:

  • La clase Highlighter define y aplica las reglas de resaltado.
  • El widget MainWindow es la ventana principal de la aplicación.

Primero revisaremos la clase Highlighter para ver cómo puedes personalizar la clase QSyntaxHighlighter para que se ajuste a tus preferencias, después echaremos un vistazo a las partes relevantes de la clase MainWindow para ver cómo puedes usar tu clase de resaltado personalizada en una aplicación.

Definición de la Clase Resaltador

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

Para proporcionar tu propio resaltado de sintaxis, debes subclasificar QSyntaxHighlighter, reimplementar la función highlightBlock(), y definir tus propias reglas de resaltado.

Hemos elegido almacenar nuestras reglas de resaltado utilizando una estructura privada: Una regla consiste en un patrón QRegularExpression y una instancia QTextCharFormat. Las distintas reglas se almacenan utilizando una clase QList.

La clase QTextCharFormat proporciona información de formato para los caracteres en un QTextDocument especificando las propiedades visuales del texto, así como información sobre su papel en un documento de hipertexto. En este ejemplo, sólo definiremos el peso y el color de la fuente utilizando las funciones QTextCharFormat::setFontWeight() y QTextCharFormat::setForeground().

Implementación de la clase Highlighter

Al subclasificar la clase QSyntaxHighlighter debe pasar el parámetro parent al constructor de la clase base. El padre es el documento de texto sobre el que se aplicará el resaltado sintáctico. En este ejemplo, también hemos elegido definir nuestras reglas de resaltado en el constructor:

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

Primero definimos una regla de palabras clave que reconoce las palabras clave más comunes de C++. Damos a keywordFormat un tipo de letra azul oscuro y en negrita. Para cada palabra clave, asignamos la palabra clave y el formato especificado a un objeto HighlightingRule y añadimos el objeto a nuestra lista de reglas.

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

A continuación creamos un formato que aplicaremos a los nombres de las clases Qt. Los nombres de las clases se mostrarán con un color magenta oscuro y en negrita. Especificamos un patrón de cadena que es en realidad una expresión regular que captura todos los nombres de clases Qt. Luego asignamos la expresión regular y el formato especificado a un objeto HighlightingRule y añadimos el objeto a nuestra lista de reglas.

También definimos reglas de resaltado para citas y funciones utilizando el mismo enfoque: Los patrones tienen la forma de expresiones regulares y se almacenan en objetos HighlightingRule con el formato asociado.

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

El lenguaje C++ tiene dos variantes de comentarios: El comentario de una sola línea (//) y el comentario multilínea (/*...*/ ). El comentario de una sola línea puede definirse fácilmente mediante una regla de resaltado similar a las anteriores. Pero el comentario multilínea necesita un cuidado especial debido al diseño de la clase QSyntaxHighlighter.

Una vez creado un objeto QSyntaxHighlighter, su función highlightBlock() será llamada automáticamente siempre que sea necesario por el motor de texto enriquecido, resaltando el bloque de texto dado. El problema aparece cuando un comentario abarca varios bloques de texto. Veremos más detenidamente cómo se puede resolver este problema cuando revisemos la implementación de la función Highlighter::highlightBlock(). En este punto sólo especificamos el color del comentario multilínea.

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 función highlightBlock() se llama automáticamente cuando el motor de texto enriquecido lo necesita, es decir, cuando hay bloques de texto que han cambiado.

Primero aplicamos las reglas de resaltado sintáctico que hemos almacenado en la lista highlightingRules. Para cada regla (es decir, para cada objeto HighlightingRule) buscamos el patrón en el bloque de texto dado utilizando la función QString::indexOf(). Cuando se encuentra la primera aparición del patrón, utilizamos la función QRegularExpressionMatch::capturedLength() para determinar la cadena que se formateará. QRegularExpressionMatch::capturedLength() devuelve la longitud de la última cadena encontrada, o 0 si no hay ninguna coincidencia.

Para realizar el formateo propiamente dicho, la clase QSyntaxHighlighter proporciona la función setFormat(). Esta función opera sobre el bloque de texto que se pasa como argumento a la función highlightBlock(). El formato especificado se aplica al texto a partir de la posición de inicio y con la longitud indicadas. Las propiedades de formato establecidas en el formato dado se fusionan en el momento de la visualización con la información de formato almacenada directamente en el documento. Tenga en cuenta que el propio documento no se ve modificado por el formato establecido mediante esta función.

Este proceso se repite hasta que se encuentra la última aparición del patrón en el bloque de texto actual.

    setCurrentBlockState(0);

Para tratar con construcciones que pueden abarcar varios bloques de texto (como el comentario multilínea de C++), es necesario conocer el estado final del bloque de texto anterior (por ejemplo, "en comentario"). En highlightBlock() puede consultar el estado final del bloque de texto anterior mediante la función QSyntaxHighlighter::previousBlockState(). Tras analizar el bloque, puede guardar el último estado mediante QSyntaxHighlighter::setCurrentBlockState().

La función previousBlockState() devuelve un valor int. Si no se establece ningún estado, el valor devuelto es -1. Puede designar cualquier otro valor para identificar un estado determinado utilizando la función setCurrentBlockState(). Una vez establecido el estado, QTextBlock mantiene ese valor hasta que se vuelve a establecer o hasta que se borra el párrafo de texto correspondiente.

En este ejemplo hemos elegido utilizar 0 para representar el estado "no en comentario", y 1 para el estado "en comentario". Cuando se aplican las reglas de resaltado de sintaxis almacenadas, inicializamos el estado de bloque actual a 0.

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

Si el estado de bloque anterior era "en comentario" (previousBlockState() == 1), iniciamos la búsqueda de una expresión final al principio del bloque de texto. Si previousBlockState() devuelve 0, iniciamos la búsqueda en la ubicación de la primera aparición de una expresión de inicio.

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

Cuando se encuentra una expresión final, calculamos la longitud del comentario y aplicamos el formato de comentario multilínea. A continuación, se busca la siguiente aparición de la expresión inicial y se repite el proceso. Si no se puede encontrar ninguna expresión final en el bloque de texto actual, establecemos el estado actual del bloque en 1, es decir, "en comentario".

Esto completa la implementación de la clase Highlighter; ahora está lista para su uso.

Definición de la clase MainWindow

Utilizar una subclase de QSyntaxHighlighter es sencillo; sólo tiene que proporcionar a su aplicación una instancia de la clase y pasarle el documento sobre el que desea que se aplique el resaltado.

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

En este ejemplo declaramos un puntero a una instancia de Highlighter que más tarde inicializaremos en la función privada setupEditor().

Implementación de la clase MainWindow

El constructor de la ventana principal es sencillo. Primero configuramos los menús, luego inicializamos el editor y lo convertimos en el widget central de la aplicación. Finalmente establecemos el título de la ventana principal.

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

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

Inicializamos e instalamos el objeto Highlighter en la función privada 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());
}

Primero creamos la fuente que queremos usar en el editor, luego creamos el propio editor que es una instancia de la clase QTextEdit. Antes de inicializar el editor con el archivo de definición de la clase MainWindow, creamos una instancia de Highlighter pasando el documento del editor como argumento. Este es el documento al que se aplicará el resaltado. Y ya está.

Un objeto QSyntaxHighlighter sólo puede instalarse en un documento a la vez, pero se puede reinstalar fácilmente el resaltador en otro documento utilizando la función QSyntaxHighlighter::setDocument(). La clase QSyntaxHighlighter también proporciona la función document() que devuelve el documento actualmente instalado.

Proyecto de ejemplo @ 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.