我正在做一个QtQuick 2.0
演示文稿,我想嵌入一些代码示例。是否可以轻松创建语法突出显示 QML 元素。
有问题的目标是将语法突出显示应用于 aTextEdit
或 a TextArea
。我知道 Qt 有 a QSyntaxHighlighter
,但文档不是很清楚如何将它应用到 aTextEdit
或 a TextArea
。
你能举例说明它是如何完成的吗?
我正在做一个QtQuick 2.0
演示文稿,我想嵌入一些代码示例。是否可以轻松创建语法突出显示 QML 元素。
有问题的目标是将语法突出显示应用于 aTextEdit
或 a TextArea
。我知道 Qt 有 a QSyntaxHighlighter
,但文档不是很清楚如何将它应用到 aTextEdit
或 a TextArea
。
你能举例说明它是如何完成的吗?
Qt Quick 的TextEdit
项目公开了一个textDocument
类型为 的属性QQuickTextDocument
。这是明确公开的,因此您可以QSyntaxHighlighter
直接与文档一起使用。
我有两个答案:
对于纯 QML 答案,我们可以使用TextArea
一个可以textFormat: TextEdit.RichText
用于格式化的。我们可以使用TextArea::getText()
获取纯文本并设置TextArea::text
富文本。这是一个模拟示例:
这是片段:
TextArea {
id: output
property bool processing: false
text: "<p>x = 123;</p><p>y = 456;</p><p>z = x + y;</p>"
textFormat: TextEdit.RichText
selectByMouse: true
onTextChanged: {
if (!processing) {
processing = true;
let p = cursorPosition;
let markUp = getText(0, length).replace(
/([A-Z][A-Za-z]*|[a-z][A-Za-z]*|[0-9]+|[ \t\n]|['][^']*[']|[^A-Za-z0-9\t\n ])/g,
function (f) {
console.log("f: ", JSON.stringify(f));
if (f.match(/^[A-Z][A-Za-z]*$/))
return "<span style='color:#800080'>" + f + "</span>";
if (f.match(/^[a-z][A-Za-z]*$/))
return "<span style='color:#800000'>" + f + "</span>";
else if (f.match(/^[0-9]+$/))
return "<span style='color:#0000ff'>" + f + "</span>";
else if (f.match(/^[ ]/))
return " "
else if (f.match(/^[\t\n]/))
return f;
else if (f.match(/^[']/))
return "<span style='color:#008000'>" + f + "</span>";
else
return f;
}
);
text = markUp;
cursorPosition = p;
processing = false;
}
}
}
要使用 Qt 的 QSyntaxHighlighter,您需要以下内容:
QSyntaxHighlighter::highlightBlock( const QString& text )
在派生类中实现,setFormat()
根据需要经常调用以标记找到的文本。为了让事情变得更简单,我创建了一个示例应用程序https://github.com/stephenquan/QtSyntaxHighlighterApp
,它包含QSyntaxHighlighter
和QTextFormat
asSyntaxHighlighter
和TextFormat
QML 类型。这样,可以处理 onHighlightBlock 信号并将语法高亮的业务逻辑放在 Javascript 而不是 C++ 中:
TextEdit {
id: textEdit
selectByMouse: true
text: [
"import QtQuick 2.12",
"",
"Item {",
" Rectangle {",
" width: 50",
" height: 50",
" color: '#800000'",
" }",
"}",
].join("\n") + "\n"
font.pointSize: 12
}
SyntaxHighlighter {
id: syntaxHighlighter
textDocument: textEdit.textDocument
onHighlightBlock: {
let rx = /\/\/.*|[A-Za-z.]+(\s*:)?|\d+(.\d*)?|'[^']*?'|"[^"]*?"/g;
let m;
while ( ( m = rx.exec(text) ) !== null ) {
if (m[0].match(/^\/\/.*/)) {
setFormat(m.index, m[0].length, commentFormat);
continue;
}
if (m[0].match(/^[a-z][A-Za-z.]*\s*:/)) {
setFormat(m.index, m[0].match(/^[a-z][A-Za-z.]*/)[0].length, propertyFormat);
continue;
}
if (m[0].match(/^[a-z]/)) {
let keywords = [ 'import', 'function', 'bool', 'var',
'int', 'string', 'let', 'const', 'property',
'if', 'continue', 'for', 'break', 'while',
];
if (keywords.includes(m[0])) {
setFormat(m.index, m[0].length, keywordFormat);
continue;
}
continue;
}
if (m[0].match(/^[A-Z]/)) {
setFormat(m.index, m[0].length, componentFormat);
continue;
}
if (m[0].match(/^\d/)) {
setFormat(m.index, m[0].length, numberFormat);
continue;
}
if (m[0].match(/^'/)) {
setFormat(m.index, m[0].length, stringFormat);
continue;
}
if (m[0].match(/^"/)) {
setFormat(m.index, m[0].length, stringFormat);
continue;
}
}
}
}
TextCharFormat { id: keywordFormat; foreground: "#808000" }
TextCharFormat { id: componentFormat; foreground: "#aa00aa"; font.pointSize: 12; font.bold: true; font.italic: true }
TextCharFormat { id: numberFormat; foreground: "#0055af" }
TextCharFormat { id: propertyFormat; foreground: "#800000" }
TextCharFormat { id: stringFormat; foreground: "green" }
TextCharFormat { id: commentFormat; foreground: "green" }
在 QML 中没有明显的方法来实现语法高亮。
可以实现自己的声明性项目,执行实际的突出显示, QSyntaxHighlighter
但随后必须为相关源代码的语言定义自己的突出显示规则。我不会为演示文稿做那么多编码。
相反,我会在一个WebView
项目中显示代码,其中突出显示已经应用为静态 HTML 标记或借助 JavaScript 突出显示库,例如highlight.js。
如果该WebView
项目确实无法使用,那么即使是Text
具有基本 HTML 支持的简单项目也应该足以处理源代码突出显示用例(如果提供静态 HTML)。
在您的应用文件中:
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQuickTextDocument* doc = childObject<QQuickTextDocument*>(engine, "textEditor", "textDocument");
Q_ASSERT(doc != 0);
// QSyntaxHighlighter derrived class
MySyntaxHighlighter* parser = new MySyntaxHighlighter(doc->textDocument());
// use parser, see QSyntaxHighlighter doc...
int ret = app.exec();
delete parser;
return ret;
获取子对象的模板函数(返回第一次出现的 objectName,因此使用唯一名称来标识 qml 文件中的对象):
template <class T> T childObject(QQmlApplicationEngine& engine,
const QString& objectName,
const QString& propertyName)
{
QList<QObject*> rootObjects = engine.rootObjects();
foreach (QObject* object, rootObjects)
{
QObject* child = object->findChild<QObject*>(objectName);
if (child != 0)
{
std::string s = propertyName.toStdString();
QObject* object = child->property(s.c_str()).value<QObject*>();
Q_ASSERT(object != 0);
T prop = dynamic_cast<T>(object);
Q_ASSERT(prop != 0);
return prop;
}
}
return (T) 0;
}
在您的 qml 文件中使用正确设置 objectName 属性的 TextEdit(在 Flickable 或任何您想要的内容中):
....
TextEdit {
id: edit
objectName: "textEditor"
width: flick.width
height: flick.height
focus: true
font.family: "Courier New"
font.pointSize: 12
wrapMode: TextEdit.NoWrap
onCursorRectangleChanged: flick.ensureVisible(cursorRectangle)
}
....
QDeclarativeItem
如果您需要一个 QML 项目来进行语法高亮,您可以通过扩展和使用上面的实用程序来简单地创建自己的项目。