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("//[^\n]*"); 56 rule.pattern = QRegExp("--[^\n]*"); 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()\n{\n--[[te\nst]]\nint a = a + b;\n\treturn 0;\n}"); 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/
作者:无脑仔的小明 出处:http://www.cnblogs.com/wunaozai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。 |