C++ object assignment between two context property in QML through Q_Invokable



  • Hi,

    I'm trying to implement a simple edit dialog in QML with (almost) pure C++ backend. The class to be edited has some displayable members and also others i.e. pointers, vectors, etc. Because of this and to keep (almost) all the logic on the C++ side, I want to have a temp instance while editing the properties in the QML window, so that I can either discard them or save them to my class instance represented there.

    One way would be to use simple properties on the QML side and assign to them the first the original values on open and the new values upon save or do nothing on discard, but that way I would have to check everything on the QML side probably in javascript and part of the logic would be transfared to the QML side, and If I have many members I would also have that my QML property and two times the assigments.

    My solution to avoid the above mentioned things is that I not just expose the two object to QML but also register their class as a QML type and then I can call a C++ clone function, as I was unable to call the overloaded assignment operator (use a single AInstance = BInstance in QML) while it would be convenient and cool.
    I also have to bind these members to their TextField.text one-by-one.

    Below you can find my MCP example. Is there a better, more sophisticated way to implement this?

    C++
    A.h

    Class A;
    
    typedef struct {
        QString prefix;
        QString firstname;
        QString lastname;
        std::vector<A*> As;
    } StructVar;
    
    class A : public QObject
    {
        Q_OBJECT
    
        Q_PROPERTY( QString  a1   READ geta1   WRITE seta1   NOTIFY   a3Changed )
        Q_PROPERTY( QString  a2   READ geta2   WRITE seta2   NOTIFY   a2Changed )
        Q_PROPERTY( QString  a3   READ geta3   WRITE seta3   NOTIFY   a3Changed )
        Q_PROPERTY( QString  var1  READ getvar1   WRITE setvar1   NOTIFY   var1Changed )
    
    signals:
        void a1Changed();
        void a2Changed();
        void a3Changed();
        void var1Changed();
    
    public:
        A( QObject *parent = 0 );
        ~A();
    
        A( const A& a );
        A& operator=( const A& a );
        Q_INVOKABLE void copy( QObject* a );
    
        ...
        setters, getters, other functions
        ...
    
    private:
        QSrtring a1;
        QSrtring a2;
        QSrtring a3;
        StructVar sv1;
        SomeOtherClass B*;
    }
    
    /* not copying here almost empty/trivial/not relevant A.cpp content */
    

    main.cpp

    #include <QApplication>
    #include <QQmlApplicationEngine>
    #include <QtQml>
    #include <QQmlContext>
    
    #include "a.h"
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        A currentA;
        currentA.seta1( "Text a1" );
        currentA.seta2( "Text a2" );
    
        A editA = currentA;
    
        qmlRegisterType<A>("My", 1, 0, "A");
    
        QQmlApplicationEngine engine;
    
        engine.rootContext()->setContextProperty( "currentA", &currentA );
        engine.rootContext()->setContextProperty( "editA",    &editA );
    
        engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
        
        return app.exec();
    }
    

    QML

    import QtQuick 2.2
    import QtQuick.Controls 1.2
    
    ApplicationWindow {
        id: appWindow
        visible: true
        height: 640
        width: 1140
        visibility: "Maximized"
    
        Rectangle {
            id: menuContainer
    
            x: 100
            y: 100
    
            width:  200
            height: 200
    
            Rectangle {
                id: saveButton
    
                x: 10
                y: 10
                width: 40
                height: 40
    
                color: "blue"
    
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        currentA.copy( editA )
                    }
                }
            }
    
            Rectangle {
                id: cancelButton
    
                x: 60
                y: 10
                width: 40
                height: 40
    
                color: "red"
    
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                         // do nothing in the example
                    }
                }
            }
    
            Item {
                id: textInputContainer
    
                width: 200
                height: 100
    
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.bottom: parent.bottom
                anchors.bottomMargin: 20
    
                Binding {
                    target: editA
                    property: "a1"
                    value: a1Text.text
                }
    
                TextField {
                    id: a1Text
    
                    text: editA.name
    
                    placeholderText: "type..."
    
                    height: 50
                    width:  150
                }
            }
        }
    }
    

    Thanks for looking it through ; )


Log in to reply
 

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