Using a Qml component property for read/write access of a value without killing bindings



  • Please have a look at the following code:

    main.qml

    @
    import QtQuick 1.0

    Rectangle {
    width: 500
    height: 200

    Column {
    Text { text: "Slider 1 " + slider1.value }
    Slider { id: slider1; value: slider2.value; minimum: 0; maximum: 10; }
    Text { text: "Slider 2 (drag me to set value 1, too)" + slider2.value }
    Slider { id: slider2; minimum: 0; maximum: 10; }

    Text { text: "Text 1 " + text1.text }
    TextInput { height: 20; width: 200; id: text1; text: text2.text; }
    Text { text: "Text 2 (text entered here will show in Text 1, too)" + text2.text }
    TextInput { height: 20; width: 200; id: text2 }
    

    }
    }
    @

    Slider.qml

    @
    import QtQuick 1.0

    Item {

    property alias value: slider.value
    property alias minimum: slider.minimum
    property alias maximum: slider.maximum
    width: slider.width
    height: slider.height

    Item {
    id: slider; width: 400; height: 16

    // value is read/write.
    property real value: 1
    onValueChanged: updatePos();
    property real maximum: 1
    property real minimum: 1
    property int xMax: width - handle.width - 4
    onXMaxChanged: updatePos();
    onMinimumChanged: updatePos();
    
    function updatePos() {
      console.log("update pos")
      if (maximum > minimum) {
        var pos = 2 + (value - minimum) * slider.xMax / (maximum - minimum);
        pos = Math.min(pos, width - handle.width - 2);
        pos = Math.max(pos, 2);
        handle.x = pos;
      } else {
        handle.x = 2;
      }
    }
    
    Rectangle {
      anchors.fill: parent
      border.color: "white"; border.width: 0; radius: 8
      gradient: Gradient {
        GradientStop { position: 0.0; color: "#66343434" }
        GradientStop { position: 1.0; color: "#66000000" }
      }
    }
    
    Rectangle {
      id: handle; smooth: true
      y: 2; width: 30; height: slider.height-4; radius: 6
      gradient: Gradient {
        GradientStop { position: 0.0; color: "lightgray" }
        GradientStop { position: 1.0; color: "gray" }
      }
    
      MouseArea {
        id: mouse
        anchors.fill: parent; drag.target: parent
        drag.axis: Drag.XAxis; drag.minimumX: 2; drag.maximumX: slider.xMax+2
        onPositionChanged: { value = (slider.maximum - slider.minimum) * (handle.x-2) / slider.xMax + slider.minimum; }
      }
    }
    

    }
    }
    @

    The slider is basically taken from some example.

    Now please try the following:

    • Use slider2 to adjust the value
    • See how slider1 will display the same value as slide2 (due to the binding in main.qml:9)
    • Now use slider1 to adjust the value
    • Now use slider2 again => binding is removed (due to Slider.qml:56)

    This seems to be a problem with bindings for all components written in Qml that use the same property for read and write access of some value.

    The interesting thing is that I tried to do basically the same with a TextInput instead of the custom slider. And guess what, it works there. The binding is not lost.

    Now TextInput is a component implemented in c++. So it does not actually assign a value to its text property but rather has a getter method and a notifier signal.

    My question now is: How can i achieve this behaviour for Qml components too?

    Thanks

    Nils



  • Did you look into using the Binding element?



  • Hi Andre,

    yes. But I cannot see how Binding solves this problem.

    I've also had a look at some of the Meego/Symbian components. They do basically the same as the Slider example, killing any binding as soon as the component modifies its own value property.

    See http://qt.gitorious.org/qt-components/qt-components/blobs/master/src/meego/CheckBox.qml.

    My motivation for doing this kind of stuff is:

    • I have a settings object containing some settings
    • I want to bind the component's value property to the value of the settings object
    • Changes in the settings object's values (from somewhere else) will now automatically update the Qml components
    • Of course this only works as long as the binding exists

    This is somewhat related to: http://developer.qt.nokia.com/forums/viewthread/1779/

    I was hoping the binding mechanism would simplify the old way of doing stuff like this:

    @
    void MyDialog::settingsToWidgets()
    {
    ui->textEdit->setText(m_settings.someText());
    ui->slider->setValue(m_settings.someValue());
    }

    void MyDialog::widgetsToSettings()
    {
    m_settings.setSomeText(ui->textEdit->text());
    m_settings.setSomeValue(ui->slider->value());
    }
    @

    Thank you

    Nils



  • In Qt Quick 1.1 you can establish binding in imperative JS code... See http://developer.qt.nokia.com/forums/viewthread/5494/


Log in to reply
 

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