PDA

View Full Version : Loading additional QML files



jforejtn
24th January 2019, 16:04
Hello,

I'm struggling with dynamic loading of *.qml files. Although my real application is way bigger I have managed to reduce the problem to following code:

(1) Single c++ application loading main.qml and then loading WindControlItem.qml


/*
* main.cpp
*/
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickItem>

int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDp iScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;

// Root object for finding QML Items by their objectName
QObject* root = engine.rootObjects()[0];
assert(root != nullptr);

// The QML Item to which we want to inject our QML-Item-loaded-from-file
QQuickItem* centralPane = qobject_cast<QQuickItem*>(root->findChild<QObject*>("centralPane"));
assert(centralPane != nullptr);

// Load the QML file to a component
QString qml_path = "WeatherCtrlItem.qml";
QQmlComponent comp(&engine, QUrl::fromLocalFile(qml_path));

// Create an instance of the component
QObject* obj = comp.create();
assert(obj != nullptr);

// Up-cast it to a QQuickItem
QQuickItem *item = qobject_cast<QQuickItem*>(obj);
assert(item != nullptr);

// Born C++, die QML
engine.setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);

// Set QObject-parent to the central pane
item->setParent(centralPane);

// Set Visual-parent to the central pane
item->setParentItem(centralPane);

return app.exec();
}


(2) Content of main.qml




/*
* main.qml
*/

import QtQuick 2.10
import QtQuick.Controls 1.4

ApplicationWindow {
id: root
visible: true
width: 800
height: 600

menuBar: MenuBar {
Menu {
title: "File"
MenuItem {
text: "Exit"
onTriggered: Qt.exit(0)
}
} // Menu
} // MenuBar

Rectangle {
anchors.left: parent.left
width: (parent.width * 0.2)
height: parent.height
}

// I want this item to eventually become a parent of another dynamically loaded
// item -- that's why I give it an objectName.
Rectangle {
objectName: "centralPane"
width: parent.width * 0.6
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
}

Rectangle {
width: (parent.width * 0.2)
height: parent.height
anchors.right: parent.right
}

} // ApplicationWindow

(3) Content of WindControlItem.qml


/*
* WindControlItem.qml
*/
import QtQuick 2.10
import QtQuick.Controls 1.4

Rectangle {
id: recRoot
color: "#778899"
anchors.fill: parent

GroupBox {
id: gpbLayers
title: "Wind layers"
anchors.fill: parent

Grid {
id: grdFields
anchors.fill: parent
columns: 2

Text {
text: "speed"
}

TextField {
id: fieldSpeed
placeholderText: "meters/sec"
}

Text {
text: "direction"
}

TextField {
id: fieldDir
placeholderText: "degrees"
}

Button{
text: "Add layer"
}

} // Grid

} // GroupBox

} // Item root

When I start the application the GUI displays correctly. The problem is that after I close the ApplicationWindow lots of warnings are printed to the output:


file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/GroupBox.qml:184: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/GroupBox.qml:204: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/GroupBox.qml:205: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/GroupBox.qml:206: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/GroupBox.qml:216: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/Control.qml:90: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/AbstractCheckable.qml:123: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/Control.qml:90: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/TextField.qml:656: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/TextInputWithHandles.qml:104: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/TextInputWithHandles.qml:131: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/Control.qml:90: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/TextField.qml:656: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/TextInputWithHandles.qml:104: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/TextInputWithHandles.qml:131: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/Control.qml:90: ReferenceError: parent is not defined
file:///C:/tools/Qt/5.12.0/msvc2017/qml/QtQuick/Controls/Private/BasicButton.qml:194: ReferenceError: parent is not defined

I have tried to debug the code with both Qt 5.11.3 and Qt 5.12.0 but the resulting behavior is identical.


Finally my questions:

(1) Am I using correct approach for dynamic loading of Items defined in *.QML file?

(2) What could be the cause for the reference errors?


Than you for your answers!

anda_skoa
26th January 2019, 09:37
(1) Am I using correct approach for dynamic loading of Items defined in *.QML file?


Your case looks much more like the use case of a Loader.

A general rule of thumb is that you do not attempt to access QML created objects by objectName and findChild/findChildren.
This kind of dependency inversion (C++ code depending on specific objects in QML) is almost always a bad idea.



(2) What could be the cause for the reference errors?


Maybe order of deletion gone wrong.
Try to not set JavaScriptOwnership, the QObject parent should be enough.

But again, this looks like a classic Loader scenario to me.

Cheers,
_