Forum: PC-Programmierung Qt Qml Two Way Binding Problems


von Dirk (Gast)


Lesenswert?

Hallo, ich bringe mir immer noch Qt Qml alleine bei und knappere schon 
länger an TwoWay Bindings, deshalb konnte ich mich über dieses 
veröffentlichtes Video von der Firma KDAB freuen.

https://www.kdab.com/kdab-qt-world-summit-2019/#component
QML Component Design: the two-way binding problem

Die PowerPoints wurden auch veröffentlicht, aber das Beispiel konnte ich 
im Internet nicht finden, deshalb hab ich einige Dinge aus der PPT 
extrahiert.

Das Interface wurde wie folgt dargestellt:
1
#ifndef BOOLEANVALUE_H
2
#define BOOLEANVALUE_H
3
#include <QObject>
4
#include <QDebug>
5
#include <QTimer>
6
7
8
class BooleanValue : public QObject
9
{
10
    Q_OBJECT
11
    Q_PROPERTY(bool isOn READ isOn WRITE setOn NOTIFY isOnChanged)
12
13
public:
14
    explicit BooleanValue(QObject *parent = nullptr);
15
    explicit BooleanValue(bool initValue, QObject *parent = nullptr);
16
17
    bool isOn() const;
18
    Q_SLOT void setOn(bool isOn); // Be sure to make it a slot or Q_INVOKABLE
19
20
    //convenience API is now possible
21
    Q_INVOKABLE void toggle();
22
23
24
signals:
25
    void isOnChanged(bool isOn);
26
27
    // New for my personal test currently uncomment
28
private slots:
29
    //void timeout();
30
31
private:
32
    bool m_isOn = false;
33
34
    // New for my personal test currently uncomment
35
    // QTimer *m_timer;
36
37
38
};
39
40
#endif // BOOLEANVALUE_H

Die Implementierung konnte ich nicht finden, deshalb hab ich es 
implementiert nach besten Gewissen.
1
#include "booleanvalue.h"
2
3
BooleanValue::BooleanValue(QObject *parent) : QObject(parent)
4
{
5
    //    m_timer = new QTimer(this);
6
    //    m_timer->setSingleShot(true);
7
    //    m_timer->setInterval(100);
8
    //    connect(m_timer,&QTimer::timeout,this,&BooleanValue::timeout);
9
}
10
11
BooleanValue::BooleanValue(bool initValue, QObject *parent) : QObject(parent)
12
{
13
    m_isOn = initValue;
14
}
15
16
bool BooleanValue::isOn() const
17
{
18
    return m_isOn;
19
}
20
21
void BooleanValue::setOn(bool isOn)
22
{
23
    if(m_isOn == isOn)
24
        return;
25
26
    m_isOn = isOn;
27
    emit isOnChanged(m_isOn);
28
29
}
30
31
32
void BooleanValue::toggle()
33
{
34
    // New for my personal test currently uncomment
35
    // m_timer->start();
36
    m_isOn = !m_isOn;
37
    emit isOnChanged(m_isOn);
38
    qDebug() << "m_isOn Changed";
39
}
40
41
// New for my personal test currently uncomment
42
//void BooleanValue::timeout()
43
//{
44
//    m_isOn = !m_isOn;
45
//    emit isOnChanged(m_isOn);
46
//    qDebug() << "m_isOn Changed";
47
//}

Die Type ist dann in der main.c registiert.
1
qmlRegisterType<BooleanValue>("BooleanValue", 1, 0, "BooleanValue");

main.qml
1
import QtQuick 2.12
2
import QtQuick.Window 2.12
3
4
Window {
5
    visible: true
6
    width: 640
7
    height: 480
8
    title: qsTr("Hello World")
9
10
        CheckBox{
11
12
            id: someController
13
            text: "checkbox"
14
        }
15
        Rectangle{
16
            color: someController.checked ? "red" : "blue"
17
            width: 100
18
            height: 100
19
            anchors.centerIn: parent
20
        }
21
}

CheckBox.qml
1
import QtQuick 2.0
2
import BooleanValue 1.0
3
import QtQuick.Controls 2.12
4
import QtQuick.Layouts 1.12
5
6
Item {
7
    id: root
8
9
    property alias checked: internal.isOn
10
    property alias text: label.text
11
12
    implicitHeight: checkbox.height
13
    implicitWidth: checkbox.width + checkbox.implicitWidth + 4
14
    //ui related code
15
16
17
18
19
    Rectangle {
20
        id: checkbox
21
        implicitWidth: 48
22
        implicitHeight: 48
23
        Rectangle{
24
            color: root.checked ?  "black" : "white"
25
            anchors{
26
                fill: parent
27
                margins: 8
28
            }
29
            border {
30
                color: "black"
31
                width: 1
32
            }
33
        }
34
35
        Text{
36
            id: label
37
            anchors{
38
                left: checkbox.right
39
                verticalCenter: checkbox.verticalCenter
40
                margins: 4
41
            }
42
            font.pointSize: 16
43
44
45
        }
46
47
        BooleanValue {
48
            id: internal
49
        }
50
51
        MouseArea {
52
            anchors.fill: parent
53
            onClicked: {
54
                internal.toggle(); // works, using convenience function on BooleanValue
55
                // internal.setOn(!internal.isOn) // works too
56
                // internal.isOn = !internal.isOn // Wrong: breaks the binding
57
            }
58
        }
59
60
    }
61
}

Die Zeile würde das TwoWay Binding brechen, soweit so gut.
1
// internal.isOn = !internal.isOn // Wrong: breaks the

Wieso wird über das Q_PROPERTY Marco ein Setter angegeben?
1
 Q_PROPERTY(bool isOn READ isOn WRITE setOn NOTIFY isOnChanged)

Wieso nicht nur ein Readonly Property und eine Funktion Q_INVOKABLE oder 
Slot zum setzen?
1
 Q_PROPERTY(bool isOn READ isOn NOTIFY isOnChanged)

Somit kommt doch keiner mehr auf die Idee
1
internal.isOn = !internal.isOn // Wrong: breaks the binding

sondern benutzt immer den Slot in Qml Code zuschreiben
1
internal.setOn(!internal.isOn)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.