文本编辑控件QScintilla动态库二次开发
使用的开源QScintilla_src-2.14.1版本32位。资源自己网上下。
二次开发了关键字,补全,折叠,光标,任意位置换行等功能。效果图如下:

代码如下:
CustomLexer.h
#include "../Depends/QScintilla_src-2.14.1/src/Qsci/qscilexercustom.h"
#include "../Depends/QScintilla_src-2.14.1/src/Qsci/qsciscintilla.h"
#include "../Depends/QScintilla_src-2.14.1/src/Qsci/qscilexer.h"
class CustomLexer : public QsciLexerCustom
{
public:
explicit CustomLexer(QObject* parent = nullptr);
// 必须重写的核心方法
const char* language() const override;
QString description(int style) const override;
void styleText(int start, int end) override;
void fold(int& foldLevel, int style); // 关键折叠逻辑
// 可选重写方法(样式控制)
QColor defaultColor(int style) const override;
QFont defaultFont(int style) const override;
// 关键字管理
void setKeywords(const QStringList& kwds);
const QStringList& keywords() const { return m_keywords; }
QString splitLineInfo(QString str);
private:
QStringList m_keywords;
int m_keywordStyle;
int m_foldStartStyle;
int m_foldEndStyle;
int m_Level;
};
CustomLexer.cpp
#include "CustomLexer.h"
#include
CustomLexer::CustomLexer(QObject* parent)
: QsciLexerCustom(parent)
{
// 定义关键字列表(含折叠标记关键字)
m_keywords = QStringList({ "func", "var", "return", "endfunc" });
m_keywordStyle = 1; // 关键字基础样式
m_foldStartStyle = 2; // 折叠起始样式(如 "begin")
m_foldEndStyle = 3; // 折叠结束样式(如 "end")
m_Level = 1;
}
const char* CustomLexer::language() const {
return "MyCustomLang"; // 自定义语言名称
}
QString CustomLexer::description(int style) const {
switch (style) {
case 0: return "Default";
case 1: return "Keyword";
case 2: return "String";
// 添加更多样式描述...
default: return "";
}
}
QString CustomLexer::splitLineInfo(QString str)
{
QString n_str = "";
if (str.contains("
"))
{
QStringList n_list = str.split("
");
n_str = n_list.at(0);
return n_str;
}
else
return str;
}
void CustomLexer::styleText(int start, int end)
{
if (!editor()) return;
//QsciStyler styler(this);
QString text = editor()->text(start, end);
for (int pos = 0; pos < text.length(); )
{
startStyling(start + pos);
setStyling(1, 0); // 默认样式
pos++;
continue;
}
//QString n_str = splitLineInfo(text);
//qDebug() << "n_str:" << n_str;
qDebug() << "styleText:" << text << ";start;" << start << ";end;" << end;
//int n_currentPos = editor()->SendScintilla(QsciScintilla::SCI_GETCURRENTPOS);
//int n_currentLine = editor()->SendScintilla(QsciScintilla::SCI_LINEFROMPOSITION, n_currentPos);
//qDebug() << "styleText::n_currentLine:" << n_currentLine << ";n_currentPos:" << n_currentPos;
// 遍历文本应用样式
for (int pos = 0; pos < text.length(); ) {
if (text[pos].isSpace()) {
startStyling(start + pos);
setStyling(1, 0); // 默认样式
pos++;
continue;
}
// 检测关键字
bool isKeyword = false;
foreach(const QString & kw, m_keywords) {
////qDebug() <<"pos:" << pos <<";kw.length():"<< kw.length() << ";test:" << text.mid(pos, kw.length());
if (text.mid(pos, kw.length()) == kw) {
////qDebug() << "gjz in........................";
startStyling(start + pos);
//setStyling(kw.length(), 1); // 关键字样式
if (kw == "func")
{
int currentPos = editor()->SendScintilla(QsciScintilla::SCI_GETCURRENTPOS);
int currentLine = editor()->SendScintilla(QsciScintilla::SCI_LINEFROMPOSITION, currentPos);
//int foldLevel = editor()->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, 2);
////qDebug() << "func::currentLine:" << currentLine << ";currentPos:" << currentPos;
////qDebug() << "func::m_Level:" << m_Level;
//qDebug() << "line:" << start + pos;
//editor()->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, currentLine, QsciScintilla::SC_FOLDLEVELHEADERFLAG);
//editor()->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, currentLine, QsciScintilla::SC_FOLDLEVELBASE | QsciScintilla::SC_FOLDLEVELHEADERFLAG | m_Level);
setStyling(kw.length(), m_foldStartStyle); // 标记为折叠起始
//////editor()->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, currentLine, QsciScintilla::SC_FOLDLEVELHEADERFLAG | m_Level);
//////m_Level++;
}
else if (kw == "endfunc")
{
int currentPos = editor()->SendScintilla(QsciScintilla::SCI_GETCURRENTPOS);
int currentLine = editor()->SendScintilla(QsciScintilla::SCI_LINEFROMPOSITION, currentPos);
////qDebug() << "endfunc::currentLine:" << currentLine << ";currentPos:" << currentPos;
////qDebug() << "endfunc::m_Level:" << m_Level;
setStyling(kw.length(), m_foldEndStyle); // 标记为折叠结束
//m_Level--;
//editor()->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, currentLine, m_Level);
}
else
setStyling(kw.length(), m_keywordStyle); // 关键字样式
pos += kw.length();
isKeyword = true;
break;
}
}
if (!isKeyword && pos < text.length()) {
pos++;
}
//if (isKeyword) continue;
//// 检测字符串(示例:双引号包裹)
//if (text[pos] == '"') {
// int endPos = text.indexOf('"', pos + 1);
// if (endPos == -1) endPos = text.length();
// startStyling(start + pos);
// setStyling(endPos - pos + 1, 2); // 字符串样式
// pos = endPos + 1;
// continue;
//}
// 默认处理
//startStyling(start + pos);
//setStyling(1, 0);
//pos++;
}
}
QColor CustomLexer::defaultColor(int style) const {
switch (style) {
case 1: return Qt::blue; // 关键字颜色
case 2: return Qt::darkGreen; // 字符串颜色
default: return Qt::black; // 默认颜色
}
}
QFont CustomLexer::defaultFont(int style) const {
QFont font("Consolas", 10);
if (style == 1) font.setBold(true); // 关键字加粗
return font;
}
void CustomLexer::setKeywords(const QStringList& kwds)
{
m_keywords = kwds;
}
void CustomLexer::fold(int& foldLevel, int style) {
if (style == 1) { // 遇到 '{'
foldLevel |= QsciScintilla::SC_FOLDLEVELHEADERFLAG;
foldLevel++;
}
else if (style == 2) { // 遇到 '}'
foldLevel--;
}
}
SCLWidget.h
#ifndef SCLWIDGET_H
#define SCLWIDGET_H
#include "qsciscintilla.h"
#include "qscilexercpp.h"
#include "qscilexercustom.h"
#include "qsciapis.h"
#include "CustomLexer.h"
#include "BodorPLC_global.h"
#include
#include
#include
#include
class SCLWidget : public QWidget
{
Q_OBJECT
public:
explicit SCLWidget(QWidget* parent = nullptr);
bool eventFilter(QObject* obj, QEvent* ev) override;
private slots:
void handleTextChanged();
private:
void checkUpdateLineInfo(int curLine);
private:
QsciScintilla* editor;
QStringList m_keywords;//关键字
QList foldedLines;//中间换行的下边行List留痕
bool m_isNewLine;//是否是换行回车
CURCURSOR m_curCursor;//换行回车光标留痕
};
#endif // SCLWIDGET_H
SCLWidget.cpp
#include "SCLWidget.h"
#include
#include
#include
SCLWidget::SCLWidget(QWidget* parent)
: QWidget(parent)
{
m_keywords = QStringList({ "func", "var", "return", "endfunc","endvar" });
m_isNewLine = false;
foldedLines = {};
m_curCursor = { 0,0 };
QVBoxLayout* mainLayout = new QVBoxLayout(this);
editor = new QsciScintilla(this);
mainLayout->addWidget(editor);
editor->installEventFilter(this);
connect(editor, SIGNAL(textChanged()),
this, SLOT(handleTextChanged()), Qt::QueuedConnection);
// 配置编辑器基础属性
editor->setMarginLineNumbers(1, true); // 显示行号
editor->setMarginWidth(1, "0000"); // 行号栏宽度
editor->setAutoIndent(true); // 自动缩进
// 应用自定义词法分析器
CustomLexer* lexer = new CustomLexer(editor);
editor->setLexer(lexer);
//关键字补全
QsciAPIs* pyApis = new QsciAPIs(lexer);
pyApis->add("func");
pyApis->add("fuaa");
pyApis->add("var");
pyApis->add("varq");
pyApis->add("return");
pyApis->add("returnq");
pyApis->add("endfunc");
pyApis->add("endvar");
pyApis->prepare();
editor->setAutoCompletionSource(QsciScintilla::AcsAPIs); // 仅使用 API 列表
editor->setAutoCompletionCaseSensitivity(true); // 区分大小写
editor->setAutoCompletionThreshold(1); // 输入1个字符触发补全
editor->setAutoCompletionFillupsEnabled(true); // 允许补全填充
// 启用折叠
editor->setFolding(QsciScintilla::BoxedTreeFoldStyle);
editor->setFoldMarginColors(Qt::lightGray, Qt::white);
// 设置折叠边栏(通常为第2边栏)
editor->setMarginWidth(2, 16); // 宽度建议16-20像素
editor->setMarginType(2, QsciScintilla::SymbolMargin);
editor->setMarginSensitivity(2, true); // 允许点击交互
// 定义折叠展开(+)和折叠(-)的符号
editor->markerDefine(QsciScintilla::RightTriangle, QsciScintilla::SC_MARKNUM_FOLDEROPEN); // 展开状态
editor->markerDefine(QsciScintilla::Minus, QsciScintilla::SC_MARKNUM_FOLDER); // 折叠状态
// 将编辑器设为中心部件
//setCentralWidget(editor);
//resize(800, 600);
}
void SCLWidget::handleTextChanged()
{
qDebug() << "handleTextChanged in.................................................";
//QString n_str = splitLineInfo(text);
//qDebug() << "n_str:" << n_str;
//qDebug() << "styleText:" << text<<";start;"<< start << ";end;" << end;
//获知当前行
int n_currentPos = editor->SendScintilla(QsciScintilla::SCI_GETCURRENTPOS);
int n_currentLine = editor->SendScintilla(QsciScintilla::SCI_LINEFROMPOSITION, n_currentPos);
qDebug() << "styleText::n_currentLine:" << n_currentLine << ";n_currentPos:" << n_currentPos;
// 获取行文本
int start = editor->SendScintilla(QsciScintilla::SCI_POSITIONFROMLINE, n_currentLine);
int end = editor->SendScintilla(QsciScintilla::SCI_GETLINEENDPOSITION, n_currentLine);
QString n_str = editor->text(start, end);
qDebug() << "handleTextChanged::str:" << n_str;
//获取折叠层级
int foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine);
int levelNum = foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
qDebug() << "foldLevel:" << foldLevel;
qDebug() << "levelNum:" << levelNum;
for (int line = 0; line < editor->lines(); ++line) {
int aa_foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, line);
int aa_levelNum = aa_foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
qDebug() << "line:" << line << ";aa_foldLevel:" << aa_foldLevel << ";levelNum:" << aa_levelNum;
}
//新增行重新更新下面行折叠层级
//折叠分级逻辑
if (m_isNewLine)//换行回车
{
m_isNewLine = false;
//新增行更新折叠层级
if (m_curCursor.col == 0)//行首
{
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine - 1, 1024 + levelNum - 1);
}
else if (m_curCursor.col == m_curCursor.len)//行尾
{
int n_foldLevel_1 = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine - 1);
int n_levelNum_1 = n_foldLevel_1 & QsciScintilla::SC_FOLDLEVELNUMBERMASK;
if (n_foldLevel_1 > 8192)
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, 1024 + n_levelNum_1);
else if (n_foldLevel_1 < 1024)
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, 1024 + n_levelNum_1 - 1);
else
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, n_foldLevel_1);
}
else//行中
{
int n_foldLevel_2 = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine - 1);
int n_levelNum_2 = n_foldLevel_2 & QsciScintilla::SC_FOLDLEVELNUMBERMASK;
if (n_foldLevel_2 > 8192 || n_foldLevel_2 < 1024)
{
//两个都要检查
if (n_foldLevel_2 > 8192)
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine - 1, 1024 + n_levelNum_2 - 1);
else
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine - 1, 1024 + n_levelNum_2);
checkUpdateLineInfo(n_currentLine - 1);
int n_foldLevel_3 = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine - 1);
int n_levelNum_3 = n_foldLevel_3 & QsciScintilla::SC_FOLDLEVELNUMBERMASK;
if (n_foldLevel_3 > 8192)
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, 1024 + n_levelNum_3);
else if (n_foldLevel_3 < 1024)
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, 1024 + n_levelNum_3 - 1);
else
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, n_foldLevel_3);
checkUpdateLineInfo(n_currentLine);
}
else
{
//检查第二个就行了
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, n_foldLevel_2);
checkUpdateLineInfo(n_currentLine);
}
}
/*if (foldLevel > 8192)
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine + 1, 1024 + levelNum);
else if (foldLevel < 1024)
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine + 1, 1024 + levelNum - 1);
else
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine + 1, foldLevel);*/
//新增行重新更新下面行折叠层级
for (int i = n_currentLine + 2; i < editor->lines(); i++)
{
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, i, foldedLines[i - 1]);
}
}
else {
for (int pos = 0; pos < n_str.length(); ) {
if (n_str[pos].isSpace())
{
pos++;
continue;
}
foreach(const QString & kw, m_keywords) {
if (n_str.mid(pos, kw.length()) == kw) {
if (kw == "func")
{
int func_foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine);
int func_levelNum = func_foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
qDebug() << "func_foldLevel1:" << func_foldLevel;
qDebug() << "func_levelNum1:" << func_levelNum;
int n_level = func_levelNum;
if (func_foldLevel < 8192)
{
if (func_foldLevel >= 1024)
n_level = func_foldLevel - 1024 + 1;
else
n_level = func_foldLevel;
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, QsciScintilla::SC_FOLDLEVELHEADERFLAG | n_level);
/*editor->insertAt("
", n_currentLine, 4);
editor->insertAt("endfunc", n_currentLine+1,0);
editor->setCursorPosition(n_currentLine+1, 7);
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine+1, n_level);*/
qDebug() << "gggggggg:" << editor->lines();
}
else
{
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, QsciScintilla::SC_FOLDLEVELHEADERFLAG | n_level);
}
qDebug() << "func:n_level:" << n_level;
func_foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine);
func_levelNum = func_foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
qDebug() << "func_foldLevel2:" << func_foldLevel;
qDebug() << "func_levelNum2:" << func_levelNum;
}
else if (kw == "endfunc")
{
int func_foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine);
int func_levelNum = func_foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
qDebug() << "endfunc_foldLevel1:" << func_foldLevel;
qDebug() << "endfunc_levelNum1:" << func_levelNum;
int n_level = levelNum;
if (foldLevel >= 1024)
{
if (foldLevel < 8192)
{
if (foldLevel == 1024)
{
n_level = 0;
//提示结构错误
}
else
n_level = foldLevel - 1024;
}
}
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, n_currentLine, n_level);
int end_foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine);
int end_levelNum = end_foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
qDebug() << "end_foldLevel:" << end_foldLevel;
qDebug() << "end_levelNum:" << end_levelNum;
}
pos += kw.length();
break;
}
}
if (pos < n_str.length()) {
pos++;
}
}
}
}
bool SCLWidget::eventFilter(QObject* obj, QEvent* ev)
{
if (obj == editor && ev->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = static_cast(ev);
if (keyEvent->key() == Qt::Key_Return) {
if (editor->SendScintilla(QsciScintilla::SCI_AUTOCACTIVE))//补全
{
qDebug() << "bu quan de hui che";
int n_currentPos = editor->SendScintilla(QsciScintilla::SCI_GETCURRENTPOS);
int n_currentLine = editor->SendScintilla(QsciScintilla::SCI_LINEFROMPOSITION, n_currentPos);
int func_foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, n_currentLine);
int func_levelNum = func_foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
qDebug() << "huiche_n_currentLine:" << n_currentLine;
qDebug() << "huiche_foldLevel:" << func_foldLevel;
qDebug() << "huiche_levelNum:" << func_levelNum;
}
else//换行
{
qDebug() << "huan hang de hui cheeeeeeeeeeeeeeeeeeeeeeeeeeee";
int n_currentPos = editor->SendScintilla(QsciScintilla::SCI_GETCURRENTPOS);
int n_currentLine = editor->SendScintilla(QsciScintilla::SCI_LINEFROMPOSITION, n_currentPos);
qDebug() << "n_currentLine:" << n_currentLine << "test:" << editor->text(n_currentLine);
QString n_str = editor->text(n_currentLine);
while (n_str.endsWith("
") || n_str.endsWith("
")) {
n_str.chop(1); // 逐个移除末尾的
或
}
m_curCursor.len = n_str.size();
editor->getCursorPosition(&m_curCursor.row, &m_curCursor.col);
qDebug() << "m_curCursor.row:" << m_curCursor.row << ";m_curCursor.col:" << m_curCursor.col << ";m_curCursor.len:" << m_curCursor.len;
foldedLines.clear();
for (int line = 0; line < editor->lines(); ++line) {
int func_foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, line);
int func_levelNum = func_foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
qDebug() << "line:" << line << ";foldLevel:" << func_foldLevel << ";levelNum:" << func_levelNum;
foldedLines.append(func_foldLevel);
}
m_isNewLine = true;
}
}
}
return false;
}
//当前行
void SCLWidget::checkUpdateLineInfo(int curLine)
{
// 获取行文本
int start = editor->SendScintilla(QsciScintilla::SCI_POSITIONFROMLINE, curLine);
int end = editor->SendScintilla(QsciScintilla::SCI_GETLINEENDPOSITION, curLine);
QString n_str = editor->text(start, end);
//获取折叠层级
int foldLevel = editor->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, curLine);
int levelNum = foldLevel & QsciScintilla::SC_FOLDLEVELNUMBERMASK; // 提取层级数值
for (int pos = 0; pos < n_str.length(); ) {
if (n_str[pos].isSpace())
{
pos++;
continue;
}
foreach(const QString & kw, m_keywords) {
if (n_str.mid(pos, kw.length()) == kw) {
if (kw == "func")
{
int n_level = levelNum;
if (foldLevel < 8192)
{
if (foldLevel >= 1024)
n_level = foldLevel - 1024 + 1;
else
n_level = foldLevel;
}
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, curLine, QsciScintilla::SC_FOLDLEVELHEADERFLAG | n_level);
}
else if (kw == "endfunc")
{
int n_level = levelNum;
if (foldLevel >= 1024)
{
if (foldLevel < 8192)
{
if (foldLevel == 1024)
{
n_level = 0;
//提示结构错误
}
else
n_level = foldLevel - 1024;
}
/*else
n_level = */
}
editor->SendScintilla(QsciScintilla::SCI_SETFOLDLEVEL, curLine, n_level);
}
pos += kw.length();
break;
}
}
if (pos < n_str.length()) {
pos++;
}
}
}









