qml中的TextArea使用QSyntaxHighlighter显示高亮语法

在这里插入图片描述
效果图,左侧显示行号,右侧用TextArea显示文本内容,并且语法高亮。

2025年5月8号更新

1、多行文本注释

多行文本注释跟普通的高亮规则代码不太一样,代码需要修改,这里以JavaScript举例。
先制定多行文本注释规则:

QVector<QPair<QRegularExpression, QTextCharFormat>> getJSMultiLineRules()
{QTextCharFormat multiLineCommentFormat;multiLineCommentFormat.setForeground(Qt::darkGreen);multiLineCommentFormat.setFontItalic(true);QVector<QPair<QRegularExpression, QTextCharFormat>> m_rules;m_rules << qMakePair(QRegularExpression("/\\*"), multiLineCommentFormat); // startm_rules << qMakePair(QRegularExpression("\\*/"), multiLineCommentFormat); // endreturn m_rules;
}

然后我们设置规则的时候,需要先设置完普通的规则,再设置多行文本规则:

void SyntaxHighlighter::highlightBlock(const QString &text)
{for (const auto &rule : m_rules) {QRegularExpressionMatchIterator it = rule.first.globalMatch(text);while (it.hasNext()) {QRegularExpressionMatch match = it.next();setFormat(match.capturedStart(), match.capturedLength(), rule.second);}}// 再设置多行规则setCurrentBlockState(0);if (m_language == JavaScript) {QVector<QPair<QRegularExpression, QTextCharFormat>> rules = getJSMultiLineRules();for (int i = 0; i < rules.size(); i+=2) { // +=2是因为多行的开头和结尾是一个配对,有两条规则QPair<QRegularExpression, QTextCharFormat> startRules = rules[i];QPair<QRegularExpression, QTextCharFormat> endRules = rules[i+1];int startIndex = 0;if (previousBlockState() != 1)startIndex = text.indexOf(startRules.first);while (startIndex >= 0) {QRegularExpressionMatch match = endRules.first.match(text, startIndex);int endIndex = match.capturedStart();int commentLength = 0;if (endIndex == -1) {setCurrentBlockState(1);commentLength = text.length() - startIndex;} else {commentLength = endIndex - startIndex + match.capturedLength();}setFormat(startIndex, commentLength, startRules.second);startIndex = text.indexOf(startRules.first, startIndex + commentLength);}}}
}

最后实现结果:
在这里插入图片描述

2、单行文本注释

单行文本注释,需要放在所有普通注释的规则之后,以免被覆盖。
否则就会出现这种情况,举个例子:
在这里插入图片描述

以下是正文

需要实现的功能:

1、左侧显示行号
2、右侧TextArea
3、可显示语法高亮

1、左侧显示行号

这里我用了一个ListView,让它跟TextView的行数对应起来,并且可以一起滚动。
简单的做法是,将ListView和TextView都放在一个ScrollView中,这样滚动的时候就可以让TextView和ListView一起滚动了。
我之前就是这么做的,但是后面发现TextView中有过长的内容时,横向滚动会把ListView滚走,这不是我想要的……
所以,我把ListView放在ScrollView的外面,看代码:

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15Rectangle {id: breakListRecx: 5width: 50height: textArea.heightanchors.verticalCenter: textArea.verticalCentercolor: "#F1F1F1"clip: trueListView {id: breakListViewanchors.fill: parentmodel: textArea.lineCountclip: truecontentY: textArea.contentYinteractive: falsedelegate: Item {width: breakListView.widthheight: index === 0 ?  (textArea.lineHeight + textArea.topPadding/2) : textArea.lineHeightRectangle {width: 1height: parent.heightcolor: "#999999"anchors.right: parent.right}Text {text: qsTr(String(index+1))anchors.verticalCenter: parent.verticalCenteranchors.right: parent.rightanchors.rightMargin: 8font.pixelSize: 20color: "#888888"}}}}

这里的几个重点:
1、ListView的model为textArea的lineCount;
2、ListView的contentY绑定到TextArea的contentY属性上,当然TextArea本身是没有这个属性的,这是我自己自定义算出来的
3、ListView中的delegate的height,如果是第一行的话,需要注意的是TextArea本身有一个topPadding,所以要把这个也带上,然后TextArea本身也是没有lineHeight属性的,这个也是我自定义算出来的;

2、右侧TextArea

再看看右侧的TextArea怎么实现的,首先它肯定是放在一个ScrollView中的,其次我们需要实现行号需要的那几个属性值,看代码:

Item {anchors.right: parent.rightanchors.rightMargin: 5anchors.left: breakListRec.rightanchors.top: header.bottomanchors.topMargin: 5anchors.bottom: parent.bottomanchors.bottomMargin: 5property int lineCount: textArea.lineCountproperty int lineHeight: textArea.cursorRectangle.heightproperty real contentY: textAreaScroll.contentHeight * textAreaScroll.ScrollBar.vertical.positionproperty int topPadding: textArea.topPaddingScrollView {id: textAreaScrollanchors.fill: parentclip: truebackground: Rectangle { color: "#F1F1F1" }TextArea {id: textAreabackground: Rectangle { color: "#F1F1F1" }font.pixelSize: 20selectByMouse: trueselectionColor: "#87cefa"leftPadding: 0}}
}

textArea.cursorRectangle.height可以获取到TextArea中一行的真实高度;
contentY需要用到滚动条的position来进行计算;

3、可显示语法高亮

这是本文的重点,这里采用了cpp中的QSyntaxHighlighter类,能更方便地定制高亮规则。
我这里简单定制了JSON, CPP, Python, JavaScript四种规则,可以相互切换;
首先我们先定义一个类SyntaxHighlighter,来继承QSyntaxHighlighter;

class SyntaxHighlighter : public QSyntaxHighlighter {}

其次,我们需要在类SyntaxHighlighter中重新实现函数highlightBlock;highlightBlock函数就是能让TextArea应用高亮的函数,在更改完高亮风格后,都必须要重新调用这个函数,以让TextArea刷新高亮风格;

void highlightBlock(const QString &text) override;

然后我们还需要将属性document和language暴露出来,给到qml使用;

Q_PROPERTY(QQuickTextDocument* document READ document WRITE setDocument NOTIFY documentChanged)
Q_PROPERTY(Language language READ language WRITE setLanguage NOTIFY languageChanged)public:enum Language { JSON, CPP, Python, JavaScript };// 设置语法格式Language language() const;void setLanguage(Language lang);// 设置文本内容QQuickTextDocument* document() const { return m_quickDocument; }void setDocument(QQuickTextDocument* doc);signals:void documentChanged();void languageChanged();

另外,我们还需要学习两个类,QRegularExpression和QTextCharFormat。
QRegularExpression是用来定制语法识别规则的,比如这样可以识别到单行注释:

QRegularExpression("//[^\n]*")

QTextCharFormat则是用来制定高亮风格的,比如这样可以制定高亮为加粗、蓝色:

QTextCharFormat keywordFormat;
keywordFormat.setForeground(Qt::blue);
keywordFormat.setFontWeight(QFont::Bold);

最后,我们还需要在main中注册这个类,这样qml才能使用:

qmlRegisterType<SyntaxHighlighter>("CustomHighlighter", 1, 0, "SyntaxHighlighter");

我们看看qml怎么使用这个类:

TextArea {id: textAreabackground: Rectangle { color: "#F1F1F1" }font.pixelSize: 20selectByMouse: trueselectionColor: "#87cefa"leftPadding: 0SyntaxHighlighter {id: highlighterdocument: textArea.textDocumentlanguage: SyntaxHighlighter.CPPonLanguageChanged: {var data = textArea.texttextArea.text = ""textArea.text = data}}}

☆☆ 好了,现在来看完整代码

先制定四种语法规则:

CPPRules.h

#ifndef CPPRULES_H
#define CPPRULES_H#include <QObject>
#include <QTextCharFormat>
#include <QRegularExpression>QVector<QPair<QRegularExpression, QTextCharFormat>> getCPPRules()
{QVector<QPair<QRegularExpression, QTextCharFormat> > m_rules;// 1. 关键字(蓝色加粗)QTextCharFormat keywordFormat;keywordFormat.setForeground(Qt::blue);keywordFormat.setFontWeight(QFont::Bold);QStringList keywords = {"char", "class", "const","double", "enum", "explicit","friend", "inline", "int","long", "namespace", "operator","private", "protected", "public","short", "signals", "signed","slots", "static", "struct","template", "typedef", "typename","union", "unsigned", "virtual","void", "volatile", "bool"};for (const QString &kw : keywords) {m_rules << qMakePair(QRegularExpression("\\b" + kw + "\\b"), keywordFormat);}// 2.类名QTextCharFormat classFormat;classFormat.setFontWeight(QFont::Bold);classFormat.setForeground(Qt::darkMagenta);m_rules << qMakePair(QRegularExpression("\\bQ[A-Za-z]+\\b"), classFormat);// 3. 单行注释(绿色)QTextCharFormat singleLineCommentFormat;singleLineCommentFormat.setForeground(Qt::darkGreen);m_rules << qMakePair(QRegularExpression("//[^\n]*"), singleLineCommentFormat);// 4. 多行注释(绿色斜体)QTextCharFormat multiLineCommentFormat;multiLineCommentFormat.setForeground(Qt::darkGreen);multiLineCommentFormat.setFontItalic(true);m_rules << qMakePair(QRegularExpression("/\\*.*?\\*/"), multiLineCommentFormat);// 5. 字符串(橙色)QTextCharFormat stringFormat;stringFormat.setForeground(QColor(255, 165, 0)); // 橙色m_rules << qMakePair(QRegularExpression("\".*\""), stringFormat);// 6. 数字(紫色)QTextCharFormat numberFormat;numberFormat.setForeground(Qt::darkMagenta);m_rules << qMakePair(QRegularExpression("\\b\\d+\\b"), numberFormat);// 7. 预处理指令(灰色)QTextCharFormat preprocessorFormat;preprocessorFormat.setForeground(Qt::gray);m_rules << qMakePair(QRegularExpression("#.*"), preprocessorFormat);// 8.函数名QTextCharFormat functionFormat;functionFormat.setForeground(Qt::blue);m_rules << qMakePair(QRegularExpression("(\\w+)::"), functionFormat);// 9.被引用,如A::Test中的TestQTextCharFormat functionTwoFormat;functionTwoFormat.setForeground(Qt::darkBlue);m_rules << qMakePair(QRegularExpression("\\b[A-Za-z0-9_]+(?=\\()"), functionTwoFormat);return m_rules;
}#endif // CPPRULES_H

JavaScriptRules.h

#ifndef JAVASCRIPTRULES_H
#define JAVASCRIPTRULES_H#include <QObject>
#include <QTextCharFormat>
#include <QRegularExpression>QVector<QPair<QRegularExpression, QTextCharFormat>> getJavaScriptRules() {QVector<QPair<QRegularExpression, QTextCharFormat> > m_rules;// 1. 关键字(蓝色加粗)QTextCharFormat keywordFormat;keywordFormat.setForeground(Qt::blue);keywordFormat.setFontWeight(QFont::Bold);QStringList keywords = {"function", "if", "else", "for", "while", "do", "switch", "case", "break","return", "var", "let", "const", "new", "this", "true", "false", "null","undefined", "try", "catch", "finally", "throw", "class", "extends", "import","export", "async", "await", "yield"};for (const QString &kw : keywords) {m_rules << qMakePair(QRegularExpression("\\b" + kw + "\\b"), keywordFormat);}// 2. 内置对象和方法(深蓝色)QTextCharFormat builtinFormat;builtinFormat.setForeground(QColor(0, 0, 139)); // 深蓝色QStringList builtins = {"console", "Object", "Array", "String", "Number", "Math", "JSON", "Promise","setTimeout", "fetch", "document", "window", "require"};for (const QString &bn : builtins) {m_rules << qMakePair(QRegularExpression("\\b" + bn + "\\b"), builtinFormat);}// 3. 单行注释(绿色)QTextCharFormat singleLineCommentFormat;singleLineCommentFormat.setForeground(Qt::darkGreen);m_rules << qMakePair(QRegularExpression("//[^\n]*"), singleLineCommentFormat);// 4. 多行注释(绿色斜体)QTextCharFormat multiLineCommentFormat;multiLineCommentFormat.setForeground(Qt::darkGreen);multiLineCommentFormat.setFontItalic(true);m_rules << qMakePair(QRegularExpression("/\\*.*?\\*/"), multiLineCommentFormat);// 5. 字符串(橙色)QTextCharFormat stringFormat;stringFormat.setForeground(QColor(255, 165, 0)); // 橙色// 匹配单引号、双引号、模板字符串m_rules << qMakePair(QRegularExpression("\".*?\""), stringFormat);m_rules << qMakePair(QRegularExpression("'.*?'"), stringFormat);m_rules << qMakePair(QRegularExpression("`.*?`"), stringFormat);// 6. 正则表达式(紫色)QTextCharFormat regexFormat;regexFormat.setForeground(Qt::darkMagenta);m_rules << qMakePair(QRegularExpression("/.+?/[gimuy]*"), regexFormat);// 7. 数字(紫色)QTextCharFormat numberFormat;numberFormat.setForeground(Qt::darkMagenta);m_rules << qMakePair(QRegularExpression("\\b\\d+\\.?\\d*\\b"), numberFormat);// 8. 函数定义(深红色)QTextCharFormat functionDefFormat;functionDefFormat.setForeground(QColor(139, 0, 0)); // 深红色m_rules << qMakePair(QRegularExpression("\\bfunction\\s+(\\w+)"), functionDefFormat);m_rules << qMakePair(QRegularExpression("\\b(\\w+)\\s*=\\s*function\\b"), functionDefFormat);// 9. 箭头函数(深青色)QTextCharFormat arrowFunctionFormat;arrowFunctionFormat.setForeground(QColor(0, 139, 139)); // 深青色m_rules << qMakePair(QRegularExpression("\\b(\\w+)\\s*=>"), arrowFunctionFormat);return m_rules;
}#endif // JAVASCRIPTRULES_H

JsonRules.h

#ifndef JSONRULES_H
#define JSONRULES_H#include <QObject>
#include <QTextCharFormat>
#include <QRegularExpression>QVector<QPair<QRegularExpression, QTextCharFormat>> getJsonRules() {QVector<QPair<QRegularExpression, QTextCharFormat> > m_rules;// 1. JSON Key(深蓝色加粗)QTextCharFormat keyFormat;keyFormat.setForeground(Qt::darkBlue);keyFormat.setFontWeight(QFont::Bold);m_rules << qMakePair(QRegularExpression("\"(\\w+)\"\\s*:"), keyFormat);// 2. JSON String Value(绿色)QTextCharFormat stringValueFormat;stringValueFormat.setForeground(Qt::darkGreen);m_rules << qMakePair(QRegularExpression("\".*\""), stringValueFormat);// 3. JSON Number(紫色)QTextCharFormat numberFormat;numberFormat.setForeground(Qt::darkMagenta);m_rules << qMakePair(QRegularExpression("\\b\\d+\\b"), numberFormat);return m_rules;
}#endif // JSONRULES_H

PythonRules.h

#ifndef PYTHONRULES_H
#define PYTHONRULES_H#include <QObject>
#include <QTextCharFormat>
#include <QRegularExpression>QVector<QPair<QRegularExpression, QTextCharFormat>> getPythonRules() {QVector<QPair<QRegularExpression, QTextCharFormat> > m_rules;// 1. 关键字(蓝色加粗)QTextCharFormat keywordFormat;keywordFormat.setForeground(Qt::blue);keywordFormat.setFontWeight(QFont::Bold);QStringList keywords = {"def", "class", "if", "elif", "else", "for", "while","try", "except", "finally", "with", "import", "from","as", "return", "yield", "lambda", "nonlocal", "global"};for (const QString &kw : keywords) {m_rules << qMakePair(QRegularExpression("\\b" + kw + "\\b"), keywordFormat);}// 2. 内置函数和类型(深蓝色)QTextCharFormat builtinFormat;builtinFormat.setForeground(QColor(0, 0, 139)); // 深蓝色QStringList builtins = {"print", "len", "range", "list", "dict", "str", "int","float", "True", "False", "None", "self"};for (const QString &bn : builtins) {m_rules << qMakePair(QRegularExpression("\\b" + bn + "\\b"), builtinFormat);}// 3. 单行注释(绿色)QTextCharFormat commentFormat;commentFormat.setForeground(Qt::darkGreen);m_rules << qMakePair(QRegularExpression("#[^\n]*"), commentFormat);// 4. 字符串(橙色)QTextCharFormat stringFormat;stringFormat.setForeground(QColor(255, 165, 0)); // 橙色// 匹配单引号、双引号、三引号字符串m_rules << qMakePair(QRegularExpression("\"\"\".*?\"\"\""), stringFormat);m_rules << qMakePair(QRegularExpression("'''.*?'''"), stringFormat);m_rules << qMakePair(QRegularExpression("\".*?\""), stringFormat);m_rules << qMakePair(QRegularExpression("'.*?'"), stringFormat);// 5. 装饰器(紫色)QTextCharFormat decoratorFormat;decoratorFormat.setForeground(Qt::darkMagenta);m_rules << qMakePair(QRegularExpression("@\\w+"), decoratorFormat);// 6. 数字(紫色)QTextCharFormat numberFormat;numberFormat.setForeground(Qt::darkMagenta);m_rules << qMakePair(QRegularExpression("\\b\\d+\\.?\\d*\\b"), numberFormat);// 7. 函数定义(深红色)QTextCharFormat functionDefFormat;functionDefFormat.setForeground(QColor(139, 0, 0)); // 深红色m_rules << qMakePair(QRegularExpression("\\bdef\\s+(\\w+)"), functionDefFormat);return m_rules;
}#endif // PYTHONRULES_H

再写一个QMLFunction类,用来给qml读取文件等信息

QMLFunction.h

#ifndef QMLFUNCTION_H
#define QMLFUNCTION_H#include <QUrl>
#include <QFile>
#include <QObject>
#include <QFileInfo>class QMLFunction : public QObject
{Q_OBJECT
public:explicit QMLFunction(QObject *parent = nullptr);Q_INVOKABLE QString readFile(QUrl filePath);Q_INVOKABLE void saveFile(QString data);Q_INVOKABLE int fileLanguage();private:QString currentFilePath;signals:};#endif // QMLFUNCTION_H

QMLFunction.cpp

#include "QMLFunction.h"
#include "SyntaxHighlighter.h"QMLFunction::QMLFunction(QObject *parent): QObject{parent}
{}QString QMLFunction::readFile(QUrl filePath)
{currentFilePath = "";currentFilePath = filePath.path(QUrl::PrettyDecoded);
#ifdef Q_OS_WIN32if(currentFilePath.startsWith('/')){currentFilePath = currentFilePath.remove(0,1);}
#endifQString data = "";QFile file(currentFilePath);if (file.open(QIODevice::ReadOnly)) {data = file.readAll();file.close();}return data;
}void QMLFunction::saveFile(QString data)
{QFile file(currentFilePath);if (file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {file.write(data.toUtf8());file.close();}
}int QMLFunction::fileLanguage()
{QFileInfo info(currentFilePath);QString suffix = info.suffix();if (suffix == "CPP") {return SyntaxHighlighter::CPP;} else if (suffix == "json") {return SyntaxHighlighter::JSON;} else if (suffix == "h") {return SyntaxHighlighter::CPP;} else if (suffix == "js") {return SyntaxHighlighter::JavaScript;} else if (suffix == "py") {return SyntaxHighlighter::Python;} else {return SyntaxHighlighter::CPP;}
}

再写高亮的主要类SyntaxHighlighter

SyntaxHighlighter.h

#ifndef SYNTAXHIGHLIGHTER_H
#define SYNTAXHIGHLIGHTER_H#include <QObject>
#include <QQuickTextDocument>
#include <QSyntaxHighlighter>
#include <QRegularExpression>class SyntaxHighlighter : public QSyntaxHighlighter
{Q_OBJECTQ_PROPERTY(QQuickTextDocument* document READ document WRITE setDocument NOTIFY documentChanged)Q_PROPERTY(Language language READ language WRITE setLanguage NOTIFY languageChanged)
public:enum Language { JSON, CPP, Python, JavaScript };Q_ENUM(Language)SyntaxHighlighter(QTextDocument *parent = nullptr);// 设置语法格式Language language() const;void setLanguage(Language lang);// 设置文本内容QQuickTextDocument* document() const { return m_quickDocument; }void setDocument(QQuickTextDocument* doc);protected:void highlightBlock(const QString &text) override;private:QQuickTextDocument* m_quickDocument = nullptr;Language m_language;QVector<QPair<QRegularExpression, QTextCharFormat>> m_rules;signals:void documentChanged();void languageChanged();};#endif // SYNTAXHIGHLIGHTER_H

SyntaxHighlighter.cpp

#include "SyntaxHighlighter.h"
#include "CPPRules.h"
#include "JavaScriptRules.h"
#include "PythonRules.h"
#include "JsonRules.h"// SyntaxHighlighter.cpp
SyntaxHighlighter::SyntaxHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) {
}SyntaxHighlighter::Language SyntaxHighlighter::language() const
{return m_language;
}void SyntaxHighlighter::setLanguage(Language lang)
{if (m_language == lang) return ;m_language = lang;m_rules.clear();switch (lang) {case JSON: {m_rules = getJsonRules();break;}case CPP: {m_rules = getCPPRules();break;}case Python: {m_rules = getPythonRules();break;}case JavaScript:{m_rules = getJavaScriptRules();break;}}rehighlight(); // 重新应用高亮emit languageChanged(); // 触发信号
}void SyntaxHighlighter::setDocument(QQuickTextDocument *doc)
{if (doc != m_quickDocument) {m_quickDocument = doc;QSyntaxHighlighter::setDocument(doc->textDocument()); // 关键转换emit documentChanged();}
}void SyntaxHighlighter::highlightBlock(const QString &text)
{for (const auto &rule : m_rules) {QRegularExpressionMatchIterator it = rule.first.globalMatch(text);while (it.hasNext()) {QRegularExpressionMatch match = it.next();setFormat(match.capturedStart(), match.capturedLength(), rule.second);}}
}

main.cpp

#include <QQmlContext>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "QMLFunction.h"
#include "SyntaxHighlighter.h"int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endifQGuiApplication app(argc, argv);qmlRegisterType<SyntaxHighlighter>("CustomHighlighter", 1, 0, "SyntaxHighlighter");QQmlApplicationEngine engine;QMLFunction qmlFunction;engine.rootContext()->setContextProperty("QMLFunc", &qmlFunction);qmlRegisterType<QMLFunction>("QMLEnum",1,0,"QMLEnum");const QUrl url(QStringLiteral("qrc:/main.qml"));QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,&app, [url](QObject *obj, const QUrl &objUrl) {if (!obj && url == objUrl)QCoreApplication::exit(-1);}, Qt::QueuedConnection);engine.load(url);return app.exec();
}

再看一下qml的文件代码

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15Window {id: window_width: 640height: 480visible: truetitle: qsTr("Hello World")Item {anchors.fill: parentHeader{id: header}LineCountList {id: breakListRec}MyTextArea {id: textArea}}
}

Header.qml

import QtQuick 2.15
import QtQuick.Dialogs 1.3
import QtQuick.Controls 2.15Item {id: headerwidth: parent.widthheight: 40Row {height: parent.heightwidth: parent.width - 10anchors.horizontalCenter: parent.horizontalCenterspacing: 5Rectangle {id: fileOpenwidth: 70height: 30color: fileOpenMouse.pressed ? "#dcdcdc" : "transparent"border.width: fileOpenMouse.pressed ? 1 : 0border.color: "#bcbcbc"anchors.verticalCenter: parent.verticalCenterToolTip.visible: fileOpenMouse.entered_ToolTip.text: qsTr("快捷键 Ctrl+O")Text {text: qsTr("打开")anchors.centerIn: parentfont.pixelSize: 16}MouseArea {id: fileOpenMouseanchors.fill: parenthoverEnabled: trueproperty bool entered_: falseonClicked: {fileDialog.open()}onEntered: {entered_ = true}onExited: {entered_ = false}}}Rectangle {id: fileSavewidth: 70height: 30color: fileSaveMouse.pressed ? "#dcdcdc" : "transparent"border.width: fileSaveMouse.pressed ? 1 : 0border.color: "#bcbcbc"anchors.verticalCenter: parent.verticalCenterToolTip.visible: fileSaveMouse.entered_ToolTip.text: qsTr("快捷键 Ctrl+O")Text {text: qsTr("保存")anchors.centerIn: parentfont.pixelSize: 16}MouseArea {id: fileSaveMouseanchors.fill: parenthoverEnabled: trueproperty bool entered_: falseonClicked: {QMLFunc.saveFile(textArea.getText())}onEntered: {entered_ = true}onExited: {entered_ = false}}}Item {id: languageItemwidth: 150height: 35Text {id: languageTitletext: qsTr("语法选择")anchors.verticalCenter: parent.verticalCenterfont.pixelSize: 16}ComboBox {id: languageSelectmodel: ["JSON", "CPP", "Python", "JavaScript"]onCurrentIndexChanged: {if (currentIndex !== textArea.getLanguage()) {textArea.setLanguage(currentIndex)}}}}}Rectangle {width: parent.widthheight: 1color: "#444444"anchors.bottom: parent.bottom}FileDialog {id: fileDialogonAccepted: {var data = QMLFunc.readFile(fileUrl)textArea.setText(data)textArea.setLanguage(QMLFunc.fileLanguage())languageSelect.currentIndex = QMLFunc.fileLanguage()}}Shortcut {sequence: "Ctrl+O"onActivated: {fileDialog.open()}}Shortcut {sequence: "Ctrl+S"onActivated: {QMLFunc.saveFile(textArea.getText())}}}

LineCountList.qml

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15Rectangle {id: breakListRecx: 5width: 50height: textArea.heightanchors.verticalCenter: textArea.verticalCentercolor: "#F1F1F1"clip: trueListView {id: breakListViewanchors.fill: parentmodel: textArea.lineCountclip: truecontentY: textArea.contentYinteractive: falsedelegate: Item {width: breakListView.widthheight: index === 0 ?  (textArea.lineHeight + textArea.topPadding/2) : textArea.lineHeightRectangle {width: 1height: parent.heightcolor: "#999999"anchors.right: parent.right}Text {text: qsTr(String(index+1))anchors.verticalCenter: parent.verticalCenteranchors.right: parent.rightanchors.rightMargin: 8font.pixelSize: 20color: "#888888"}MouseArea {anchors.fill: parentonClicked: {textArea.selectLine(index)}}}}}

MyTextArea.qml

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import CustomHighlighter 1.0Item {anchors.right: parent.rightanchors.rightMargin: 5anchors.left: breakListRec.rightanchors.top: header.bottomanchors.topMargin: 5anchors.bottom: parent.bottomanchors.bottomMargin: 5property int lineCount: textArea.lineCountproperty int lineHeight: textArea.cursorRectangle.heightproperty real contentY: textAreaScroll.contentHeight * textAreaScroll.ScrollBar.vertical.positionproperty int topPadding: textArea.topPaddingScrollView {id: textAreaScrollanchors.fill: parentclip: truebackground: Rectangle { color: "#F1F1F1" }TextArea {id: textAreabackground: Rectangle { color: "#F1F1F1" }font.pixelSize: 20selectByMouse: trueselectionColor: "#87cefa"leftPadding: 0SyntaxHighlighter {id: highlighterdocument: textArea.textDocumentlanguage: SyntaxHighlighter.CPPonLanguageChanged: {var data = textArea.texttextArea.text = ""textArea.text = data}}}}function setText(text) {textArea.text = text}function getText() {return textArea.text}// 选中指定行的函数function selectLine(lineIndex) {var lines = textArea.text.split("\n");if (lineIndex < 0 || lineIndex >= lines.length) return;// 计算行首位置var startPos = 0;for (var i = 0; i < lineIndex; i++) {startPos += lines[i].length + 1; // +1 是换行符}// 计算行尾位置var endPos = startPos + lines[lineIndex].length+1;// 选中行并更新当前行textArea.select(startPos, endPos);forceActiveFocus();}function setLanguage(type) {highlighter.language = type}function getLanguage() {return highlighter.language;}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/904683.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python从入门到精通】--‘@‘符号的作用

在Python中&#xff0c;符号主要有三种用途&#xff1a;装饰器&#xff08;Decorator&#xff09;、矩阵乘法运算符&#xff08;Python 3.5&#xff09;以及类型提示中的修饰符&#xff08;如typing&#xff09;。 目录 1.--装饰器&#xff08;Decorator&#xff09; 2.--矩…

VAE和Stable Diffusion的关系

文章目录 ✅ 简单回顾&#xff1a;什么是 VAE&#xff1f;&#x1f504; Stable Diffusion 和 VAE 的关系&#xff1a;&#x1f3af; 编码器&#xff1a;&#x1f4a5; 解码器&#xff1a; &#x1f914; 那 Stable Diffusion 本身是 VAE 吗&#xff1f;&#x1f9e0; 简要对比…

PyTorch_点积运算

点积运算要求第一个矩阵 shape:(n, m)&#xff0c;第二个矩阵 shape: (m, p), 两个矩阵点积运算shape为&#xff1a;(n,p) 运算符 用于进行两个矩阵的点乘运算torch.mm 用于进行两个矩阵点乘运算&#xff0c;要求输入的矩阵为3维 &#xff08;mm 代表 mat, mul&#xff09;to…

02_JVM

1、JVM虚拟机组成及内存分配 三大部分&#xff1a; 类装载子系统JVM虚拟机字节码执行引擎 其中&#xff0c;JVM虚拟机运行时数据区&#xff08;内存模型&#xff09;包含五部分&#xff1a;堆、栈&#xff08;线程&#xff09;、方法区&#xff08;元空间&#xff09;、本地…

基于FPGA控制PCF8591开展ADC采样,以采样烟雾模块输出模拟电压为例(IIC通信)

基于FPGA控制PCF8591开展ADC采样 前言一、芯片手册阅读1.设备地址2.字节地址3.IIC通信协议 二、仿真分析三、代码分析总结视频演示 前言 这段时间做设计总是遇到一些传感器模块输出模拟电压&#xff0c;采集模拟电压进而了解传感器输出的浓度占比&#xff0c;在淘宝上找到了一…

在Python和C/C++之间共享std::vector<std::vector<int>>数据

在Python和C/C之间共享std::vector<std::vector>数据 在Python和C/C之间共享嵌套向量数据(std::vector<std::vector<int>>)可以通过几种方法实现。以下是几种常见的方法&#xff1a; 方法1: 使用Cython Cython是连接Python和C的很好选择&#xff0c;它可以…

Linux NVIDIA 显卡驱动安装指南(适用于 RHEL/CentOS)

&#x1f4cc; 一、禁用 Nouveau 开源驱动 NVIDIA 闭源驱动与开源的 nouveau 驱动冲突&#xff0c;需先禁用&#xff1a; if [ ! -f /etc/modprobe.d/blacklist-nouveau.conf ]; thenecho -e "blacklist nouveau\noptions nouveau modeset0" | sudo tee /etc/modpr…

Python爬虫实战:获取千库网各类素材图片,为设计师提供参考

一、引言 在当今设计领域,丰富的素材积累对设计师而言至关重要。千库网作为一个素材资源丰富的平台,拥有海量的各类素材图片。然而,手动从该网站收集素材不仅耗时,而且效率低下。Python 作为一种功能强大的编程语言,具备丰富的库和工具,可用于开发高效的爬虫程序。通过 …

vue截图-html2canvas

使用html2canvas进行截图操作 在 Vue 中使用 ​​html2canvas​​ 将 HTML 元素&#xff08;如包含贝塞尔曲线的 Canvas/SVG&#xff09;转换为图片 下载html2canvas npm install html2canvas在页面中使用&#xff0c;要截取哪个div的内容&#xff0c;先给这个div加一个ref标…

介绍Unity中的Dictionary

在 Unity&#xff08;C#&#xff09;中&#xff0c;Dictionary 是一个非常常用的数据结构&#xff0c;它提供 键值对&#xff08;Key-Value Pair&#xff09; 的存储方式。类似于 Python 的 dict 或 JavaScript 的对象&#xff08;Object&#xff09;&#xff0c;但它是强类型的…

MySQL 常用函数(详解)

目录 一、数学函数1.1 四舍五入函数1.2 求绝对值函数二、日期时间函数2.1 获取当前日期和时间三、字符串函数3.1 字符串拼接函数3.2 提取子字符串函数四、聚合函数4.1 计算平均值函数4.2 计算最大值函数五、转换函数5.1 类型转换函数六、总结MySQL 提供了丰富的内置函数,涵盖了…

SOFA编译-Ubuntu20.04-SOFA22.12

一、事前说明 单纯的编译sofa是很简单的&#xff0c;但是想要同时编译SofaPython3则比较难了&#xff0c;我编译了v22.12分支&#xff0c;其他版本sofa的编译也可以参考此篇教程&#xff0c;需注意的是&#xff1a; 1、确定SOFA需要的Python版本&#xff0c;sofa22.12需要的是…

静态BFD配置

AR2配置 int g0/0/0 ip add 10.10.10.2 quit bfd quit bfd 1 bind peer-ip 10.10.10.1 source-ip 10.10.10.2 auto commit AR1配置 int g0/0/0 ip add 10.10.10.1 int g0/0/1 ip add 10.10.11.1 quit bfd quit bfd 1 bind peer-ip 10.0.12.2 source-ip 10.0.12.1 auto co…

关键字where

C# 中的 where 关键字主要用在泛型约束&#xff08;Generic Constraints&#xff09;中&#xff0c;目的是对泛型类型参数限制其必须满足的条件&#xff0c;从而保证类型参数具备特定的能力或特性&#xff0c;增强类型安全和代码可读性。 约束写法说明适用场景举例C#版本要求w…

Arm核的Ubuntu系统上安装Wireshark

Arm核的Ubuntu系统上安装Wireshark 一、安装wireshark 安装命令&#xff1a; sudo apt-get install wireshark-qt 如下图所示&#xff1a; 安装过程弹出如下界面&#xff1a; 鼠标选择Yes&#xff0c;点回车键确认 安装完成。 二、打开wireshark 输入命令行打开wireshark …

编专利或委托他人编专利属于学术不端行为吗?

原文链接&#xff1a;编专利或委托他人编专利属于学术不端行为吗&#xff1f; 自己编专利或委托他人编专利属于学术不端吗&#xff1f; 5月4日&#xff0c;一篇题为《针对性护理干预在子宫肌瘤围手术期的情绪和生活质量临床应用效果》的论文&#xff0c;受到网友的广泛议论。…

Music AI Sandbox:打开你的创作新世界

AI 和音乐人的碰撞 其实&#xff0c;Google 早在 2016 年就启动了一个叫 Magenta 的项目&#xff0c;目标是探索 AI 在音乐和艺术创作上的可能性。一路走来&#xff0c;他们和各种音乐人合作&#xff0c;终于在 2023 年整出了这个 Music AI Sandbox&#xff0c;并且通过 YouTub…

Java游戏服务器开发流水账(2)开发中Maven的管理

Maven 是一款流行的 Java 项目管理工具&#xff0c;它基于项目对象模型&#xff08;Project Object Model&#xff0c;POM&#xff09;的概念来管理项目的构建、依赖和文档等。游戏服务器开发中也会使用. 项目构建 生命周期管理&#xff1a;Maven 定义了一套清晰的项目构建生…

枚举 · 例8扩展-校门外的树:hard

登录—专业IT笔试面试备考平台_牛客网 代码区&#xff1a; #include<algorithm> #include<iostream> #include<vector>using namespace std; struct TREE{int left,right; }; bool compare(const TREE&a,const TREE& b ){if(a.left!b.left){return…

Windows Server 2025 安装AMD显卡驱动

运行显卡驱动安装程序&#xff0c;会提示出问题。但是此时资源已经解压 来到驱动路径 C:\AMD\AMD-Software-Installer\Packages\Drivers\Display\WT6A_INF 打开配置文件&#xff0c;把这两行替换掉 %ATI% ATI.Mfg, NTamd64.10.0...16299, NTamd64.10.0, NTamd64.6.0, NTamd64.…