Details
-
Bug
-
Resolution: Duplicate
-
P2: Important
-
None
-
5.11.2
-
None
-
Windows 10, Nvidia graphic card
Description
Launching a qml application with QQmlApplicationEngine when it contains a Surface3D Item from QtDataVisualization leads to a dead-lock when closing the app.
There is no dead-lock if the qml app is launched with a QQuickWidget but using this prevents the use of ApplicationWindow Item
This happens on win10 and sometieme on win7. Never on linux
When it failed (dead-lock) this error message is displayed : Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures.
Related bugs :
Dead-lock code:
// main.cpp #include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
// main.qml import QtQuick 2.11 import QtQuick.Controls 2.4 import QtDataVisualization 1.3 ApplicationWindow { visible: true width: 640 height: 480 Surface3D{} }
Working code :
// main.cpp #include <QApplication> #include <QQuickWidget> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); QQuickWidget *view = new QQuickWidget; view->setSource(QUrl(QStringLiteral("qrc:/main.qml"))); view->show();// QQmlApplicationEngine engine; return app.exec(); }
// main.qml import QtQuick 2.11 import QtDataVisualization 1.3 Item { width: 640 height: 480 Surface3D{} }
// minimal.qbs import qbsProject { minimumQbsVersion: "1.7.1" CppApplication { Depends { name: "Qt.core" } Depends { name: "Qt.quick" } Depends { name: "Qt.quickwidgets" } Depends { name: "Qt.datavisualization" } // Additional import path used to resolve QML modules in Qt Creator's code model property pathList qmlImportPaths: [] cpp.cxxLanguageVersion: "c++11" cpp.defines: [ // The following define makes your compiler emit warnings if you use // any feature of Qt which as been marked deprecated (the exact warnings // depend on your compiler). Please consult the documentation of the // deprecated API in order to know how to port your code away from it. "QT_DEPRECATED_WARNINGS", // You can also make your code fail to compile if you use deprecated APIs. // In order to do so, uncomment the following line. // You can also select to disable deprecated APIs only up to a certain version of Qt. //"QT_DISABLE_DEPRECATED_BEFORE=0x060000" // disables all the APIs deprecated before Qt 6.0.0 ] files: [ "main.cpp", "qml.qrc", ] Group { // Properties for the produced executable fileTagsFilter: "application" qbs.install: true } } }
The workaround I'm using : I parse the qml tree looking for surface3D items and I delete them manually on closing
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQuickWindow> QObjectList grabChildrenObjByClassName(QObject *parentObj, const QString & className){ QObjectList objList; foreach(QObject *obj, parentObj->children()){ if ((obj->metaObject()->className() == className ) || (obj->metaObject()->superClass()->className() == className )){ objList << obj; }else{ objList << grabChildrenObjByClassName(obj, className); } } return objList; } int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; if(QSysInfo::productType() == "windows"){// && QSysInfo::productVersion() == "10"){ QObject *rootObj = engine.rootObjects().first(); if (rootObj != nullptr){ QQuickWindow *wnd = qobject_cast<QQuickWindow*>(rootObj); if(wnd != nullptr){ QString const className("QtDataVisualization::DeclarativeSurface"); QObjectList surface3DList = grabChildrenObjByClassName(wnd, className); QObject::connect(wnd, &QQuickWindow::visibleChanged, [surface3DList](bool flg){ if (!flg){ foreach(QObject *obj, surface3DList){ obj->deleteLater(); } } }); } } } return app.exec(); }