gpt4 book ai didi

c++ - 是否可以在单独的线程中将 QObject 设置为 QML 上下文属性?

转载 作者:行者123 更新时间:2023-11-28 04:34:02 24 4
gpt4 key购买 nike

我构建了一个小测试示例以更好地理解 Qt 5 提供的 QML/C++ 绑定(bind)。

QML 端基本上是一个 StackLayout,带有多个 Page,在控制台或 Label 中显示信息。用户可以使用 Button 浏览这些页面。

只要一切都在单线程中运行,就可以了。通过 QObject 的信号和槽的 QML/C++ 绑定(bind)按预期工作。

但是当我尝试将暴露给另一个线程中的 QML 的 QObject 移动时,我收到此消息并且应用程序被终止:

QQmlEngine: Illegal attempt to connect to BackendWorker(0xbe8a7c28) that is in a different thread than the QML engine QQmlApplicationEngine(0xbe8a7c44.

这是应用程序的主要部分:

int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

QGuiApplication app(argc, argv);

BackendWorker backendWorker; // expose a signal and a slot only

QQmlApplicationEngine engine;

QQmlContext *ctx = engine.rootContext();

ctx->setContextProperty("backendWorker", &backendWorker);

QThread t1;
backendWorker.moveToThread(&t1); // here is the offending part
t1.start();

engine.load(QUrl(QStringLiteral("qrc:/UI/main.qml")));

if (engine.rootObjects().isEmpty())
return -1;

return app.exec();
}

是否所有暴露给 QML 的QObject(具有属性、信号或槽或Q_INVOKABLE)都必须与QGuiApplication 存在于同一个线程中 ?

编辑:

这是一个较小的示例,它显示了一个 QStringListModel 与 QML ListView 相比,它位于一个单独的线程中并且它可以工作,那么这怎么可能呢?

// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QStringListModel>
#include <QQmlContext>
#include <QTimer>
#include <QThread>

class Functor
{
public:
Functor(QStringListModel *model) : m_model(model) { }
void operator()() {
QStringList list;
list << "item 5" << "item 6" << "item 7" ;
m_model->setStringList(list);
}
private:
QStringListModel *m_model;
};

int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

QGuiApplication app(argc, argv);

QStringListModel listModel;

Functor functor(&listModel);

QQmlApplicationEngine engine;

QQmlContext *ctx = engine.rootContext();

ctx->setContextProperty("listModel", &listModel);

QThread t1;
QStringList list;
list << "item 1" << "item 2" << "item 3" << "item 4" ;
listModel.setStringList(list);
listModel.moveToThread(&t1);
t1.start();

engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;

QTimer::singleShot(5000, functor);

return app.exec();
}

QML 方面:

// main.qml
import QtQuick 2.9
import QtQuick.Window 2.2

Window {
visible: true

ListView {
width: 200
height: 500
anchors.centerIn: parent
model: listModel
delegate: Rectangle {
height: 50
width: 200
Text {
text : display
}
}
}
}

谢谢。

最佳答案

Qt 在 C++ 级别支持跨线程边界的连接,但在 QML 级别不支持。 QML 引擎很可能在不久的将来(如果有的话)不支持它们。查看错误报告 It's not possible to connect two QML objects living in different threads由于超出范围而被关闭。

下面,您可以看到一个简化的示例来实现一个 worker 并将其作为上下文属性注册到 QML 引擎:

class BackendWorker : public QObject {
Q_OBJECT
public slots:
void operate() {
int i = 0;
while (i < 1000) {
report(i++);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
signals:
void report(int x);
};

class BackendController : public QObject {
Q_OBJECT
public:
BackendController() {
w.moveToThread(&t);
connect(this, &BackendController::start, &w, &BackendWorker::operate);
connect(&w, &BackendWorker::report, this, &BackendController::report);
t.start();
}
signals:
void start();
void report(int x);
private:
BackendWorker w;
QThread t;
};

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
BackendController c;
engine.rootContext()->setContextProperty("BackendController", &c);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}

关于c++ - 是否可以在单独的线程中将 QObject 设置为 QML 上下文属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52057450/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com