Integrating QML and C++



  • Hi all,

    As the first step for being familiar with the technique integrating QML and C++ I went for this example.
    I ran it and I have some questions:

    • Why do we need a Q_PROPERTY macro there? Yeah, I know that it's said that it declares a property that could be accessed from QML. But we have two functions for both reading and writing to the data member. (userName) We could have declared a data member named, say, userName, and haven't declared a a Q_PROPERTY macro seemingly.

    • The program does almost nothing and just gets texts! Emitting the signal won't work either there.


  • Moderators

    @tomy said in Integrating QML and C++:

    We could have declared a data member named

    You mean a public member? Well, it is called encapsulation in object oriented languages: you make your data fields private and provide read/write methods where you can control the access (for example refuse changes which should not be possible).



  • @tomy said in Integrating QML and C++:

    I ran it and I have some questions:

    • Why do we need a Q_PROPERTY macro there? Yeah, I know that it's said that it declares a property that could be accessed from QML. But we have two functions for both reading and writing to the data member. (userName) We could have declared a data member named, say, userName, and haven't declared a a Q_PROPERTY macro seemingly.

    • The program does almost nothing and just gets texts! Emitting the signal won't work either there.

    hi tomy

    let's see if I can makes a bit more clear for you, with my (limited) knowledge.

    first of lets change the example q_propery a bit so one does not get confused with the nomenclature

    //original
    Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged)
    
    //new
    Q_PROPERTY(QString userName READ getUserName WRITE setUserName NOTIFY userNameChanged)
    

    On the QML-Side the property is named userName
    you can do property bindings with it:

    userName : "FixesText"
    
    //or
    userName: otherStringProperty
    

    if a bound property is changed the signal userNameChanged is emitted

    on QML-Side you can attach to that via

    onUserNameChanged: console.log("Username was changed", userName)
    

    on cpp side via QObject:::connect()

    connect(this, myClass::userNameChanged, [=]{qDebug() << "Username was changed" << getUserName();});
    

    the signal is always emitted on both sides, QML and cpp

    assigning a new string to the property on qml side

    userName = "New Username"
    

    actually envokes the cpp function setUserName

    If you envoke setUserName from the cpp class, userNameChanged is emitted, if the string actually is different from before:

    If a QML property is bound to userName, QML will call getUserName to get the new string and update all bound properties.

    emitting userNameChanged() from cpp without actually chaning m_userName will have no visible change in your QML code, but it will update all bound properties.

    chaning m_userName without emitting the signal userNameChanged on cpp side will not update the QML part



  • @jsulm
    No, I exactly meant a private date member, say, next to m_userName.


  • Qt Champions 2017

    @tomy
    But private members are private and
    cannot be accessed by any one outside the class.
    :)



  • @J.Hilk

    Hi J.Hilk, thank you very much.

    //original
    Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged)
    
    //new
    Q_PROPERTY(QString userName READ getUserName WRITE setUserName NOTIFY userNameChanged)
    

    On the QML-Side the property is named userName

    So declaring a Q_PROPERTY is the only way to have a property/variable inside the C++ code and also have access to it from QML side and declaring such a property inside the private or even public area (on the C++ side) doesn't provide us with accessing it from the QML side, yes?

    if a bound property is changed the signal userNameChanged is emitted

    Like here:
    onTextChanged: backend.userName = text
    Yeah?

    on QML-Side you can attach to that via

    onUserNameChanged: console.log("Username was changed", userName)
    

    I used it inside the BackEnd:

    BackEnd {
            id: backend
            onUserNameChanged: console.log("Username was changed", userName)
        }
    

    If a QML property is bound to userName, QML will call getUserName to get the new string and update all bound properties.

    Like here?
    text: backend.userName



  • Hi @tomy

    So declaring a Q_PROPERTY is the only way to have a property/variable inside the C++ code and also have access to it from QML side and declaring such a property inside the private or even public area (on the C++ side) doesn't provide us with accessing it from the QML side, yes?

    Q_Property is a Macro so I would asume it does not matter if its in the public, or private section of your class. But your read &write functions defenitly have to be public.

    It is not the only way, but the most convenient. I know of one more way to get a value from a cpp class:

    //in your header
    public:
        Q_INVOKABLE int getIntValueFromCpp(){return qrand();}
    
    //In qml
    val intValue = myCppObject.getIntValueFromCpp()
    

    if a bound property is changed the signal userNameChanged is emitted

    Like here:
    onTextChanged: backend.userName = text
    Yeah?

    Yes as soon as text changes the in your backend setUserName is invoked, thanks to the Q_PROPERTY makro, and because of the body of setUserName userNameChanged is emitted if text != userName

    If a QML property is bound to userName, QML will call getUserName to get the new string and update all bound properties.

    Like here?
    text: backend.userName

    yes:
    : = Propertybinding
    = = Asigning a Value

    keep in mind, asigning a value (=) will destroy a previous binding.


Log in to reply
 

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