Qt中文字編輯器實現語法高亮功能(Qscitinlla)

世紀隱龍發表於2020-12-29

Qt中文字編輯器實現語法高亮功能(Qscitinlla)

Scintilla是一個免費、跨平臺、支援語法高亮的編輯控制元件。它完整支援原始碼的編輯和除錯,包括語法高亮、錯誤指示、程式碼完成(code completion)和呼叫提示(call tips)。能包含標記(marker)的頁邊(margin)可用於標記斷點、摺疊和高亮當前行。而QScintilla是Scintilla在QT上的移植。使用該庫可以更為方便的開發Qt程式。

下面以windows開發為例:

Qscitinlla下載地址: https://riverbankcomputing.com/software/qscintilla/download

解壓,在Qt4Qt5目錄,用QtCreator開啟qscintilla.pro,構建專案。

生成qscintilla2_qt5.lib或.a檔案(本例子使用Qt5.7.1  MSVC2013)

1、建立QWidget工程

在.pro檔案新增標頭檔案以及動態連結庫的引用:

INCLUDEPATH += C:/Users/pan/Desktop/QScintilla_gpl-2.10.1/Qt4Qt5
LIBS += -LC:/Users/pan/Desktop/QScintilla_gpl-2.10.1/build-qscintilla-Desktop_Qt_5_7_1_MSVC2013_64bit-Debug/debug/ -lqscintilla2_qt5d

或者不用新增INCLUDEPATH,直接將Qt4Qt5目錄中的Qsci目錄拷貝到工程中。

2、新增用到的標頭檔案

//QsciScintilla作為QWidget的控制元件,需要新增該控制元件的標頭檔案
#include <Qsci/qsciscintilla.h>
//以python語法作為例子,該語法分析器的標頭檔案
#include <Qsci/qscilexerpython.h>
//設定程式碼提示功能,依靠QsciAPIs類實現
#include <Qsci/qsciapis.h>

3、設定具體功能程式碼

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
 
    QsciScintilla *editor=new QsciScintilla(this);
    //設定語法
    QsciLexerPython *textLexer = new QsciLexerPython;//建立一個詞法分析器
    editor->setLexer(textLexer);//給QsciScintilla設定詞法分析器
 
    //行號提示
    editor->setMarginType(0,QsciScintilla::NumberMargin);//設定編號為0的頁邊顯示行號。
    editor->setMarginLineNumbers(0,true);//對該頁邊啟用行號
    editor->setMarginWidth(0,15);//設定頁邊寬度
    //程式碼提示
    QsciAPIs *apis = new QsciAPIs(textLexer);
    apis->add(QString("import"));
    apis->prepare();
 
    editor->setAutoCompletionSource(QsciScintilla::AcsAll);   //設定源,自動補全所有地方出現的
    editor->setAutoCompletionCaseSensitivity(true);   //設定自動補全大小寫敏感
    editor->setAutoCompletionThreshold(1);    //設定每輸入一個字元就會出現自動補全的提示
 
    pLayout = new QVBoxLayout(this);
    pLayout->addWidget(editor);
    pLayout->setContentsMargins(0,0,0,0);
 
 
}

說明:

行號顯示功能:

QsciScintilla左邊可顯示頁邊(Margins)和標記(Markers)。

頁邊是位於文字顯示區左邊的一豎條區域,它可以用於顯示行號、書籤、斷點標記等, Scintilla最多可以有5個頁邊(從左到右的編號為0~4)。

標記用來標記文字位置,如顯示自定義的內容,譬如斷點、錯誤位置等等,對於具有摺疊功能的,可以使用32種標記(0-31),如果編輯器要支援程式碼摺疊功能,需要預留25-31,這7個作為專用摺疊標記。

自動補全功能:

a 定義一個QsciAPIs類,建構函式中將父類指向你前面定義的lexer類。 
b 呼叫其中的類對應的add方法或者load方法想要補全的關鍵字。

對於補全的關鍵字比較少的可以通過add新增,如果補全內容比較多,可以通過load新增。

QsciAPIs*apis = new QsciAPIs(textLexer); 
if(!apis->load(QString("D://api.txt"))) 
    QMessageBox::warning(this,QString("提示"),QString("讀取檔案失敗")); 
else 
    apis->prepare(); 

c 呼叫類對應的prepare方法來準備好關鍵字。 

d 在你前面定義的QsciScintilla類中的相關方法,常見的方法包括:

setAutoCompletionSource、setAutoCompletionCaseSensitivity、setAutoCompletionThreshold

其中,setAutoCompletionSource可設的屬性包括:

列舉型別描述
QsciScintilla::AcsNone沒有自動補全的資源,即禁用自動補全提示功能
QsciScintilla::AcsAll所有可用的資源都要自動補全提示,包括當前文件中出現的名稱和使用QsciAPIs類加入的名稱
QsciScintilla::AcsDocument當前文件中出現的名稱都自動補全提示
QsciScintilla::AcsAPIs使用QsciAPIs類加入的名稱都自動補全提示

 至此,可以完成一個簡單的python指令碼編輯器。

 

4、編碼問題

Scintilla預設編碼是ANSI ,所以輸入中文字元會出現亂碼

可以給它設定為UTF-8,即新增程式碼:(順便設定文字的字型)

//設定顯示字型
editor->setFont(QFont("Courier New"));
//設定編碼方式
editor->SendScintilla(QsciScintilla::SCI_SETCODEPAGE,QsciScintilla::SC_CP_UTF8);//設定編碼為UTF-8

 

 

5、高亮配色補充

然而,使用的過程中,對比一些其他的編輯器,發現存在問題:

該控制元件不支援python中的內建函式、以及一些編輯器通常把self也高亮實現。

可以看到原始碼中支援的高亮型別:

// Returns the foreground colour of the text for a style.
QColor QsciLexerPython::defaultColor(int style) const
{
    switch (style)
    {
    case Default:
        return QColor(0x80,0x80,0x80);
 
    case Comment:
        return QColor(0x00,0x7f,0x00);
 
    case Number:
        return QColor(0x00,0x7f,0x7f);
 
    case DoubleQuotedString:
    case SingleQuotedString:
        return QColor(0x7f,0x00,0x7f);
 
    case Keyword:
        return QColor(0x00,0x00,0x7f);
 
    case TripleSingleQuotedString:
    case TripleDoubleQuotedString:
        return QColor(0x7f,0x00,0x00);
 
    case ClassName:
        return QColor(0x00,0x00,0xff);
 
    case FunctionMethodName:
        return QColor(0x00,0x7f,0x7f);
 
    case Operator:
    case Identifier:
        break;
 
    case CommentBlock:
        return QColor(0x7f,0x7f,0x7f);
 
    case UnclosedString:
        return QColor(0x00,0x00,0x00);
 
    case HighlightedIdentifier:
        return QColor(0x40,0x70,0x90);
 
    case Decorator:
        return QColor(0x80,0x50,0x00);
    }
 
    return QsciLexer::defaultColor(style);
}

其中的關鍵字定義:

// The list of Python keywords that can be used by other friendly lexers.
const char *QsciLexerPython::keywordClass =
    "and as assert break class continue def del elif else except exec "
    "finally for from global if import in is lambda None not or pass "
    "print raise return try while with yield";

 

 

Enumerator

Default 

The default.

Comment 

A comment.

Number 

A number.

DoubleQuotedString 

A double-quoted string.

SingleQuotedString 

A single-quoted string.

Keyword 

A keyword.

TripleSingleQuotedString 

A triple single-quoted string.

TripleDoubleQuotedString 

A triple double-quoted string.

ClassName 

The name of a class.

FunctionMethodName 

The name of a function or method.

Operator 

An operator.

Identifier 

An identifier.

CommentBlock 

A comment block.

UnclosedString 

The end of a line where a string is not closed.

HighlightedIdentifier 

A highlighted identifier. These are defined by keyword set

  1. Reimplement keywords() to define keyword set 2.
Decorator 

A decorator.

可以看到,該外掛中應該是不支援python的內建函式的,這個內建函式和版本有關。

在自己的python中輸入dir(__builtins__),可將其重定向到文字中,記錄好這些需要高亮的語句。

#################################

對於print,由於在python2中,print "xxx"是作為關鍵字存在的,而使用print("xxx")的方式其為一個內建函式。

故,在python中輸入:

import keyword
 
print keywold.kwlist

可以在輸出結果中看到print,而內建函式中也可以看到。

 

#################################

 參考上表中對於HighligetedIdentifier的介紹,可以知道,其對於自定義的值,kewords()函式傳遞的set值為2,重寫keywords()函式,定義類如下:

pythontest.h

class QsciLexerPythonTest : public QsciLexerPython
{
    //Q_OBJECT
public:
    const char *keywords(int set) const;
};

pythontest.cpp

const char * QsciLexerPythonTest::keywords(int set) const
{
 
    if(set == 2)
    {
        return "self str";
    }
 
    return QsciLexerPython::keywords(set);
}

注意,繼承的類中不要有Q_OBJECT巨集,否則會出現:error LNK2001: 無法解析的外部符號

 在Widget類中定義顏色:

textLexer->setColor(QColor(Qt::gray),QsciLexerPython::Comment);    //設定自帶的註釋行為灰色
textLexer->setColor(QColor(Qt::black),QsciLexerPython::FunctionMethodName);
textLexer->setColor(QColor(Qt::black),QsciLexerPython::ClassName);
textLexer->setColor(QColor(Qt::darkBlue),QsciLexerPython::Keyword);
 
textLexer->setColor(QColor(Qt::red),QsciLexerPython::HighlightedIdentifier);

這樣,對於self、str兩個自定義的關鍵字就可以用紅色高亮。

可以看到,使用這個庫開發是比較方便的,對比Qt自帶的QSyntaxHighlighter控制元件要好很多!

 

相關文章