Auto Binding 2 ways with Cpp Dynamic Property



  • Hi everyone !

    I know how Qt binding work, but it not work for Dynamic Property.
    Then I'm trying to implement 2 ways binding support Dynamic Property use simple function.

    The ideal is use eventFilter on DynamicPropertyChangedEvent to get notify when DynamicProperty changed then update destination property. (This is done as the code below)

    Q_INVOKABLE void binding(QObject* qmlObj, QString qmlProp, QObject* cppObj, QString cppProp);
    

    My class DynamicObject work as Context Object for an qml component

    class DynamicObject : public QObject
    {
        Q_OBJECT
    private:
        QMap<QString, QVariant> bindingList;
        QMap<QString, QStringList> cppToQml;
    
    protected:
        bool eventFilter(QObject *obj, QEvent *event);
    
    public:
        Q_INVOKABLE void binding(QObject* qmlObj, QString qmlProp, QObject* cppObj, QString cppProp);
        Q_INVOKABLE QObject* thisContextObject();
    }
    
    void DynamicObject::autoBinding(QObject* qmlObj, QString qmlProp, QObject* cppObj, QString cppProp)
    {
        //Set value from source (cpp) to qml
        qmlObj->setProperty(qPrintable(qmlProp), cppObj->property(qPrintable(cppProp)));
        // ==> Setup auto binding from source (cpp) to destination (qml)
        //Generate Unique Key for this binding
        QString uniqueKey = QString("%1%2%3%4").arg((size_t)qmlObj).arg(qmlProp).arg(size_t(cppObj)).arg(cppProp);
        qDebug() << "Binding Key: " + uniqueKey;
        if (!bindingList.contains(uniqueKey))
        {
            //Add Binding Info into Binding List
            BindingInfo* bInfo = new BindingInfo(qmlObj, qmlProp, cppObj, cppProp);
            QVariant val = QVariant::fromValue(bInfo);
            bindingList.insert(uniqueKey, val);
            //Add Binding Map for Cpp Property to Qml Property
            QStringList qmlPropList;
            if (cppToQml.contains(cppProp))
            {
                qmlPropList = cppToQml.value(cppProp);
            }
            qmlPropList.append(uniqueKey);
            cppToQml[cppProp] = qmlPropList;
        }
    
        // ==> Setup auto binding from destination (qml) to source (cpp)
        QVariant qmlVal = qmlObj->property(qPrintable(qmlProp));
        qDebug() << qmlVal;
        if (qmlProp == "text") {
            //Try to connect qml signal textChanged with a lot in this object
            QObject::connect(qmlObj, SIGNAL(textChanged()), this, onTextChanged);
            //Try to forward qml object's events use event filter
            qmlObj->installEventFilter(this);
        }
    }
    
    bool DynamicObject::eventFilter(QObject *obj, QEvent *event)
    {
        qDebug() << "Event Captured: " << event->type() << " on Object (" << obj << ")";
        if (event->type() == QEvent::KeyPress)
        {
            QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
            qDebug("Key pressed: %d", keyEvent->key());
        }
        if (event->type() == QEvent::KeyRelease)
        {
            QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
            qDebug("Key released: %d", keyEvent->key());
        }
        if (event->type() == QEvent::DynamicPropertyChange) {
            QDynamicPropertyChangeEvent *propEvent = static_cast<QDynamicPropertyChangeEvent *>(event);
            QString propName = propEvent->propertyName();
            qDebug() << (size_t)obj << ":" << propName;
        }
    }
    

    But it more difficult when I try to get notity when Qml Property changed

    I'm tried eventFilter, but for each controls, I have to handle correct event (To much switch case)

    Then I try to connect <property>Changed SIGNAL with corresponded slot (ex: textChanged => onTextChanged).
    I got the pointer to qml Object & property name which I need to "listen" on, But I don't know how to cast QObject to Qml Type (for example: QObject to TextField)

    Any one have any ideal or solution for this?! Please help !!!



  • I'm really need help !!!

    Any Qt core Development team, Qt Professional or Qt Moderator here can point out a direction for me?
    Or any suggestion please !!!


  • Lifetime Qt Champion

    Hi,

    Why do you need a big switch case ?

    Since these are all dynamic properties, what do you need to cast the QObjects ?

    If you are in such need for help, then you should maybe consider getting a commercial license which include support or hire someone to help you on this.



  • Dear @SGaist

    "Why do you need a big switch case ?"

    • As you can see in the DynamicObject::eventFilter. It already check if DynamicPropertyChanged Event fired or not.
      I can get KeyPress, KeyRelease, but can't get DynamicPropertyChange. So, if I handle KeyRelease for TextField or SelectionChanged for ComboBox... etc... it will be a lot of case to switch (or if ... then)

    "What do you need to cast the QObjects"

    In Qml file, I'm setup autoBinding like this

    Component.onCompleted: {
            viewModel = thisContextObject();
            autoBinding(advSearch, "model", viewModel, "FilterList")
            autoBinding(txtName, "model", viewModel, "CompanyName")
        }
    

    So I'm try to connect textChange signal of TextField (or other Property of other Qml Object) to related slot (in cpp autoBinding function). That why I need to cast QObject to TextField or something else.


  • Lifetime Qt Champion

    There's something I'm not sure I'm following properly. Can you explain a use case for dynamic properties in QML ?



  • @SGaist
    Sorry for late responded. (I don't know why I can't get notification when mine topic got answer or comment.

    Let take an sample Code for the use case

    //cpp
    QQmlContext* ctx = engine.rootContext();
        ctx->setContextObject(mainViewModel);
    
    //QML
    TextField{
       id : txtName
    }
    
    Component.onCompleted: {
       viewModel = thisContextObject();
       autoBinding(txtName, "text", viewModel, "SelectedItem.Name");
    }
    
    

    As you can see in the Code above.
    I setup an auto Binding between txtName.text <=> "SelectedItem.Name" ("SelectedItem" & "Name" are Dynamic Property in mainViewModel)
    in Qt way (With normal Property declared by Q_PROPERTY), I have to setup a binding for each way like this

    TextField{
       id : txtName
       text : SelectedItem.Name
    }
    
    Binding {
       target: SelectedItem
       property: "Name"
       value: txtName.text
    }
    

    What I want is "How to implement Qml to Cpp binding like what Binding Element does.
    if I can have a look at Binding element source code, may be I can figure it out.


  • Lifetime Qt Champion

    You can look at the code without any problem. Just download the sources, either through the maintenance tool or clone it with git.


Log in to reply
 

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