QSyntaxHighlight rehighlight() 忽略从另一个线程触发的更改



我有一个拼写检查线程,它会不时触发spellcheck()信号,这些信号连接到荧光笔的rehighlight()方法。后者将整个块设置为具有红色前景。

这曾经在Qt 5.6.2中工作,在较新版本中停止工作。我无可救药地等待它在Qt 5.9.5中得到修复,但它仍然不起作用(无论是在Windows 10中还是在OS X中)。

重现问题的小例子可以从这里获得 https://bitbucket.org/ribtoks/qt-highlighting-issue(为了重现,请在输入中键入一些内容。rehighlight()将从后台线程每 7 秒触发一次)

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickTextDocument>
#include <QSyntaxHighlighter>
#include <QThread>
#include <QString>
class SpellCheckWorker : public QObject
{
Q_OBJECT
public:
explicit SpellCheckWorker(QObject *parent = 0) : QObject(parent), m_Counter(0), m_IsOK(false)
{ }
public:
bool isOK() { return m_IsOK; }
signals:
void spellcheck();
public slots:
void process() {
qInfo() << "Worker Thread is" << QThread::currentThreadId();
while (1) {
m_Counter++;
m_IsOK = m_Counter % 7 == 0;
QThread::sleep(1);
emit spellcheck();
}
}
private:
int m_Counter;
volatile bool m_IsOK;
};
class SpellCheckErrorsHighlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
SpellCheckErrorsHighlighter(SpellCheckWorker *worker, QTextDocument *document):
QSyntaxHighlighter(document),
m_Worker(worker)
{ }
virtual ~SpellCheckErrorsHighlighter() {}
protected:
virtual void highlightBlock(const QString &text) override {
if (!m_Worker->isOK()) {
qDebug() << "Worker is not OK" << text;
return;
}
qInfo() << "Reapplied formatting for" << text;
qInfo() << "Highlight thread is" << QThread::currentThreadId();
this->setFormat(0, text.length(), QColor(0xff, 0, 0));
}
private:
SpellCheckWorker *m_Worker;
};
class MainModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
explicit MainModel(QObject *parent = 0) : QObject(parent), m_Worker(nullptr)
{ }
public:
QString name() const { return m_name; }
void startChecking() {
qInfo() << "Main thread is" << QThread::currentThreadId();
m_Worker = new SpellCheckWorker();
QThread *thread = new QThread();
m_Worker->moveToThread(thread);
QObject::connect(thread, &QThread::started, m_Worker, &SpellCheckWorker::process);
thread->start();
}
Q_INVOKABLE void initNameHighlighting(QQuickTextDocument *document) {
SpellCheckErrorsHighlighter *highlighter = new SpellCheckErrorsHighlighter(m_Worker, document->textDocument());
QObject::connect(m_Worker, &SpellCheckWorker::spellcheck,
highlighter, &SpellCheckErrorsHighlighter::rehighlight);
}
signals:
void nameChanged();
public slots:
void setName(QString name)
{
if (m_name == name)
return;
m_name = name;
emit nameChanged();
}
private:
SpellCheckWorker *m_Worker;
QString m_name;
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
MainModel mainModel;
mainModel.startChecking();
QQmlApplicationEngine engine;
QQmlContext *rootContext = engine.rootContext();
rootContext->setContextProperty("mainModel", &mainModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
#include "main.moc"

main.qml

import QtQuick 2.6
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.3
import QtQuick.Window 2.0
ApplicationWindow  {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
StackView {
id: mainStackView
anchors.fill: parent
focus: true
initialItem: Rectangle {
anchors.fill: parent
Rectangle {
id: titleRect
height: 30
width: 300
anchors.centerIn: parent
color: "#ffffff"
border.color: "#000000"
border.width: titleTextInput.activeFocus ? 1 : 0
clip: true
focus: false
Flickable {
id: titleFlick
contentWidth: titleTextInput.paintedWidth
contentHeight: titleTextInput.paintedHeight
height: parent.height
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 5
anchors.rightMargin: 5
clip: true
flickableDirection: Flickable.HorizontalFlick
interactive: false
focus: false
function ensureVisible(r) {
if (contentX >= r.x)
contentX = r.x;
else if (contentX+width <= r.x+r.width)
contentX = r.x+r.width-width;
}
TextEdit {
id: titleTextInput
width: paintedWidth > titleFlick.width ? paintedWidth : titleFlick.width
height: titleFlick.height
text: mainModel.name
focus: true
onTextChanged: mainModel.name = text
Component.onCompleted: mainModel.initNameHighlighting(titleTextInput.textDocument)
onCursorRectangleChanged: titleFlick.ensureVisible(cursorRectangle)
}
}
}
}
}
}

有没有办法让它与解决方法一起工作?我需要在后台线程中保留拼写检查逻辑,因此无法将其移动到主线程。

您似乎通过以下两个陈述指的是两个不同的根本原因:

向荧光笔提供插槽调用没有问题。

m_Worker->isOK() 检查是否存在每 7 秒仅执行一次突出显示的原因。Qt中的错误只能用这个来证明。

如果我只关注第二句话,看起来问题是你无法击中陈述if (!m_Worker->isOK())对吗?

这很可能是由于您的代码或特定平台上的Qt问题而导致的问题。 您能否更改代码以避免这种情况,即仅在 7 秒后发出spellcheck信号以避免从另一个线程进行此检查?

好的,所以在弄乱了你的代码之后, 问题是您没有在第 55 行附近的 hilightBlock 指令main.cpp内调用此行,以保持以前的格式。

添加这个来修复它(我认为)这个问题仍然相当不清楚......

if (!m_Worker->isOK()) {
qDebug() << "Worker is not OK" << text;
this->setFormat(0, text.length(), this->format(0));
return;
}

问题的另一部分是你没有为语法荧光笔定义任何规则......所以一旦变成红色,它就会永远是红色的。

相关内容

  • 没有找到相关文章

最新更新