Я создал небольшой тестовый пример, чтобы лучше понять привязки QML / C ++, предлагаемые Qt 5.
Сторона QML в основном представляет собой StackLayout
с несколькими Page
, которые отображают информацию на консоли или в Label
. Пользователь может перемещаться по этим страницам, используя Button
.
Пока все работает в одном потоке, все в порядке.
Привязки QML / C ++ к сигналам и слотам QObject
работают должным образом.
Но когда я пытаюсь переместить QObject
, доступный для QML, в другой поток, я получаю это сообщение, и приложение уничтожается:
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();
}
Должны ли все QObject
, открытые для QML (со свойствами, сигналами или слотами или 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
}
}
}
}
Спасибо.