我们有一行代码,我一直(或更长时间)使用它来获取指向根窗口的指针。我们最近开始使用 HTTP 语法从服务器导入组件。当我们把它们放在一起时,程序崩溃,engine.rootObjects().first()返回空。这是一个简化的“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();
}
Run Code Online (Sandbox Code Playgroud)
这是一个简化的“main.qml”,其中包含导致问题的导入:
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
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们注释掉 main.cpp 中获取根窗口指针的以下行,程序就会运行:
QObject* rootWindowPointer = (engine.rootObjects().first();
如果我们注释掉 main.qml 中“导入”我们的组件的以下行,程序也会运行:
导入“http://eggs:88/empty”
但是,如果您启用了这两行,那么当 main.cpp 中的该行尝试获取指针时,您会遇到以下崩溃:
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.
Run Code Online (Sandbox Code Playgroud)
由于不知道为什么这两件事会相关,我们认为这可能是时间问题(不太可能,但有可能)。所以我们在指针获取前面放了一条等待线:
执行 {} while (engine.rootObjects().isEmpty());
但它永远不会变得非空。我们还尝试了真正的 HTTP 库、一个空库和一个伪造的 URL,每次都得到完全相同的结果(因此您可以在没有实际 URL 的情况下尝试它)。
有谁知道为什么会发生这种情况?
如果这是一个不起眼的错误,有人能想到解决方法吗?
是否有另一种方法来获取根窗口的指针以供 C++ 使用?
没有什么隐晦的,但这是预期的行为。当对象完成构建时,rootObjects 被分配给 C++,并且由于您有一个异步加载 url(http),因此构建是异步的。因此,如果你想获得 root 权限,那么你必须使用 objectCreated 信号:
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);
Run Code Online (Sandbox Code Playgroud)