Qt項目之高亮關鍵字Python編輯器實現

  • 2019 年 10 月 5 日
  • 筆記

之前大部分內容在寫Qt一些小部件以及基礎模組的用法,不成體系,大部分時候還是用什麼找什麼。隨著對Qt的逐漸熟悉,應該做一些項目,這樣可以在實際應用的過程中加深對程式的理解。本次要和大家分享的就是高亮語法Python編輯器。

使用Qt編寫編輯器項目,可以有兩種方式。一種是使用Qt自身的類如Widget、QPlainTextEdit、QSyntaxHighlighter等我們自己根據Qt提供的Api去實現編輯器;另一種可以是使用第三方庫QScintilla(是Scintilla 在Qt上的移植)去實現編輯器的各種功能。對於我們自己實現小型的編輯器來講差別不大。我從另外的角度說下,自己實現了編輯器,可能還會需要添加虛擬鍵盤的功能。Qt可以通過插件的方式開發虛擬鍵盤功能,這時候使用QScintilla開發的編輯器在使用虛擬鍵盤上會受到一些限制。

在網上搜索資料,最後覺得Qt的兩篇官方教程比較好,附上鏈接:

Code Editor Example :

https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html

Syntax Highlighter Example :

https://doc.qt.io/qt-5/qtwidgets-richtext-syntaxhighlighter-example.html

本篇文章參考網上資料以及Qt官方文檔,又加入了對文件增刪改查等功能,已經是一個較為完整的小項目了。先上一張效果圖:

程式環境:ubuntu、Qt 5.5.1

LineNumberArea 類,繼承QWidget,實現行號區域的繪製。

CodeEditor 類,繼承QPlainTextEdit,更新行號,載入文本,文件操作等。

CodeHighLight 類繼承QSyntaxHighlighter,實現關鍵字、特殊語法等的高亮。

Widget類, UI層操作。

1. 繼承 QPlainTextEdit 添加一些功能

行號區域是一個單獨的小部件,我們再這個部件上「畫」出行號,當文本行數變化時,行號區域的寬度也要發生變化,此時需要重新繪製行號區域。

void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)  {      QPainter painter(lineNumberArea);      painter.fillRect(event->rect(), Qt::lightGray);          QTextBlock block = firstVisibleBlock();      int blockNumber = block.blockNumber();      int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();      int bottom = top + (int) blockBoundingRect(block).height();        while (block.isValid() && top <= event->rect().bottom()) {          if (block.isVisible() && bottom >= event->rect().top()) {              QString number = QString::number(blockNumber + 1);              painter.setPen(Qt::black);              painter.drawText(-2, top, lineNumberArea->width(), fontMetrics().height(),                               Qt::AlignRight, number);          }            block = block.next();          top = bottom;          bottom = top + (int) blockBoundingRect(block).height();          ++blockNumber;      }  }
高亮游標所在行:  void CodeEditor::highlightCurrentLine()  {      QList<QTextEdit::ExtraSelection> extraSelections;        if (!isReadOnly()) {          QTextEdit::ExtraSelection selection;            QColor lineColor = QColor(Qt::yellow).lighter(160);            selection.format.setBackground(lineColor);          selection.format.setProperty(QTextFormat::FullWidthSelection, true);          selection.cursor = textCursor();          selection.cursor.clearSelection();          extraSelections.append(selection);      }        setExtraSelections(extraSelections);  }

2. 高亮關鍵字

繼承QSyntaxHighlighter,突出一些關鍵字和語法顯示。這裡面主要是一些正則表達式的應用。我們可以定義多種QTextCharFormat類型的規則,設置他們的顏色,指定他們的格式,再將他們分配給HighlightingRule對象,並將該對象附加到我們的規則列表中。

    singleLineCommentFormat.setForeground(Qt::red);      rule.pattern = QRegExp("#[^n]*");      rule.format = singleLineCommentFormat;      highlightingRules.append(rule);

3. 文件操作

讀取文件

bool CodeEditor::openFile(QString &file)  {      QFile f(file);        QTextStream stream(&f);      QApplication::setOverrideCursor(Qt::WaitCursor);        this->setPlainText(stream.readAll());      QApplication::restoreOverrideCursor();      setCurrentFile(file);      connect(this, SIGNAL(textChanged()), this, SLOT(setDocumentModified()));      this->showMaximized();      return true;  }

保存文件

bool CodeEditor::saveFile(QString &name)  {      QString filePath = m_filePath;      QString fileName = QString("%1/%2.py").arg(filePath).arg(name);        QFile file(fileName);        QApplication::setOverrideCursor(Qt::WaitCursor);      QTextStream stream(&file);      stream << this->toPlainText();      setCurrentFile(fileName);      QApplication::restoreOverrideCursor();      return true;  }

為了可讀性,刪掉了一些程式碼。

4. 使用 MDI Area 添加文檔窗體

void Widget:: on_pbn_newFile_clicked()  {      ui->sw_loadFile->hide();      ui->sw_editor->show();      ui->mdiArea->show();        m_pythonCodeEditor = createMdiChild();      m_codeHighLight = new CodeHighLight(m_pythonCodeEditor->document());        ui->mdiArea->addSubWindow(m_pythonCodeEditor);      m_pythonCodeEditor->newFile();  }

Tags: