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.pswp.cn/news/904683.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904683.shtml
英文地址,請注明出處:http://en.pswp.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.…