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?




  • Moderators



  • @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?


  • Moderators

    @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 your ButtonExit item and binds all the properties. However, it does not have a parent at this point, so the error message is correct: parent is null.

    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 with qobject_cast which is much more robust.
    • QQuickItem inherits QObject, so oButtonExit is redundant. Just do all your operations on oItemButtonExit:
    QQuickItem *oItemButtonExit = qobject_cast<QQuickItem*>(oComponentButtonExit.create());
    oItemButtonExit->setParentItem(...);
    oItemButtonExit->setParent(...);
    


  • @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?


  • Moderators

    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().

    1. Call QQmlComponent::beginCreate()
    2. Set the parent
    3. Call QQmlComponent::completeCreate()

    See https://doc.qt.io/qt-5/qqmlcomponent.html#beginCreate



  • @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
    


  • 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


  • Moderators

    @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 here

    I'm glad you found a solution. Happy coding!

    May I ask why you're using dynamic_cast instead of qobject_cast?


  • Qt Champions 2018

    For others reading this post :
    This is not idiomatic QML and generally leads to messy and not really maintenable code

    https://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.


 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.