Qt小例子学习87 - 语法高亮

Qt小例子学习87 - 语法高亮

HighlightingRule.h

#ifndef SYNTAXHIGHLIGHTER_H
#define SYNTAXHIGHLIGHTER_H

#include <QRegularExpression>
#include <QSyntaxHighlighter>

class QQuickTextDocument;

class HighlightingRule
{
public:
    HighlightingRule(const QString &patternStr, int n,
                     const QTextCharFormat &matchingFormat);
    QString originalRuleStr;
    QRegularExpression pattern;
    int nth;
    QTextCharFormat format;
};

class PythonSyntaxHighlighter : public QSyntaxHighlighter
{
    Q_OBJECT
public:
    PythonSyntaxHighlighter(QTextDocument *parent);
    const QTextCharFormat getTextCharFormat(const QString &colorName,
                                            const QString &style = QString());
    void initializeRules();
    bool matchMultiline(const QString &text, const QRegularExpression &delimiter,
                        const int inState, const QTextCharFormat &style);

protected:
    void highlightBlock(const QString &text);

private:
    QStringList keywords;
    QStringList operators;
    QStringList braces;
    QHash<QString, QTextCharFormat> basicStyles;
    QList<HighlightingRule> rules;
    QRegularExpression triSingleQuote;
    QRegularExpression triDoubleQuote;
};

class SyntaxHighlighterHelper : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QQuickTextDocument *quickdocument READ quickdocument WRITE
               setQuickdocument NOTIFY quickdocumentChanged)
public:
    SyntaxHighlighterHelper(QObject *parent = nullptr)
        : QObject(parent), m_quickdocument(nullptr) {}
    QQuickTextDocument *quickdocument() const;
    void setQuickdocument(QQuickTextDocument *quickdocument);
signals:
    void quickdocumentChanged();

private:
    QQuickTextDocument *m_quickdocument;
};

#endif // SYNTAXHIGHLIGHTER_H

HighlightingRule.cpp

#include "syntaxhighlighter.h"
#include <QQuickTextDocument>

HighlightingRule::HighlightingRule(const QString &patternStr, int n,
                                   const QTextCharFormat &matchingFormat)
{
    originalRuleStr = patternStr;
    pattern = QRegularExpression(patternStr);
    nth = n;
    format = matchingFormat;
}

PythonSyntaxHighlighter::PythonSyntaxHighlighter(QTextDocument *parent)
    : QSyntaxHighlighter(parent)
{
    keywords = QStringList() << "and"
               << "assert"
               << "break"
               << "class"
               << "continue"
               << "def"
               << "del"
               << "elif"
               << "else"
               << "except"
               << "exec"
               << "finally"
               << "for"
               << "from"
               << "global"
               << "if"
               << "import"
               << "in"
               << "is"
               << "lambda"
               << "not"
               << "or"
               << "pass"
               << "print"
               << "raise"
               << "return"
               << "try"
               << "while"
               << "yield"
               << "None"
               << "True"
               << "False";

    operators = QStringList() << "=" <<
                // Comparison
                "=="
                << "!="
                << "<"
                << "<="
                << ">"
                << ">=" <<
                // Arithmetic
                "\\+"
                << "-"
                << "\\*"
                << "/"
                << "//"
                << "%"
                << "\\*\\*" <<
                // In-place
                "\\+="
                << "-="
                << "\\*="
                << "/="
                << "%=" <<
                // Bitwise
                "\\^"
                << "\\|"
                << "&"
                << "~"
                << ">>"
                << "<<";

    braces = QStringList() << "{"
             << "}"
             << "\\("
             << "\\)"
             << "\\["
             << "]";

    basicStyles.insert("keyword", getTextCharFormat("blue"));
    basicStyles.insert("operator", getTextCharFormat("red"));
    basicStyles.insert("brace", getTextCharFormat("darkGray"));
    basicStyles.insert("defclass", getTextCharFormat("black", "bold"));
    basicStyles.insert("brace", getTextCharFormat("darkGray"));
    basicStyles.insert("string", getTextCharFormat("magenta"));
    basicStyles.insert("string2", getTextCharFormat("darkMagenta"));
    basicStyles.insert("comment", getTextCharFormat("darkGreen", "italic"));
    basicStyles.insert("self", getTextCharFormat("black", "italic"));
    basicStyles.insert("numbers", getTextCharFormat("brown"));

    triSingleQuote.setPattern("'''");
    triDoubleQuote.setPattern("\"\"\"");

    initializeRules();
}

void PythonSyntaxHighlighter::initializeRules()
{
    for (const QString &currKeyword : keywords)
    {
        rules.append(HighlightingRule(QString("\\b%1\\b").arg(currKeyword), 0,
                                      basicStyles.value("keyword")));
    }
    for (const QString &currOperator : operators)
    {
        rules.append(HighlightingRule(QString("%1").arg(currOperator), 0,
                                      basicStyles.value("operator")));
    }
    for (const QString &currBrace : braces)
    {
        rules.append(HighlightingRule(QString("%1").arg(currBrace), 0,
                                      basicStyles.value("brace")));
    }
    // 'self'
    rules.append(HighlightingRule("\\bself\\b", 0, basicStyles.value("self")));

    // Double-quoted string, possibly containing escape sequences
    // FF: originally in python : r'"[^"\\]*(\\.[^"\\]*)*"'
    rules.append(HighlightingRule("\"[^\"\\\\]*(\\\\.[^\"\\\\]*)*\"", 0,
                                  basicStyles.value("string")));
    // Single-quoted string, possibly containing escape sequences
    // FF: originally in python : r"'[^'\\]*(\\.[^'\\]*)*'"
    rules.append(HighlightingRule("'[^'\\\\]*(\\\\.[^'\\\\]*)*'", 0,
                                  basicStyles.value("string")));

    // 'def' followed by an identifier
    // FF: originally: r'\bdef\b\s*(\w+)'
    rules.append(HighlightingRule("\\bdef\\b\\s*(\\w+)", 1,
                                  basicStyles.value("defclass")));
    //  'class' followed by an identifier
    // FF: originally: r'\bclass\b\s*(\w+)'
    rules.append(HighlightingRule("\\bclass\\b\\s*(\\w+)", 1,
                                  basicStyles.value("defclass")));

    // From '#' until a newline
    // FF: originally: r'#[^\\n]*'
    rules.append(HighlightingRule("#[^\\n]*", 0, basicStyles.value("comment")));

    // Numeric literals
    rules.append(HighlightingRule(
                     "\\b[+-]?[0-9]+[lL]?\\b", 0,
                     basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+[lL]?\b'
    rules.append(HighlightingRule(
                     "\\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\\b", 0,
                     basicStyles.value("numbers"))); // r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b'
    rules.append(HighlightingRule(
                     "\\b[+-]?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b", 0,
                     basicStyles.value(
                         "numbers"))); // r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b'
}

void PythonSyntaxHighlighter::highlightBlock(const QString &text)
{
    for (const HighlightingRule &rule : rules)
    {
        QRegularExpressionMatchIterator matchIterator =
            rule.pattern.globalMatch(text);
        while (matchIterator.hasNext())
        {
            QRegularExpressionMatch match = matchIterator.next();
            setFormat(match.capturedStart(), match.capturedLength(), rule.format);
        }
    }
    setCurrentBlockState(0);
    bool isInMultilne =
        matchMultiline(text, triSingleQuote, 1, basicStyles.value("string2"));
    if (!isInMultilne)
        isInMultilne =
            matchMultiline(text, triDoubleQuote, 2, basicStyles.value("string2"));
}

bool PythonSyntaxHighlighter::matchMultiline(
    const QString &text, const QRegularExpression &delimiter, const int inState,
    const QTextCharFormat &style)
{
    QRegularExpressionMatch match;
    int startIndex = 0;
    if (previousBlockState() != 1)
        startIndex = text.indexOf(delimiter);
    while (startIndex >= 0)
    {
        QRegularExpressionMatch match = delimiter.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, style);
        startIndex = text.indexOf(delimiter, startIndex + commentLength);
    }

    return currentBlockState() == inState;
}

const QTextCharFormat
PythonSyntaxHighlighter::getTextCharFormat(const QString &colorName,
        const QString &style)
{
    QTextCharFormat charFormat;
    QColor color(colorName);
    charFormat.setForeground(color);
    if (style.contains("bold", Qt::CaseInsensitive))
        charFormat.setFontWeight(QFont::Bold);
    if (style.contains("italic", Qt::CaseInsensitive))
        charFormat.setFontItalic(true);
    return charFormat;
}

QQuickTextDocument *SyntaxHighlighterHelper::quickdocument() const
{
    return m_quickdocument;
}

void SyntaxHighlighterHelper::setQuickdocument(
    QQuickTextDocument *quickdocument)
{
    m_quickdocument = quickdocument;
    if (m_quickdocument)
    {
        new PythonSyntaxHighlighter(m_quickdocument->textDocument());
    }
}

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.12
import Foo 1.0

Window {
    id: mainWindow
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    SyntaxHighlighterHelper{
        quickdocument: ta.textDocument
    }

    TextArea{
        id:ta
        anchors.fill: parent
        selectByMouse: true
        selectByKeyboard: true
        font.pointSize: 12
        textMargin: 16
        font.family:"courier new"
        persistentSelection: true
        textFormat: Text.StyledText
        tabStopDistance: 4*fontMetrics.advanceWidth(" ")
        FontMetrics {
            id: fontMetrics
            font.family: ta.font
        }
    }
}

main.cpp

#include "syntaxhighlighter.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    qmlRegisterType<SyntaxHighlighterHelper>("Foo", 1, 0,
            "SyntaxHighlighterHelper");
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值