0

I am trying to read an int value from my QML side on c++ but this value remains 0 and doesn't update on c++ side while console.log() clearly shows me that it increments after each click . What am I doing wrong here?

.qml file

FocusScope {

        property alias myrecordint: startbutton.recordint

        Rectangle {
            id: buttonPaneShadow
            width: bottomColumn.width + 16
            height: parent.height
            anchors.top: parent.top
            anchors.right: parent.right
            color: "white"

            Column {
                anchors {
                    right: parent.right
                    top: parent.top
                    margins: 8
                }

                id: buttonsColumn
                anchors.rightMargin: 20
                anchors.topMargin: 20
                spacing: 12

                CameraButton {
                    id: startbutton
                    property int recordint:0
                    text: "Record"
                    visible: camera.videoRecorder.recorderStatus == CameraRecorder.LoadedStatus
                    onClicked:
                    {
                        recordint=recordint+1
                        camera.videoRecorder.record()
                        console.log(recordint)

                    }
                }
           }
      }
 }

.cpp file

   QQmlEngine engine;
   QQmlComponent component(&engine, QUrl("qrc:/VideoCaptureControls.qml"));
   QObject *object = component.create();
   qDebug() << "Property value:" << QQmlProperty::read(object, "myrecordint").toInt();
Raad
  • 37
  • 8
  • 3
    It is a very bad way to expose c++ to qml or vice versa. Qt already offers a way to connect your c++ classes with qml objects, please read here https://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html before develop your application. – calynr Feb 18 '20 at 08:30
  • 1
    @arnes Thank you so much I will definitely go through that link! I'm not that much experienced in QML but this helps! – Raad Feb 18 '20 at 08:41
  • 1
    you're very welcome, if you get stuck somewhere you can look the examples https://doc.qt.io/qt-5/qmlextendingexamples.html – calynr Feb 18 '20 at 09:15
  • @arnes Wow you're amazing thanks! I can see that there are examples about exporting `C++ Properties and Classes`. Are there any minimal examples about exporting `QML properties` as I need to access a `QML Object` on my `c++` side? – Raad Feb 18 '20 at 09:31
  • 2
    https://doc.qt.io/qt-5/qtqml-referenceexamples-adding-example.html actually this example shows how to do that. Declare and define Person class. After, at main.cpp, before `engine.load( "your_qml.qml" )` called, add this piece of code, `qmlRegisterType( "your_module_name" , 1 /*major version of your module*/ , 2 /*minor version of your module*/ , "Person" /*Qml type name*/ );` so it tells to qml engine to expose `Person` class to `qml` side. You can access your properties also you can also call `public slots:` functions from qml side – calynr Feb 18 '20 at 09:39
  • 1
    @arnes Alrighty! Thank you so much! I will play around with to see if I can make it work out! – Raad Feb 18 '20 at 09:47
  • see my answer to similar question here [link](https://stackoverflow.com/a/70176831/4780334) – Sherif O. Nov 30 '21 at 23:36

2 Answers2

0

EDIT

After commenting back and forth, it seems you are not using the instance you should use, since you are creating a new instance on a button click.

Also, the reading of the property is execute-once and not auto-updated.

All-in-all this is a classic XY problem and you should strive to use a C++ model as also pointed out by Arnes (example 1 and example 2)

Original answer (wrong since the property is top-level)

You can only read properties from the top-level of a QML object (when reading from outside the object). You should move the property as suggested below:

Rectangle {
        id: buttonPaneShadow
        width: bottomColumn.width + 16
        height: parent.height
        anchors.top: parent.top
        anchors.right: parent.right
        color: "white"

        property int recordint:0 //move to here

        Column {
            anchors {
                right: parent.right
                top: parent.top
                margins: 8
            }

            id: buttonsColumn
            anchors.rightMargin: 20
            anchors.topMargin: 20
            spacing: 12

            CameraButton {
                id: startbutton
                text: "Record"
                visible: camera.videoRecorder.recorderStatus == CameraRecorder.LoadedStatus
                onClicked:
                {
                    recordint=recordint+1
                    camera.videoRecorder.record()
                    console.log(recordint)

                }
            }
    }
}

Personally, I dislike the way you seem to implement this. I would rather go for a C++ model with properties that get updated, but that's up to you

Amfasis
  • 3,932
  • 2
  • 18
  • 27
  • Thank you for your answer. actually there was a mistake on my code. I have edited the code. my property is top-level I assume (if I am wrong kindly correct me as I'm not good in `QML`) – Raad Feb 18 '20 at 08:34
  • 1
    If it's not too much to ask would you also please give me a reference to such a c++ model? Personally I'm not a fan of the method that I have chosen either I just did it this way because I'm not aware of other methods :) – Raad Feb 18 '20 at 08:38
  • 1
    @Raad I see you already got the hint about the C++ models. To answer your other question: your property is not top-level of the qml file (assuming that is the one you load in attached .cpp file), since it is in one of the components that you qml file creates – Amfasis Feb 18 '20 at 12:42
  • Yes that is correct. but I'm passing `property int recordint` to `property alias myrecordint` which is top-level and then read it in .cpp. Am I wrong? – Raad Feb 19 '20 at 04:00
  • 1
    @Raad well that's funny then... apart from the advise of using C++ models, I'd like to understand why this fails, because it actually shouldn't. Can you tell when you where reading the property in C++ code? (continuous or only once after the loading in the .cpp snippet) – Amfasis Feb 19 '20 at 07:07
  • I execute the `c++` code block I included in the question every time I click on a `QpushButton`. could that be the problem? maybe I reread the .qml file on every click? – Raad Feb 19 '20 at 07:48
  • 1
    So that means you are creating a new `VideoCaptureControls` on every click? In that case it's no wonder you are always reading 0 and you should definitely follow the C++ model route ;-) – Amfasis Feb 19 '20 at 07:53
  • I see. so it is one time executable ? I will definitely move to c++ model but just wondering how is it possible to get the most recent QML object value instead of the initialized one in this method? is that even possible? – Raad Feb 19 '20 at 08:06
  • 1
    It's a one-time execute yes, but also, most probably you are not reading the value you think you should (I assume you have a running qml gui and are creating a non-visible object every time you click you QPushButton). About possibility: there might be a chance you can get the changed signal, so that you can read the new value, or you can do it based on a QTimer, but really: _don't_ ;-) – Amfasis Feb 19 '20 at 08:35
  • 1
    Thank you and Arnes for your helps! although I haven't solved the problem yet but I will mark your answer as accepted since it has covered the issue with details! – Raad Feb 19 '20 at 09:56
0

here is an example of code to read qml data from c

QObject *rootObject = engine.rootObjects().first();
QObject *pageOne = rootObject->findChild<QObject*>("page1box");

//calling qml function from c
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(pageOne, "myQmlFunction",
    Q_RETURN_ARG(QVariant, returnedValue),
    Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
Sherif O.
  • 506
  • 4
  • 15