Search code examples
c++multithreadingqtqtquick2qt-quick

How to create QtQuick window outside the main thread


What I'd like to have is a main thread that instantiates a class that extends QQuickView and moves it to a second thread.

Ideally, I would like to do something like this:

main.cpp

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    MyClass myClassObj;

    myClassObj.init();

    return 0;
}

MyClass.cpp

void init()
{
    MyQtQuickClass view;

    QThread* GUIthread = new QThread(this);

    view.moveToThread(GUIthread);
    QObject::connect(GUIthread, SIGNAL(started()), &view, SLOT(init()));

    GUIthread.start();
}

MyQtQuickCLass.cpp

void init()
{
    QQmlContext* rootContext = this->rootContext();

    // Setup view code here

    this->show();

    QGuiApplication::instance()->exec();
}

With something like this I get this error: QQmlEngine: Illegal attempt to connect to QQmlContext(0x120fc60) that is in a different thread than the QML engine QQmlEngine(0xdf6e70).

Is there a workaround? Or a way to create the QML engine directly in the second thread?


Solution

  • If you want a QQuickView to live outside the main() thread, then you must:

    1. Create a new std::thread (NOT a QThread, because it is a QObject so it mustn't be created before your QGuiApplication)
    2. Run an init() function in that thread. Let it instantiate your QGuiApplication and start the event loop.
    3. Create your QQmlEngine/QQuickView/QQuickWidget in that thread too.
    4. Ensure that all of your GUI objects are accessed from that thread only.
    5. Ensure that your main() thread doesn't create any QObjects until after your QGuiApplication has been created in your other thread.

    See How to avoid Qt app.exec() blocking main thread for more details.