Linux下Qt制作代码编辑器
阅读原文时间:2021年04月24日阅读:1

源代码已上传,有需要可以下载:

源代码

0.开发环境

    看了那么多博客,没几个说明自己的开发环境的,所以开头先说明一下这个代码编辑器的开发环境

系统 deepin15.5   

内核

Qt版本 5.8.0

1.编辑器预览

    下面进入正文,先来看一下这个编辑器的基本情况

有基本的语法高亮\自动补全\换行缩进\括号匹配.

菜单栏有基本功能的实现,能选择不同的语言来进行语法高亮.

基本上实现了一个代码编辑器的基本功能.

接下来将从代码编辑器主体的实现和菜单栏的实现开始说.

2.项目的创建

建立一个Qt Widgets Application.

设置默认.

3.QScintilla库介绍

语法高亮\自动补全\换行缩进\括号匹配\行号显示的功能主要由一个重要的外部库实现--Scintilla

官网:https://www.scintilla.org

Qt下这个库叫QScintilla

下载:https://riverbankcomputing.com/software/qscintilla/download 

说明文档:http://pyqt.sourceforge.net/Docs/QScintilla2/index.html

功能的实现主要参照了两人的博客,在此非常感谢(ps:两人的QScintilla都打错了)

Qt文本高亮控件Qscitinlla的用法

Qt中文本编辑器实现语法高亮功能(Qscitinlla)

在此要修正一下两个博客说到的QScintilla的配置问题

在.pro文件添加头文件以及动态链接库的引用:

INCLUDEPATH += Qt4Qt5文件夹的地址

Qt4Qt5文件夹在下载完解压后的文件夹中

然后Qt中右键工程选择添加外部库

选择编译生成的.a文件.

这样pro文件就添加了外部库的内容.

4.实现 语法高亮\自动补全\换行缩进\括号匹配\行号显示

代码实现编辑器主体的QWidget界面

//widget.h//widget.h
class widget : public QWidgetclass widget : publ
{
    Q_OBJECT
public:

    widget(QWidget *parent = 0);
    //~widget();
     QsciScintilla *geteditor(){ //返回QScintilla的对象指针
        return editor;
    }
    void setLexer(const QString &);//设置不同语言的词法分析器

private:
    QsciScintilla *editor=new QsciScintilla(this);
};
#endif // WIDGET_H

源文件实现widget类的构造函数和设置词法分析器函数

构造函数先实现行号提示\界面显示\字体和编码方式编码方式设置为UTF-8,不然中文会乱码设置编码格式还有其他更简短的函数实现,具体查看QScintilla库的说明文件.

 //行号提示
    editor->setMarginType(0,QsciScintilla::NumberMargin);//设置编号为0的页边显示行号。
    editor->setMarginLineNumbers(0,true);//对该页边启用行号
    editor->setMarginWidth(0,15);//设置页边宽度
//界面
    QVBoxLayout *pLayout = new QVBoxLayout(this);
    pLayout->addWidget(editor);
    pLayout->setContentsMargins(0,0,0,0);
//设置显示字体
    editor->setFont(QFont("Courier 10 Pitch"));
//设置编码方式
    editor->SendScintilla(QsciScintilla::SCI_SETCODEPAGE,QsciScintilla::SC_CP_UTF8);//设置编码为UTF-8

下面是widget函数内的setLexer函数的实现

设置词法分析器函数

QsciLexer *textLexer;
textLexer = new QsciLexerCPP;
editor->setLexer(textLexer);//给QsciScintilla设置词法分析器

先设置好词法分析器再设置代码提示等功能

//代码提示
    QsciAPIs *apis = new QsciAPIs(textLexer);

 
    apis->prepare();

 
    editor->setAutoCompletionSource(QsciScintilla::AcsAll);   //设置源,自动补全所有地方出现的
    editor->setAutoCompletionCaseSensitivity(true);   //设置自动补全大小写敏感
    editor->setAutoCompletionThreshold(2);    //设置每输入2个字符就会出现自动补全的提示
 
//设置自动缩进
    editor->setAutoIndent(true);

 
//显示选中行号
    editor->setCaretLineVisible(true);
    editor->setCaretLineBackgroundColor(Qt::lightGray);

 
//Enables or disables, according to enable, this display of indentation guides.
    editor->setIndentationGuides(true);

 
//显示行号背景颜色
    //editor->setMarginsBackgroundColor(Qt::gray);

 
//It is ignored if an indicator is being used. The default is blue.
    editor->setUnmatchedBraceForegroundColor(Qt::blue);

 
//括号匹配
    editor->setBraceMatching(QsciScintilla::SloppyBraceMatch);

至此代码编辑器的功能基本实现

5.MainWindow的基本设置

构造函数要加上widget对象和当前文本的文件名

private:

    widget *WidGet=new widget(this);
    QString currentName;//当前文本的文件名

对应的构造函数实现要加上

    setWindowTitle(tr("Qt代码编辑器"));
    this->resize(QSize(600,500));   //设置初始窗口大小
    setCentralWidget(WidGet);   //设主体为代码编辑器

其他基本为槽函数,下面会讲到

6.文件功能的实现 新建\打开\保存\另存为\关闭

这里就用到了QMainWindow的功能函数.

具体功能的实现参照了下面的博客

[转载]Qt -- MainWindow实现文本新建/打开/保存/另存

没改动的地方就不贴出来了

#1 基本上textEdit.document()对象改为

WidGet->geteditor()

#2 打开函数(非槽函数)实现

void MainWindow::loadFile(const QString &fileName)
{
    QFile file(fileName);
    WidGet->setLexer(fileName);
    if(!file.open(QFile::ReadOnly|QFile::Text))
    {
        QMessageBox::critical(this,
                              "critical",
                              "cannot read file"
                              );
        return;
    }
    else
    {
        QTextStream in(&file);
        WidGet->geteditor()->setText(in.readAll());
        setCurrentFile(fileName);
    }
}

增加了根据文件名设置语法分析器

 WidGet->setLexer(fileName);

*注意 这是widget类中的setLexer函数,修改上面widget类中的setLexer函数实现根据不同文件名的后缀来实现不同语言的词法分析器.

修改textEdit.setPlainText(in.readAll())为

WidGet->geteditor()->setText(in.readAll());

#3 另存为函数

bool MainWindow::slotSaveAs()
{
    QString slcStr;
    QString fileName =QFileDialog::getSaveFileName(this,
                                                   QString::fromLocal8Bit("文件另存为"),
                                                   "",
                                                   tr("Config Files(*);;text(*.txt);;C(*.cpp);;python(*.py);;Java(*.java);;HTML(*html)"),
                                                   &slcStr
                                                   );
    if(slcStr.startsWith("text")&&!fileName.endsWith(".txt")){
                fileName+=".txt";
        }
    if(slcStr.startsWith("C")&&!fileName.endsWith(".cpp")){
                fileName+=".cpp";
        }
    if(slcStr.startsWith("python")&&!fileName.endsWith(".py")){
                fileName+=".py";
        }
    if(slcStr.startsWith("Java")&&!fileName.endsWith(".java")){
                fileName+=".py";
        }
    if(slcStr.startsWith("HTML")&&!fileName.endsWith(".html")){
                fileName+=".py";
        }
    if(fileName.isNull())
        return false;
    else if(saveFile(fileName))
        loadFile(fileName);
    else return false;
}

第七行函数可以实现在保存的时候选择不同的文件类型

选择的类型字符串保存在第八行的slcStr中对

之后的代码根据slcStr而在保存的文件中添加后缀来更改文件类型

7.菜单栏增加对不同语言的选择以实现对不同语言的语法高亮

做法和在菜单栏增添打开\保存等功能的做法大同小异

语言选择的槽函数(以c为例)

void wgsetLexercpp(){
        WidGet->setLexer(".cpp");
    }

这样就可以实现语言的选择

8.总结

主要需要熟悉QScintilla库的使用

难度不大但不能只依赖库函数

要结合自己本身c语言的知识