简体   繁体   中英

"engine.rootObjects().first()" in main.cpp crashes when main.qml imports over HTTP

We have a line of code that I've been using forever (or longer) to fetch a pointer to the root window. We've recently started importing our components from a server using the HTTP syntax for import. When we put then together, the program crashes, with engine.rootObjects().first() returning empty. Here is a simplified "main.cpp":

#include <QGuiApplication>
#include <QQmlApplicationEngine>

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

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    QObject* rootWindowPointer = (engine.rootObjects().first());        // <-- this is the function that fails

    return app.exec();
}

And here is a simplified "main.qml" with the import that caused the problem:

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

import "http://eggs:88/empty"       // <-- this is the added line that caused the problem

ApplicationWindow {
    id: window
    visible: true
    width: 200
    height: 100
    title: qsTr("Liblo Server Test")

    Text {
        text: "Made it this far . . ."
        anchors.centerIn: parent
    }
}

If we comment out the following line in main.cpp that gets the root window pointer, the program runs:

QObject* rootWindowPointer = (engine.rootObjects().first();

If we comment out the following line in main.qml that 'imports' our components, the program also runs:

Import "http://eggs:88/empty"

But if you have both lines enabled, then you get the following crash when that line in main.cpp tries to fetch the pointer:

20:37:03: Starting /xxxx/mark/QtApps/build-libloServer-Desktop_Qt_5_15_0_GCC_64bit-Debug/rootwindow ...
QML debugging is enabled. Only use this in a safe environment.
ASSERT: "!isEmpty()" in file ../../Qt/5.15.0/gcc_64/include/QtCore/qlist.h, line 361
20:37:04: The program has unexpectedly finished.
20:37:04: The process was ended forcefully.
20:37:04: /xxxx/xxxx/QtApps/build-libloServer-Desktop_Qt_5_15_0_GCC_64bit-Debug/rootwindow crashed.

Having no idea why these two things would be related, we considered that it might be timing (unlikely, but possible). So we put a wait line in front of the pointer fetch:

Do {} while ( engine.rootObjects().isEmpty());

But it never becomes non-empty. We also tried our real HTTP library, an empty library, and a bogus URL, with the exact same results each time (so you can try it without actually having a URL).

Does anyone have any insight on why this is happening?

If this is an obscure bug, can anyone think of a work-around?

Is there another way to fetch a pointer to the root window for C++ use?

There is nothing obscure but it is expected behavior. The rootObjects are assigned to C++ when the object is finished building and since you have an asynchronous loading url (the http) then the construction is asynchronous. So if you want to get root then you must use the objectCreated signal:

QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                 &app, [url, &engine](QObject *obj, const QUrl &objUrl) {
    if (!obj && url == objUrl)
        QCoreApplication::exit(-1);
    else{
        if(engine.rootObjects().isEmpty())
            return;
        QObject* rootWindowPointer = engine.rootObjects().first();
        qDebug() << rootWindowPointer;
    }
}, Qt::QueuedConnection);

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