Error in creating QML Component from C++. Why?
-
Hello!
I am trying to create QML Component from C++. Everything works fine, but I have this errors in log on start application (When I am trying to create it in QML - no errors):qrc:/ButtonExit.qml:30: TypeError: Cannot read property 'width' of null qrc:/ButtonExit.qml:32: TypeError: Cannot read property 'horizontalCenter' of null
on kill application
qrc:/ButtonExit.qml:32: TypeError: Cannot read property 'horizontalCenter' of undefined qrc:/ButtonExit.qml:38: TypeError: Cannot read property 'horizontalCenter' of undefined
Every property that is predefined in button.qml within "parent" rising error but everything works fine:
Rectangle { id: buttonExit; objectName: "buttonExit"; color: COLOR.blueDark(); width: parent.width * 0.8; height: width * 0.2; anchors.horizontalCenter: parent.horizontalCenter; Text { id: buttonExitLabel; text: qsTr("Exit"); anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: parent.verticalCenter; color: COLOR.whiteClean(); font.pointSize: 18; } MouseArea { id: buttonExitArea; anchors.fill: parent; onClicked: { Qt.quit(); } } }
main.cpp:
int main(int Counter, char *Arguments[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication Application(Counter, Arguments); QQmlApplicationEngine Engine; Engine.load(QUrl(Main)); if (Engine.rootObjects().isEmpty()) { return -1; } QObject *oRootObject = dynamic_cast<QObject*>(Engine.rootObjects()[0]); QObject *oBottomBlock = oRootObject->findChild<QObject*>("bottomBlock"); if (oBottomBlock) { QQmlComponent oComponent(&Engine,QUrl(QString("qrc:/ButtonExit.qml"))); QObject *oButtonExit = oComponent.create(); oButtonExit->setParent(oBottomBlock); QQuickItem *oItemButtonExit = qobject_cast<QQuickItem*>(oButtonExit); oItemButtonExit->setParentItem(qobject_cast<QQuickItem*>(oBottomBlock)); aLOG << oBottomBlock; aLOG << oBottomBlock->children(); } return Application.exec(); }
How to avoid this errors?
-
I found this thread https://stackoverflow.com/questions/34721748/is-it-possible-to-access-qml-anchors-from-c related to issue.
-
-
@jksh said in Error in creating QML Component from C++. Why?:
@bogong see https://forum.qt.io/topic/53666/adding-qml-element-from-c
I've seen it and upvoted it too before :) This the first thread that been reading. The problem that I have slightly different - when I mean "parent", I mean "parent" defined inside of QML, not in C++. This parent inside of QML working (thx to you first thread) but I have error messages in log for every property in QML that is defined through calling parent.
The question is why I have error messages but it's working how it has to be working? Why there are error messages only when I am trying to define for example "width" not like number but like "parent.width" inside of QML.
The global idea is to create adoptive ui component from C++ that is using relative value (parented) and anchors instead of numbers and constants.
This what do I mean in QML created from C++:
Rectangle { ... width: parent.width; anchors.horizontalCenter: parent.horizontalCenter; ... }
When I am using this relative definition of "width" for example - it's working perfectly but I have error message. When I am using the same directly in QML - no any error and the same result, it's happening only when I am creating QML component that contain relative values from C++ only.
Rectangle { ... width: 300; ... }
When I am using constant value instead of relative - it's working perfectly too and no any error messages.
Just tested on Qt 5.12.4 and Qt 5.13 -
The same issue appeared on Qt 5.13.1. The source of example published here.
QML debugging is enabled. Only use this in a safe environment. qrc:/ButtonExit.qml:30: TypeError: Cannot read property 'width' of null qrc:/ButtonExit.qml:32: TypeError: Cannot read property 'horizontalCenter' of null qrc:/PaddingItem.qml:27: TypeError: Cannot read property 'width' of null 1567772412676 QQuickColumn(0x7ffaf842e570, name = "bottomBlock") 1567772412676 (QQuickRectangle(0x7ffb185b6a70, name = "buttonExit"), QQuickItem(0x7ffaf8469080, name = "paddingButtom"))
Is it bug or not?
-
@jksh said in Error in creating QML Component from C++. Why?:
@bogong see https://forum.qt.io/topic/53666/adding-qml-element-from-c
I've seen it and upvoted it too before :) This the first thread that been reading. The problem that I have slightly different - when I mean "parent", I mean "parent" defined inside of QML, not in C++. This parent inside of QML working (thx to you first thread) but I have error messages in log for every property in QML that is defined through calling parent.
The question is why I have error messages but it's working how it has to be working? Why there are error messages only when I am trying to define for example "width" not like number but like "parent.width" inside of QML.
The global idea is to create adoptive ui component from C++ that is using relative value (parented) and anchors instead of numbers and constants.
This what do I mean in QML created from C++:
Rectangle { ... width: parent.width; anchors.horizontalCenter: parent.horizontalCenter; ... }
When I am using this relative definition of "width" for example - it's working perfectly but I have error message. When I am using the same directly in QML - no any error and the same result, it's happening only when I am creating QML component that contain relative values from C++ only.
Rectangle { ... width: 300; ... }
When I am using constant value instead of relative - it's working perfectly too and no any error messages.
Just tested on Qt 5.12.4 and Qt 5.13@bogong said in Error in creating QML Component from C++. Why?:
The question is why I have error messages but it's working how it has to be working? Why there are error messages only when I am trying to define for example "width" not like number but like "parent.width" inside of QML.
When you call
QQmlComponent oComponentButtonExit(&Engine,QUrl(QString("qrc:/ButtonExit.qml")));
, Qt creates yourButtonExit
item and binds all the properties. However, it does not have a parent at this point, so the error message is correct: parent isnull
.After the
ButtonExit
is created, you set the parent so the property bindings start working.To see this in action, add some debug messages:
QQmlComponent oComponentButtonExit(&Engine,QUrl(QString("qrc:/ButtonExit.qml"))); QObject *oButtonExit = oComponentButtonExit.create(); QQuickItem *oItemButtonExit = qobject_cast<QQuickItem*>(oButtonExit); qDebug() << "Before: " << oItemButtonExit; // <-- Add this oItemButtonExit->setParentItem(qobject_cast<QQuickItem*>(oBottomBlock)); oButtonExit->setParent(oBottomBlock); qDebug() << "After: " << oItemButtonExit; // <-- Add this
Notes:
- Do replace
dynamic_cast
withqobject_cast
which is much more robust. QQuickItem
inheritsQObject
, so oButtonExit is redundant. Just do all your operations on oItemButtonExit:
QQuickItem *oItemButtonExit = qobject_cast<QQuickItem*>(oComponentButtonExit.create()); oItemButtonExit->setParentItem(...); oItemButtonExit->setParent(...);
- Do replace
-
@bogong said in Error in creating QML Component from C++. Why?:
The question is why I have error messages but it's working how it has to be working? Why there are error messages only when I am trying to define for example "width" not like number but like "parent.width" inside of QML.
When you call
QQmlComponent oComponentButtonExit(&Engine,QUrl(QString("qrc:/ButtonExit.qml")));
, Qt creates yourButtonExit
item and binds all the properties. However, it does not have a parent at this point, so the error message is correct: parent isnull
.After the
ButtonExit
is created, you set the parent so the property bindings start working.To see this in action, add some debug messages:
QQmlComponent oComponentButtonExit(&Engine,QUrl(QString("qrc:/ButtonExit.qml"))); QObject *oButtonExit = oComponentButtonExit.create(); QQuickItem *oItemButtonExit = qobject_cast<QQuickItem*>(oButtonExit); qDebug() << "Before: " << oItemButtonExit; // <-- Add this oItemButtonExit->setParentItem(qobject_cast<QQuickItem*>(oBottomBlock)); oButtonExit->setParent(oBottomBlock); qDebug() << "After: " << oItemButtonExit; // <-- Add this
Notes:
- Do replace
dynamic_cast
withqobject_cast
which is much more robust. QQuickItem
inheritsQObject
, so oButtonExit is redundant. Just do all your operations on oItemButtonExit:
QQuickItem *oItemButtonExit = qobject_cast<QQuickItem*>(oComponentButtonExit.create()); oItemButtonExit->setParentItem(...); oItemButtonExit->setParent(...);
- Do replace
-
@jksh SUPER-MEGA-HUGE Thanks to you for this explanation. It's making clear for me now. Is there any way to create with parent for avoiding this messages?
You're welcome!
@bogong said in Error in creating QML Component from C++. Why?:
Is there any way to create with parent for avoiding this messages?
I haven't tried it myself, but I think you must avoid
QQmlComponent::create()
.- Call
QQmlComponent::beginCreate()
- Set the parent
- Call
QQmlComponent::completeCreate()
- Call
-
You're welcome!
@bogong said in Error in creating QML Component from C++. Why?:
Is there any way to create with parent for avoiding this messages?
I haven't tried it myself, but I think you must avoid
QQmlComponent::create()
.- Call
QQmlComponent::beginCreate()
- Set the parent
- Call
QQmlComponent::completeCreate()
@jksh This works fine on creating:
QQmlComponent oComponentButtonExit(&Engine,QUrl(QString("qrc:/ButtonExit.qml"))); QQuickItem *oItemButtonExit = dynamic_cast<QQuickItem*>(oComponentButtonExit.beginCreate(Engine.rootContext())); oItemButtonExit->setParentItem(dynamic_cast<QQuickItem*>(oBottomBlock)); oItemButtonExit->setParent(oBottomBlock); oComponentButtonExit.completeCreate();
But there are on killing application still troubles:
QML debugging is enabled. Only use this in a safe environment. 1567855709534 QQuickColumn(0x7f9c09406a40, name = "bottomBlock") 1567855709535 (QQuickRectangle(0x7f9c2b089530, name = "buttonExit")) qrc:/ButtonExit.qml:32: TypeError: Cannot read property 'horizontalCenter' of undefined qrc:/ButtonExit.qml:38: TypeError: Cannot read property 'horizontalCenter' of undefined qrc:/ButtonExit.qml:39: TypeError: Cannot read property 'verticalCenter' of undefined
- Call
-
-
Solution found. It's a little tricky but do not rising any error message.
Briefly - you have to define object creating function in QML and invoke it from C++. Only then it's working correctly, without any error messages. The example published here@bogong said in Error in creating QML Component from C++. Why?:
Solution found. It's a little tricky but do not rising any error message.
Briefly - you have to define object creating function in QML and invoke it from C++. Only then it's working correctly, without any error messages. The example published hereI'm glad you found a solution. Happy coding!
May I ask why you're using
dynamic_cast
instead ofqobject_cast
? -
For others reading this post :
This is not idiomatic QML and generally leads to messy and not really maintenable codehttps://forum.qt.io/post/548974
Don't access QML objects from C++. Instead expose your data from C++ to QML and present or react on it accordingly in QML.
-
@bogong said in Error in creating QML Component from C++. Why?:
nchors.horizontalCenter: parent.horizontalCenter;
I'm glad you gays found a solution. Happy coding!
But there are other way that work very well and without any error messages too.:
Rectangle { id: buttonExit; anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined }