Qt Qml Two Way Binding Problems

Gast #6157609
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)

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.