Furkanzmc / QML-Coding-Guide

A collection of good practices when writing QML code - https://doc.qt.io/qt/qtqml-index.html
The Unlicense
532 stars 79 forks source link

Transient Bindings break existing bindings #7

Open davemilter opened 3 years ago

davemilter commented 3 years ago

Thanks for your work. But in reality the "transient binding" described here https://github.com/Furkanzmc/QML-Coding-Guide#transient-bindings looks like broke existing binding. In code bellow expect that after destroying temp the previous binding cfg_flag1 -> flag1 will work, but actually it doesn't work right after "transient binding" creation it stops work. I tried with Qt 5.15.1

import QtQuick 2.0
import QtQuick.Controls 2.15

Rectangle {
    id: rect
    width: 100
    height: 100
    color: "red"

    property bool flag1: {
        console.log("set flag1 to", cfg_flag1);
        return cfg_flag1;
    }
    property bool cfg_flag1: true

    Text {
        anchors.centerIn: parent
        text: "flag1: " + flag1.toString() + ", cfg_flag1 " + cfg_flag1.toString()
    }

    Timer {
        id: timer
        interval: 1000
        repeat: false
        onTriggered: {
            console.log("timer trigger");
            cfg_flag1 = false;
        }
    }

    Button {
        anchors.top: parent.top
        text: "button 1"
        onClicked: {
            console.log("buggon1 cliecked");
            let temp = cmpBinding.createObject(rect, {
                "target": rect,
                "property": "flag1",
                "value": true,
                "restoreMode": Binding.RestoreBinding,
            });
            temp.Component.onDestruction.connect(function() { console.log("destroyed"); });
            temp.destroy();
            console.log("end of clicked");
            timer.start();
        }
    }

    Component {
        id: cmpBinding

        Binding {
        }

    }
}
OlivierLDff commented 3 years ago

Interesting conf about binding : https://www.youtube.com/watch?v=G6W6MSzM7rs

Furkanzmc commented 3 years ago

Sorry about the late response. I didn't receive a notification for this, or see it in my home page.

Before going into the details, I want to say that I wrote these a while ago, and with the recent changes to QML some of them do not really apply any more. My knowledge also increased, so I wouldn't even recommend some (albeit very few) of them any more. I've been meaning to do a review of it and update the information to be up-to-date but I have been very busy recently.

That being said, this may be a behaviour change in the recent versions or a bug. You can find some interesting things on Qt's Jira, particularly the bug that's highlighted once you click on the link.

The documentation for the when property states that:

When the binding becomes inactive again, any direct bindings that were previously set on the property will be restored.

It doesn't mention anything about the destruction of the binding object. I would expect a binding to be restored when the Binding object is destroyed. I tried these examples with v5.11.0, and I remember this working otherwise I wouldn't have put it here (Or I'm wrong, it's been so long I can't remember). Sadly, I can't install that version with the installer or the archive. With the recent versions, like you said, it doesn't work. However, If you use the following onClicked handler, it will work:

onClicked: {
    console.log("buggon1 cliecked");
    let temp = cmpBinding.createObject(rect, {
        "when": true,
        "target": rect,
        "property": "flag1",
        "value": true,
    });
    temp.Component.onDestruction.connect(function() {
        console.log("destroyed");
    });
    temp.when = false
    temp.destroy();
    console.log("end of clicked");
    timer.start();
}

Even when the when property is set to true and the binding is destroyed without changing the when property, it doesn't restore the binding. I think the problem you are encountering should be a bug. Even though this transient binding is kind of a hack, there might be cases where you enable a certain binding as long as an object is alive and disable the binding when that object is destroyed.

Let me know If you are willing to create a bug report for it, otherwise I'll do it referencing this issue. @davemilter