├── aweSomeEditorhiahia ├── src │ ├── typedef.h │ ├── myhighlighter.h │ ├── codeeditor.h │ ├── myhighlighter.cpp │ └── codeeditor.cpp ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── aweSomeEditorhiahia.pro └── mainwindow.ui ├── .gitignore └── README.md /aweSomeEditorhiahia/src/typedef.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPEDEF_H 2 | #define TYPEDEF_H 3 | 4 | typedef enum{ 5 | BROWSE, 6 | EDIT, 7 | }editorMode; 8 | 9 | 10 | #endif // TYPEDEF_H 11 | 12 | -------------------------------------------------------------------------------- /aweSomeEditorhiahia/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | debug/ 2 | Debug/ 3 | release/ 4 | Makefile 5 | *.Debug 6 | *.Release 7 | *.pro.user.* 8 | *.pro.user 9 | *.docx 10 | *.autosave 11 | *.o 12 | *.eep 13 | *.elf 14 | *.lss 15 | *.map 16 | *.srec 17 | *.mk 18 | moc_* 19 | ui_mainwindow.h 20 | ui_* 21 | qrc_* 22 | -------------------------------------------------------------------------------- /aweSomeEditorhiahia/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent) 6 | { 7 | this->setupUi(this); 8 | configEditor = new CodeEditor(); 9 | configEditor->setMode(EDIT); 10 | gridLayout->addWidget(configEditor); 11 | MyHighLighter *highlighter = new MyHighLighter(configEditor->document()); 12 | } 13 | 14 | MainWindow::~MainWindow() 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /aweSomeEditorhiahia/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "ui_mainwindow.h" 6 | #include "src/codeeditor.h" 7 | #include "src/myhighlighter.h" 8 | #include "src/typedef.h" 9 | class MainWindow : public QMainWindow,Ui::MainWindow 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit MainWindow(QWidget *parent = 0); 15 | ~MainWindow(); 16 | 17 | private: 18 | CodeEditor *configEditor; 19 | }; 20 | 21 | #endif // MAINWINDOW_H 22 | -------------------------------------------------------------------------------- /aweSomeEditorhiahia/aweSomeEditorhiahia.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2015-09-17T10:51:31 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = aweSomeEditorhiahia 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | mainwindow.cpp \ 17 | src/codeeditor.cpp \ 18 | src/myhighlighter.cpp 19 | 20 | HEADERS += mainwindow.h \ 21 | src/codeeditor.h \ 22 | src/myhighlighter.h \ 23 | src/typedef.h 24 | 25 | FORMS += mainwindow.ui 26 | -------------------------------------------------------------------------------- /aweSomeEditorhiahia/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /aweSomeEditorhiahia/src/myhighlighter.h: -------------------------------------------------------------------------------- 1 | #ifndef MYHIGHLIGHTER_H 2 | #define MYHIGHLIGHTER_H 3 | #include 4 | #include 5 | #include 6 | class MyHighLighter : public QSyntaxHighlighter 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | MyHighLighter(QTextDocument *parent = 0); 12 | 13 | protected: 14 | void highlightBlock(const QString &text) Q_DECL_OVERRIDE; 15 | 16 | private: 17 | struct HighlightingRule 18 | { 19 | QRegExp pattern; 20 | QTextCharFormat format; 21 | }; 22 | QVector highlightingRules; 23 | 24 | QRegExp commentStartExpression; 25 | QRegExp commentEndExpression; 26 | 27 | QTextCharFormat keywordFormat; 28 | QTextCharFormat classFormat; 29 | QTextCharFormat singleLineKey; 30 | QTextCharFormat singleLineValue; 31 | QTextCharFormat singleLineCommentFormat; 32 | QTextCharFormat multiLineCommentFormat; 33 | QTextCharFormat quotationFormat; 34 | QTextCharFormat functionFormat; 35 | }; 36 | #endif // MYHIGHLIGHTER_H 37 | -------------------------------------------------------------------------------- /aweSomeEditorhiahia/src/codeeditor.h: -------------------------------------------------------------------------------- 1 | #ifndef CODEEDITOR_H 2 | #define CODEEDITOR_H 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | class LineNumberArea; 13 | 14 | class CodeEditor : public QPlainTextEdit 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | CodeEditor(QWidget *parent = 0); 20 | void setMode(editorMode mode); 21 | void lineNumberAreaPaintEvent(QPaintEvent *event); 22 | int lineNumberAreaWidth(); 23 | 24 | protected: 25 | void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; 26 | 27 | private slots: 28 | void updateLineNumberAreaWidth(int newBlockCount); 29 | void highlightCurrentLine(); 30 | void updateLineNumberArea(const QRect &, int); 31 | 32 | private: 33 | QWidget *lineNumberArea; 34 | }; 35 | 36 | 37 | class LineNumberArea : public QWidget 38 | { 39 | public: 40 | LineNumberArea(CodeEditor *editor) : QWidget(editor) { 41 | codeEditor = editor; 42 | } 43 | 44 | QSize sizeHint() const Q_DECL_OVERRIDE { 45 | return QSize(codeEditor->lineNumberAreaWidth(), 0); 46 | } 47 | 48 | protected: 49 | void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE { 50 | codeEditor->lineNumberAreaPaintEvent(event); 51 | } 52 | 53 | private: 54 | CodeEditor *codeEditor; 55 | }; 56 | 57 | #endif // CODEEDITOR_H 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #制作高亮语法编辑器 2 | > 开发平台:Qt5.4.1 3 | 4 | ------------------- 5 | ###搭建一个编辑器 6 | >QPlainTextEdit 7 | 8 | 通过继承QPlainTextEdit添加更多的功能: 9 | 10 | 1. 添加高亮显示当前编辑行 11 | 2. 添加显示行号 12 | 13 | ####1. 添加高亮显示当前编辑行 14 | 当光标位置发生改变之后,会触发这个信号: 15 | ```c++ 16 | cursorPositionChanged() 17 | ``` 18 | 19 | 在处理这个信号槽时,我们可以这样做 20 | ```c++ 21 | QList extraSelections; 22 | 23 | if (!isReadOnly()) { 24 | QTextEdit::ExtraSelection selection; 25 | 26 | QColor lineColor = QColor(Qt::yellow).lighter(160); 27 | 28 | selection.format.setBackground(lineColor); 29 | selection.format.setProperty(QTextFormat::FullWidthSelection, true); 30 | selection.cursor = textCursor(); 31 | selection.cursor.clearSelection(); 32 | extraSelections.append(selection); 33 | } 34 | 35 | setExtraSelections(extraSelections); 36 | ``` 37 | 主要工作就是通过设置这个结构体来对当前光标选择的行进行操作: 38 | ``` 39 | struct ExtraSelection 40 | { 41 | QTextCursor cursor; 42 | QTextCharFormat format; 43 | }; 44 | ``` 45 | 进行上述操作之后,QPlainTextEdit上就可以高亮显示当前编辑行了. 46 | ####2. 添加显示行号 47 | 行号的显示其实是在QPlainTextEdit左面放置一个QWidget,然后在Qwidget上画出对应的行号. 48 | 49 | *注意:* 50 | 51 | 因为行号的长度是变化的,所以显示行号的Qwidget的宽度也应该是变化的,因此要获取QPlainTextEdit的所有行数目. 52 | 主要方法是: 53 | ``` 54 | void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) 55 | { 56 | QPainter painter(lineNumberArea); 57 | painter.fillRect(event->rect(), Qt::lightGray); 58 | 59 | 60 | QTextBlock block = firstVisibleBlock(); 61 | int blockNumber = block.blockNumber(); 62 | int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); 63 | int bottom = top + (int) blockBoundingRect(block).height(); 64 | 65 | while (block.isValid() && top <= event->rect().bottom()) { 66 | if (block.isVisible() && bottom >= event->rect().top()) { 67 | QString number = QString::number(blockNumber + 1); 68 | painter.setPen(Qt::black); 69 | painter.drawText(-2, top, lineNumberArea->width(), fontMetrics().height(), 70 | Qt::AlignRight, number); 71 | } 72 | 73 | block = block.next(); 74 | top = bottom; 75 | bottom = top + (int) blockBoundingRect(block).height(); 76 | ++blockNumber; 77 | } 78 | } 79 | ``` 80 | 81 | ###添加语法高亮 82 | >QSyntaxHighlighter 83 | 84 | 通过继承QSyntaxHighlighter类并实现 85 | ``` 86 | highlightBlock(const QString &text) 87 | ``` 88 | 即可实现语法高亮,具体的语法需要自己通过这则表达式实现规则. 89 | ![这里写图片描述](http://img.blog.csdn.net/20150917111311626) 90 | [github](http://example.com/ "optional title") 91 | -------------------------------------------------------------------------------- /aweSomeEditorhiahia/src/myhighlighter.cpp: -------------------------------------------------------------------------------- 1 | #include "myhighlighter.h" 2 | 3 | MyHighLighter::MyHighLighter(QTextDocument *parent) 4 | : QSyntaxHighlighter(parent) 5 | { 6 | HighlightingRule rule; 7 | 8 | keywordFormat.setForeground(Qt::darkBlue); 9 | keywordFormat.setFontWeight(QFont::Bold); 10 | QStringList keywordPatterns; 11 | keywordPatterns << "\\bchar\\b" << "\\bclass\\b" << "\\bconst\\b" 12 | << "\\bdouble\\b" << "\\benum\\b" << "\\bexplicit\\b" 13 | << "\\bfriend\\b" << "\\binline\\b" << "\\bint\\b" 14 | << "\\blong\\b" << "\\bnamespace\\b" << "\\boperator\\b" 15 | << "\\bprivate\\b" << "\\bprotected\\b" << "\\bpublic\\b" 16 | << "\\bshort\\b" << "\\bsignals\\b" << "\\bsigned\\b" 17 | << "\\bslots\\b" << "\\bstatic\\b" << "\\bstruct\\b" 18 | << "\\btemplate\\b" << "\\btypedef\\b" << "\\btypename\\b" 19 | << "\\bunion\\b" << "\\bunsigned\\b" << "\\bvirtual\\b" 20 | << "\\bvoid\\b" << "\\bvolatile\\b"; 21 | foreach (const QString &pattern, keywordPatterns) { 22 | rule.pattern = QRegExp(pattern); 23 | rule.format = keywordFormat; 24 | highlightingRules.append(rule); 25 | } 26 | classFormat.setFontWeight(QFont::Bold); 27 | classFormat.setForeground(Qt::darkMagenta); 28 | rule.pattern = QRegExp("\\bQ[A-Za-z]+\\b"); 29 | rule.format = classFormat; 30 | highlightingRules.append(rule); 31 | 32 | singleLineCommentFormat.setForeground(Qt::red); 33 | rule.pattern = QRegExp("//[^\n]*"); 34 | rule.format = singleLineCommentFormat; 35 | highlightingRules.append(rule); 36 | 37 | multiLineCommentFormat.setForeground(Qt::red); 38 | 39 | quotationFormat.setForeground(Qt::darkGreen); 40 | rule.pattern = QRegExp("\".*\""); 41 | rule.format = quotationFormat; 42 | highlightingRules.append(rule); 43 | 44 | functionFormat.setFontItalic(true); 45 | functionFormat.setForeground(Qt::blue); 46 | rule.pattern = QRegExp("\\b[A-Za-z0-9_]+(?=\\()"); 47 | rule.format = functionFormat; 48 | highlightingRules.append(rule); 49 | 50 | commentStartExpression = QRegExp("/\\*"); 51 | commentEndExpression = QRegExp("\\*/"); 52 | } 53 | 54 | void MyHighLighter::highlightBlock(const QString &text) 55 | { 56 | foreach (const HighlightingRule &rule, highlightingRules) { 57 | QRegExp expression(rule.pattern); 58 | int index = expression.indexIn(text); 59 | while (index >= 0) { 60 | int length = expression.matchedLength(); 61 | setFormat(index, length, rule.format); 62 | index = expression.indexIn(text, index + length); 63 | } 64 | } 65 | 66 | setCurrentBlockState(0); 67 | 68 | int startIndex = 0; 69 | if (previousBlockState() != 1) 70 | startIndex = commentStartExpression.indexIn(text); 71 | 72 | 73 | while (startIndex >= 0) { 74 | int endIndex = commentEndExpression.indexIn(text, startIndex); 75 | int commentLength; 76 | if (endIndex == -1) { 77 | setCurrentBlockState(1); 78 | commentLength = text.length() - startIndex; 79 | } else { 80 | commentLength = endIndex - startIndex 81 | + commentEndExpression.matchedLength(); 82 | } 83 | setFormat(startIndex, commentLength, multiLineCommentFormat); 84 | startIndex = commentStartExpression.indexIn(text, startIndex + commentLength); 85 | } 86 | } -------------------------------------------------------------------------------- /aweSomeEditorhiahia/src/codeeditor.cpp: -------------------------------------------------------------------------------- 1 | #include "codeeditor.h" 2 | #include 3 | 4 | CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent) 5 | { 6 | lineNumberArea = new LineNumberArea(this); 7 | 8 | connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); 9 | connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); 10 | connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); 11 | 12 | updateLineNumberAreaWidth(0); 13 | setMode(BROWSE); 14 | } 15 | int CodeEditor::lineNumberAreaWidth() 16 | { 17 | int digits = 1; 18 | int max = qMax(1, blockCount()); 19 | while (max >= 10) { 20 | max /= 10; 21 | ++digits; 22 | } 23 | 24 | int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits; 25 | 26 | return space; 27 | } 28 | 29 | void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */) 30 | { 31 | setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); 32 | } 33 | 34 | void CodeEditor::updateLineNumberArea(const QRect &rect, int dy) 35 | { 36 | if (dy) 37 | lineNumberArea->scroll(0, dy); 38 | else 39 | lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height()); 40 | 41 | if (rect.contains(viewport()->rect())) 42 | updateLineNumberAreaWidth(0); 43 | } 44 | 45 | void CodeEditor::resizeEvent(QResizeEvent *e) 46 | { 47 | QPlainTextEdit::resizeEvent(e); 48 | 49 | QRect cr = contentsRect(); 50 | lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); 51 | } 52 | void CodeEditor::highlightCurrentLine() 53 | { 54 | QList extraSelections; 55 | 56 | if (!isReadOnly()) { 57 | QTextEdit::ExtraSelection selection; 58 | 59 | QColor lineColor = QColor(Qt::yellow).lighter(160); 60 | 61 | selection.format.setBackground(lineColor); 62 | selection.format.setProperty(QTextFormat::FullWidthSelection, true); 63 | //selection.cursor = textCursor(); 64 | //selection.cursor.clearSelection(); 65 | extraSelections.append(selection); 66 | } 67 | 68 | setExtraSelections(extraSelections); 69 | } 70 | 71 | void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) 72 | { 73 | QPainter painter(lineNumberArea); 74 | painter.fillRect(event->rect(), Qt::lightGray); 75 | 76 | 77 | QTextBlock block = firstVisibleBlock(); 78 | int blockNumber = block.blockNumber(); 79 | int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); 80 | int bottom = top + (int) blockBoundingRect(block).height(); 81 | 82 | while (block.isValid() && top <= event->rect().bottom()) { 83 | if (block.isVisible() && bottom >= event->rect().top()) { 84 | QString number = QString::number(blockNumber + 1); 85 | painter.setPen(Qt::black); 86 | painter.drawText(-2, top, lineNumberArea->width(), fontMetrics().height(), 87 | Qt::AlignRight, number); 88 | } 89 | 90 | block = block.next(); 91 | top = bottom; 92 | bottom = top + (int) blockBoundingRect(block).height(); 93 | ++blockNumber; 94 | } 95 | } 96 | void CodeEditor::setMode(editorMode mode) 97 | { 98 | if(mode == BROWSE) 99 | { 100 | this->setReadOnly(true); 101 | this->setStyleSheet("background:#f2f2f3;"); 102 | highlightCurrentLine(); 103 | } 104 | else if(mode == EDIT) 105 | { 106 | this->setReadOnly(false); 107 | this->setStyleSheet("background:#ffffff;"); 108 | highlightCurrentLine(); 109 | } 110 | } --------------------------------------------------------------------------------