简体   繁体   中英

Calling a QObject function from QML across threads

I'm trying to determine how calling QObject slots or Q_INVOKABLE methods from QML for a QObject that lives in another thread works, and whether or not its safe to do so.

Assume there's a MainThread and ThreadA. QObjectA lives in ThreadA. The QML engine/gui/everything lives in the MainThread. I expose QObjectA to the QML engine using

declarativeView->setContextProperty("someObj",ObjectA)

Now in a QML file, I call

someObj.someMethod();

Where someMethod is a slot or is Q_INVOKABLE. I'd like to know which thread actually executes the function. If it's MainThread, that would be a bad thing, and calling a method like that across threads would be dangerous. If it was executed by ThreadA however, all would be well.

Based on this documentation: http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html , I'm assuming that QMetaObject::invokeMethod() is used to call the QObject function. That documentation ( http://doc.qt.nokia.com/4.7-snapshot/qmetaobject.html#invokeMethod ), shows that there are different connection types available, just like with Qt signals and slots.

I'd like to know if Qt's qml engine automagically chooses the right type for the situation when invoking C++ methods from QML across threads, and if so, calling methods for objects that live in other threads from QML is an acceptable practice.

As it became apparent a while ago, QML doesn't seem to be able to go across threads.

So one needs to implement a C++ side intermediate object that lives in the main thread to dispatch calls to objects in other threads.

QML object -> object in a different thread // doesn't work!!!
QML object -> C++ mediator object -> object in a different thread // WORKS!!!

Basically, "transcending" threads must happen in C++ entirely, thus the need of a mediator object.

I guess the someMethod will be executed in ThreadA since the object lives in that thread.

But normally if this gives a problem, then I would do something like this.

connect(&threadA, SIGNAL(started()), someObj, SLOT(someMethod());

But to start that ThreadA we need one more CppObject to link QML and CPP.

You can use this->thread(); or QThread::currentThreadId(); inside the slot to get the thread the slot is working in. It will always be the thread, the ObjectA was created in (if there was no moveToThread() ).

The Qt-Engine will select the right Qt:ConnectionType by determine call and called thread.

Extra tip: You can use GammaRay or ThreadSanitizer to see current direct connections across threads.

QML logic is event-driven and all invokes are parts of JavaScript functions. JS functions may be event handlers (for ex. UI event handlers) or may be invoked somewhere in C++ code if you wrap them in QScript object. Also you can invoke them in JavaScript WorkerTherad. That is why only you can provide an answer, where does someObj.someMethod() invokation take place.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM