• QT创建代码编辑器(高亮显示)


    0.前言

      接上一篇博客,上一篇博客讲到在QT里面调用Lua,还有Lua里面调用QT里面的函数两部分。由于需要在QT里面写Lua脚本或者通过文件导入Lua脚本。为了方便查看代码,就需要进行简单的高亮。

    1. 效果图

    2. 代码部分

      本次代码分成两部分,一部分是自定义代码高亮,一部分是自定义编辑器区域。

      CodeHighLighter(自定义代码高亮)【以Lua语法为例】

      CodeHighLighter.h

     1 #ifndef CODEHIGHLIGHTER_H
     2 #define CODEHIGHLIGHTER_H
     3 
     4 #include <QSyntaxHighlighter>
     5 #include <QTextCharFormat>
     6 #include <QTextDocument>
     7 
     8 class CodeHighLighter: public QSyntaxHighlighter
     9 {
    10     Q_OBJECT
    11 
    12 public:
    13     CodeHighLighter(QTextDocument *parent = 0);
    14 
    15 protected:
    16     void highlightBlock(const QString &text) override;
    17 
    18 
    19 private:
    20     struct HighlightingRule
    21     {
    22         QRegExp pattern;
    23         QTextCharFormat format;
    24     };
    25     QVector<HighlightingRule> highlightingRules;
    26 
    27     QRegExp commentStartExpression;         //多行注释开始标识符
    28     QRegExp commentEndExpression;           //多行注释结束标识符
    29 
    30     QTextCharFormat keywordFormat;          //关键字
    31     QTextCharFormat classFormat;            //
    32     QTextCharFormat singleLineKey;          //单行关键字
    33     QTextCharFormat singleLineValue;        //单行值
    34     QTextCharFormat singleLineCommentFormat;//单行注释
    35     QTextCharFormat multiLineCommentFormat; //多行注释
    36     QTextCharFormat quotationFormat;        //字符串标识符
    37     QTextCharFormat functionFormat;         //方法标识符
    38 };
    39 
    40 #endif // CODEHIGHLIGHTER_H

      CodeHighLighter.cpp

      1 #include "codehighlighter.h"
      2 #include <QtDebug>
      3 
      4 CodeHighLighter::CodeHighLighter(QTextDocument *parent): QSyntaxHighlighter(parent)
      5 {
      6     HighlightingRule rule;
      7 
      8     //对于下面正则表达式,标记为紫色,类名称
      9     classFormat.setFontWeight(QFont::Bold);
     10     classFormat.setForeground(Qt::darkMagenta);
     11     rule.pattern = QRegExp("\b[A-Za-z]+:\b");
     12     rule.format = classFormat;
     13     highlightingRules.append(rule);
     14     rule.pattern = QRegExp("\b[A-Za-z]+\.\b");
     15     rule.format = classFormat;
     16     highlightingRules.append(rule);
     17 
     18     //字符串,标记深红色
     19     quotationFormat.setForeground(Qt::darkRed);
     20     rule.pattern = QRegExp("".*"");
     21     rule.format = quotationFormat;
     22     highlightingRules.append(rule);
     23     rule.pattern = QRegExp("'.*'");
     24     rule.format = quotationFormat;
     25     highlightingRules.append(rule);
     26 
     27     //函数标记为斜体蓝色
     28     functionFormat.setFontItalic(true);
     29     functionFormat.setForeground(Qt::blue);
     30     rule.pattern = QRegExp("\b[A-Za-z0-9_]+(?=\()");
     31     rule.format = functionFormat;
     32     highlightingRules.append(rule);
     33 
     34     //关键字
     35     QStringList keywords = {
     36         "and", "break", "do", "else", "elseif", "end", "false",
     37         "for", "function", "if", "in", "local", "nil", "not", "or",
     38         "repeat", "return", "then", "true", "unitl", "while", "goto"
     39     };
     40     //对于下面关键字部分,标记为深蓝色
     41     keywordFormat.setForeground(Qt::darkBlue);
     42     keywordFormat.setFontWeight(QFont::Bold);
     43     QStringList keywordPatterns;
     44     for(int i=0; i<keywords.length(); i++)
     45     {
     46         QString pattern = "\b" + keywords[i] + "\b";
     47         rule.pattern = QRegExp(pattern);
     48         rule.format = keywordFormat;
     49         highlightingRules.append(rule);
     50     }
     51 
     52     //对于下面正则表达式,单行注释标记为绿色
     53     singleLineCommentFormat.setForeground(Qt::darkGreen);
     54     singleLineCommentFormat.setFontItalic(true);
     55     //rule.pattern = QRegExp("//[^
    ]*");
     56     rule.pattern = QRegExp("--[^
    ]*");
     57     rule.format = singleLineCommentFormat;
     58     highlightingRules.append(rule);
     59 
     60     //对于多行注释
     61     multiLineCommentFormat.setForeground(Qt::darkGreen);
     62     multiLineCommentFormat.setFontItalic(true);
     63     //commentStartExpression = QRegExp("/\*");
     64     //commentEndExpression = QRegExp("\*/");
     65     //Lua 多行注释 --[[xx]]
     66     commentStartExpression = QRegExp("--\[\[");
     67     commentEndExpression = QRegExp("\]\]");
     68 }
     69 
     70 void CodeHighLighter::highlightBlock(const QString &text)
     71 {
     72     foreach (const HighlightingRule &rule, highlightingRules) {
     73         QRegExp expression(rule.pattern);
     74         int index = expression.indexIn(text);
     75         while (index >= 0) {
     76             int length = expression.matchedLength();
     77             setFormat(index, length, rule.format);
     78             index = expression.indexIn(text, index + length);
     79         }
     80     }
     81 
     82     setCurrentBlockState(0);
     83 
     84     int startIndex = 0;
     85     if (previousBlockState() != 1)
     86         startIndex = commentStartExpression.indexIn(text);
     87 
     88 
     89     while (startIndex >= 0) {
     90         int endIndex = commentEndExpression.indexIn(text, startIndex);
     91         int commentLength;
     92         if (endIndex == -1) {
     93             setCurrentBlockState(1);
     94             commentLength = text.length() - startIndex;
     95         } else {
     96             commentLength = endIndex - startIndex
     97                     + commentEndExpression.matchedLength();
     98         }
     99         setFormat(startIndex, commentLength, multiLineCommentFormat);
    100         startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
    101     }
    102 }

      CodeEditor(自定义编辑器)

      CodeEditor.h

     1 #ifndef CODEEDITOR_H
     2 #define CODEEDITOR_H
     3 
     4 #include "CodeTypeDef.h"
     5 #include <QPlainTextEdit>
     6 #include <QObject>
     7 #include <QPaintEvent>
     8 #include <QResizeEvent>
     9 #include <QSize>
    10 #include <QWidget>
    11 #include <QSyntaxHighlighter>
    12 #include <QPainter>
    13 
    14 typedef enum{
    15     BROWSE,
    16     EDIT,
    17 }EditorMode;
    18 
    19 class CodeEditor : public QPlainTextEdit
    20 {
    21     Q_OBJECT
    22 
    23 public:
    24     CodeEditor(QWidget *parent=0);
    25     void setMode(EditorMode mode);
    26     void lineNumberAreaPaintEvent(QPaintEvent *event);
    27     int lineNumberAreaWidth();
    28 
    29 protected:
    30     void resizeEvent(QResizeEvent *e) override;
    31 
    32 private slots:
    33     void updateLineNumberAreaWidth(int newBlockCount);
    34     void highlightCurrentLine();
    35     void updateLineNumberArea(const QRect &rect, int dy);
    36 
    37 private:
    38     QWidget *lineNumberArea;
    39 };
    40 
    41 class LineNumberArea: public QWidget
    42 {
    43 public:
    44     LineNumberArea(CodeEditor *editor): QWidget(editor){
    45         codeEditor = editor;
    46     }
    47     QSize sizeHint() const override{
    48         return QSize(codeEditor->lineNumberAreaWidth(), 0);
    49     }
    50 protected:
    51     void paintEvent(QPaintEvent *event) override {
    52         codeEditor->lineNumberAreaPaintEvent(event);
    53     }
    54 private:
    55     CodeEditor *codeEditor;
    56 };
    57 
    58 #endif // CODEEDITOR_H

      CodeEditor.cpp 

      1 #include "codeeditor.h"
      2 #include <QDebug>
      3 
      4 CodeEditor::CodeEditor(QWidget *parent): QPlainTextEdit(parent)
      5 {
      6     lineNumberArea = new LineNumberArea(this);
      7 
      8     //事件绑定
      9     connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
     10     connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int)));
     11     connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
     12 
     13     updateLineNumberAreaWidth(0);
     14     setMode(EditorMode::BROWSE);
     15     setTabStopDistance(32);
     16     setFont(QFont(QString::fromUtf8("Source Code Pro"), 12));
     17 }
     18 
     19 int CodeEditor::lineNumberAreaWidth()
     20 {
     21     int digits = 1;
     22     int max = qMax(1, blockCount());
     23     while (max >= 10) {
     24         max /= 10;
     25         ++digits;
     26     }
     27     QFontMetrics metrics(QFont(QString::fromUtf8("Source Code Pro"), 12, QFont::Weight::Bold));
     28     int space = 10 + metrics.horizontalAdvance(QChar('9')) * digits;
     29     return space;
     30 }
     31 
     32 void CodeEditor::updateLineNumberAreaWidth(int)
     33 {
     34     setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
     35 }
     36 
     37 void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
     38 {
     39     if (dy)
     40         lineNumberArea->scroll(0, dy);
     41     else
     42         lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
     43 
     44     if (rect.contains(viewport()->rect()))
     45         updateLineNumberAreaWidth(0);
     46 }
     47 
     48 void CodeEditor::resizeEvent(QResizeEvent *e)
     49 {
     50     QPlainTextEdit::resizeEvent(e);
     51 
     52     QRect cr = contentsRect();
     53     lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
     54 }
     55 
     56 void CodeEditor::highlightCurrentLine()
     57 {
     58     QList<QTextEdit::ExtraSelection> extraSelections;
     59 
     60     if (!isReadOnly()) {
     61         QTextEdit::ExtraSelection selection;
     62         QColor lineColor = QColor("whitesmoke");
     63         selection.format.setBackground(lineColor);
     64         selection.format.setProperty(QTextFormat::FullWidthSelection, true);
     65         selection.cursor = textCursor();
     66         selection.cursor.clearSelection();
     67         extraSelections.append(selection);
     68     }
     69     setExtraSelections(extraSelections);
     70 }
     71 
     72 void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
     73 {
     74     QPainter painter(lineNumberArea);
     75     painter.fillRect(event->rect(), Qt::lightGray);
     76 
     77 
     78     QTextBlock block = firstVisibleBlock();
     79     int blockNumber = block.blockNumber();
     80     int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
     81     int bottom = top + (int) blockBoundingRect(block).height();
     82 
     83     while (block.isValid() && top <= event->rect().bottom()) {
     84         if (block.isVisible() && bottom >= event->rect().top()) {
     85             QString number = QString::number(blockNumber + 1);
     86             painter.setPen(Qt::black);
     87             painter.setFont(QFont(QString::fromUtf8("Source Code Pro"), 12, QFont::Weight::Bold));
     88             painter.drawText(-5, top, lineNumberArea->width(), fontMetrics().height(),
     89                              Qt::AlignRight, number);
     90         }
     91 
     92         block = block.next();
     93         top = bottom;
     94         bottom = top + (int) blockBoundingRect(block).height();
     95         ++blockNumber;
     96     }
     97 }
     98 
     99 void CodeEditor::setMode(EditorMode mode)
    100 {
    101     if(mode == EditorMode::BROWSE) //预览
    102     {
    103         this->setReadOnly(true);
    104         this->setStyleSheet("background: #f0f0f0;");
    105         highlightCurrentLine();
    106     }
    107     else if(mode == EditorMode::EDIT) //编辑
    108     {
    109         this->setReadOnly(false);
    110         this->setStyleSheet("background: #fcfcfc;");
    111         highlightCurrentLine();
    112     }
    113 }

      MainWidow 调用

     1 MainWindow::MainWindow(QWidget *parent)
     2     : QMainWindow(parent)
     3     , ui(new Ui::MainWindow)
     4 {
     5     ui->setupUi(this);
     6 
     7     codeEditor = new CodeEditor();
     8     codeEditor->setMode(EditorMode::EDIT);
     9     codeEditor->setPlainText("int function()
    {
    --[[te
    st]]
    int a = a + b;
    	return 0;
    }");
    10 
    11     ui->gridLayout->addWidget(codeEditor);
    12     CodeHighLighter *highlighter = new CodeHighLighter();
    13     highlighter->setDocument(codeEditor->document());
    14 }
    15 
    16 MainWindow::~MainWindow()
    17 {
    18     delete ui;
    19 }
    20 
    21 void MainWindow::on_btnHighLightData_clicked()
    22 {
    23     qDebug() << codeEditor->toPlainText();
    24 }

    参考资料:

      https://github.com/tianzhihen/SyntaxHighlighterEditor

    本文地址:https://www.cnblogs.com/wunaozai/p/14097927.html
    个人主页:https://www.wunaozai.com/

  • 相关阅读:
    java练习6
    java练习5
    java练习4
    java练习3
    java练习2
    java练习1
    用代码实现判断字符串的开头和结尾
    语句练习题2
    语句练习题1
    值类型和引用类型的区别
  • 原文地址:https://www.cnblogs.com/wunaozai/p/14097927.html
Copyright © 2020-2023  润新知