Qt 5.1通过线程的QML属性
Qt 5.1 QML property through Threads
为了解决这个问题,我创建了一个重复我遇到的相同问题的TestApp。
我正在将我的软件从Qt 4.8移植到Qt 5.1。
我的第一个程序是多线程的,只要类是线程安全的,就可以顺利地使用QML。但现在我得到了这样的信息:
QObject::connect: No such slot TestApp::run() in ..ThreadingTestmain.cpp:21
QQmlEngine: Illegal attempt to connect to TestApp(0x29cfb8) that is in a different thread than the QML engine QQmlEngine(0x2f3e0f8).
这是再现错误的代码:
main.cpp:
#include <QtGui/QGuiApplication>
#include <QQmlContext>
#include <QThread>
#include "qtquick2applicationviewer.h"
#include "testapp.h"
int main(int argc, char *argv[])
{
int out;
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
TestApp * testapp = new TestApp();
QThread * testappThread;
testappThread = new QThread();
QObject::connect(testappThread, SIGNAL(started()), testapp, SLOT(run()));
testapp->moveToThread(testappThread);
testappThread->start();
viewer.rootContext()->setContextProperty("TestApp", testapp);
viewer.setMainQmlFile(QStringLiteral("qml/ThreadingTest/main.qml"));
viewer.showExpanded();
out = app.exec();
testappThread->quit();
testappThread->wait();
delete testapp;
delete testappThread;
return out;
}
testapp.h:
#ifndef TESTAPP_H
#define TESTAPP_H
#include <QObject>
#include <QString>
#include <QTimer>
#include <QReadWriteLock>
#define HELLOWORLD "Hello World !"
extern QReadWriteLock HelloWorldLock;
class TestApp : public QObject
{
Q_OBJECT
Q_PROPERTY(QString HelloWorld READ getHelloWorld WRITE setHelloWorld NOTIFY HelloWorldChanged)
public:
explicit TestApp(QObject *parent = 0);
virtual ~TestApp();
QString getHelloWorld();
void setHelloWorld(QString);
public slots:
void run();
void toggleHelloWorld();
signals:
void HelloWorldChanged();
private:
QString m_HelloWorld;
QTimer * m_Timer;
};
#endif // TESTAPP_H
testapp.cpp:
#include "testapp.h"
QReadWriteLock HelloWorldLock(QReadWriteLock::Recursive);
TestApp::TestApp(QObject *parent) :
QObject(parent)
{
HelloWorldLock.lockForWrite();
m_HelloWorld = HELLOWORLD;
HelloWorldLock.unlock();
m_Timer = new QTimer(this);
connect(m_Timer, SIGNAL(timeout()), this, SLOT(toggleHelloWorld()));
}
TestApp::~TestApp() {
m_Timer->stop();
delete m_Timer;
}
QString TestApp::getHelloWorld() {
HelloWorldLock.lockForRead();
QString out = m_HelloWorld;
HelloWorldLock.unlock();
return out;
}
void TestApp::setHelloWorld(QString text) {
HelloWorldLock.lockForWrite();
m_HelloWorld = text;
HelloWorldLock.unlock();
emit HelloWorldChanged();
}
void TestApp::run() {
m_Timer->start(1000);
}
void TestApp::toggleHelloWorld() {
HelloWorldLock.lockForWrite();
if(m_HelloWorld == "") {
m_HelloWorld = HELLOWORLD;
}
else {
m_HelloWorld = "";
}
HelloWorldLock.unlock();
emit HelloWorldChanged();
}
main.qml:
import QtQuick 2.0
Rectangle {
width: 360
height: 360
Text {
text: TestApp.HelloWorld
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
}
我的程序相当复杂(有很多属性和类要与接口共享),我不想只为了连接我的属性而创建接口类。。。你对解决这个问题有什么建议吗?
您不需要自己线程化应用程序,因为在Qt5中,QML2引擎已经是大规模多线程的,所以只需启动QQuickView,将您需要的C++部分公开到上下文中,在其中设置QML文件,并显示()。这就足够了。不要试图自己修改QML线程,这确实比QML1中更复杂。
这里有各种各样的东西:
-
在线程之间移动QTimer是有问题的,尤其是在启动的情况下
-
辅助线程从不调用exec(),因此其中的QTimer不会启动(但我怀疑它确实会启动,因为您创建了它,然后使用moveToThread
-
QML引擎在其线程(即本例中的主线程)上肯定会调用您的属性访问器,因此它们需要像您所说的那样是线程安全的。
我的建议是对事物进行重组,以避免完全使用moveToThread,然后看看还有什么问题。
相关文章:
- QML:修改在不同QML文件(而非main.QML)中定义的子对象的属性
- Qt Quick-如何仅从c++代码与qml属性交互
- 如何将类的属性从 c++ 获取到 QML 中
- 是否可以在单独的线程中将 QObject 设置为 QML 上下文属性?
- 属性分配无效:"displayText"是文本字段 qml 中的只读属性
- QVariants 在 QML 中的C++和属性中的使用
- 在 QML 中更改父属性时更改子属性
- 从C++使用编译时安全性更改 QML 属性
- Javascript 函数作为从 c++ 定义的 QML 属性
- 如何将C++属性绑定到 QML 属性
- 当连接的 QML 属性更改时C++对象不会获取值
- C++对象的属性的 QML 属性
- 无法将 QVariantMap 设置为 QML 属性
- Qml属性挂钩
- 如何在C++中动态添加/删除QML属性
- Qt 5.1通过线程的QML属性
- 如何在依赖属性更改时重新计算绑定到 qml 属性的 c++ 函数
- 具有多个线程的 QML C++ 属性绑定
- 在Qt c++中枚举QML属性
- 自定义类型的Qml属性