Qt 5.4/Qml: Prevent binding loop

谁都会走 提交于 2020-01-01 09:10:10

问题


I have a global singleton "Settings" which holds application settings. When I try to run the following code I get a QML CheckBox: Binding loop detected for property "checked":

CheckBox {
    checked: Settings.someSetting                         
    onCheckedChanged: {
        Settings.someSetting = checked;
    }
}

It is obvious why this error occurs, but how can I correctly implement this functionality without a binding loop? E.g. I want to save the current checked state of the checkbox in the settings singleton.

I am using Qt 5.4 and Qml Quick 2.

Regards,


回答1:


Don't bind it. Because the check box does not fully depend on Setting.someSetting.

When a user clicked the checkbox, the CheckBox.checked is changed by itself. At the same time, the property binding is no longer valid. Settings.someSetting cannot modify the CheckBox after it is clicked by user. Therefore, the checked: Settings.someSetting binding is wrong.

If you want to assign an initial value to the check box when the component is ready, use Component.onCompleted to assign it:

CheckBox {
    id: someSettingCheckBox 

    Component.onCompleted: checked = Settings.someSetting
    onCheckedChanged: Settings.someSetting = checked; 
}

If you are working on a more complex scenario, the Setting.someSetting may be changed by some other things during runtime and the state of the check box is required to be changed simultaneously. Catch onSomeSettingChanged signal and explicitly changed the check box. Submit the value of someSettingCheckBox to Settings only when the program/widget/dialog/xxx finished.

CheckBox { id: someSettingCheckBox }

//within the Settings, or Connection, or somewhere that can get the signal.
onSomeSettingChanged: someSettingCheckBox.checked = someSetting



回答2:


If you don't want to make a binding loop - don't make a binding, use a proxy variable, for example. Other simple solution can be to check the value:

CheckBox {
    checked: Settings.someSetting                         
    onCheckedChanged: {
        if (checked !== Settings.someSetting) {
            Settings.someSetting = checked;
        }
    }
}



回答3:


You can also make two-way binding to resolve this issue:

CheckBox {
    id: checkBox

    Binding { target: checkBox; property: "checked"; value: Settings.someSetting }
    Binding { target: Settings; property: "someSetting"; value: checkBox.checked }
}



回答4:


Sometimes it is useful to separate input and output values in control. In this case control always displays real value and it can also show a delay to the user.

CheckBox {
    checked: Settings.someSetting
    onClicked: Settings.someSetting = !checked
}


来源:https://stackoverflow.com/questions/28250710/qt-5-4-qml-prevent-binding-loop

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!