如何进行涉及QML MouseAreas的声明性双向绑定?

时间:2018-02-21 04:49:23

标签: qt qml declarative

我创建了一个具有拨号和自定义控件的QML用户界面。自定义控件基本上是一个带MouseArea的进度条,允许用户通过单击来设置值。作为Qt的property binding docs point out,只要我在MouseArea点击处理程序中从Javascript分配自定义控件的值,我就会失去它与拨号盘之间的声明性绑定。 / p>

是否有可能使这种绑定双向,甚至更好,将两个控件的值链接到QML层次结构中它们上面的单个值?是否可以使用声明性语法来完成此操作,因此我不会在每个控件中都有复杂的事件处理程序代码?

import QtQuick 2.9
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Window 2.2
import QtQuick.Shapes 1.0


Window {
    id: window
    visible: true
    width: 800
    height: 200

    readonly property int range: 10

    RowLayout {
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        spacing: 5

        Dial {
            id: dial1
            live: true
            from: 0
            to: window.range
            stepSize: 1
            snapMode: Dial.SnapAlways
        }

        Control {
            id: dut

            implicitWidth: 200
            implicitHeight: 50

            property int range: window.range
            property int value: dial1.value

            onValueChanged: {
                console.log("New value: " + value);
            }

            Rectangle {
                width: parent.width
                height: parent.height
                color: Qt.rgba(0,0,0,0)
                border.color: Qt.rgba(0,0,0,1)
                border.width: 1
            }

            Rectangle {
                width: parent.width * dut.value/dut.range
                height: parent.height
                color: Qt.rgba(0,0,0,1)
            }

            MouseArea {
                anchors.fill: parent

                onClicked: {
                    dut.value = Math.round(mouseX/width * dut.range);
                }
            }
        }
    }
}

请注意,如果我改变关系,即。有dial1.value: dut.value,然后绑定没有被破坏(虽然它不是很双向)。

我意识到这个例子基本上重新发明了滚动条,但是我试图通过更复杂的控制来实现这一点,因为值之间的声明性关系会让生活更轻松。

评论中的详细说明:我不了解但想要了解的是,其他QML组件是如何完成的。例如,使用Dial我可以将其value属性设置为绑定到某个其他组件的属性,并且单击拨号不会删除该绑定。我不必为了做到这一点而挂钩它的鼠标事件。尽管我们已经了解了如何做到这一点,但我并没有更接近理解它。

关于QML中的双向属性绑定还有其他问题,但是我还没有能够将它们应用到我的问题中,因为(a)我真的,真的想要一些声明性的东西,以及(b){{1} }属性和事件似乎不适用于MouseArea个对象(因为,我无法弄清楚如何整合这两个东西)。

2 个答案:

答案 0 :(得分:1)

我会这样做的:

import QtQuick 2.9
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Window 2.2
import QtQuick.Shapes 1.0


Window {
    id: window
    visible: true
    width: 800
    height: 200

    readonly property int range: 10
    property int commonValue

    RowLayout {
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        spacing: 5

        Dial {
            id: dial1
            live: true
            from: 0
            to: window.range
            stepSize: 1
            snapMode: Dial.SnapAlways
            onValueChanged: {
                commonValue = dial1.value
                console.log("New value: " + value);
            }
        }
        Rectangle {
            width: 200
            height: 50
            color: Qt.rgba(0,0,0,0)
            border.color: Qt.rgba(0,0,0,1)
            border.width: 1

            MouseArea {
                anchors.fill: parent

                onClicked: {
                    commonValue = Math.round(mouseX/width * window.range)
                    dial1.value = commonValue
                }
            }

            Rectangle {
                width: parent.width * window.commonValue/window.range
                height: parent.height
                color: Qt.rgba(0,0,0,1)
            }
        }
    }
}

答案 1 :(得分:0)

使用Binding QML Type

MouseArea {
    id: mouseArea
    anchors.fill: dut
}

Binding {
    target: dut
    property: 'value'
    value: Math.round(mouseArea.mouseX/mouseArea.width * dut.range);
    when: mouseArea.pressed && mouseArea.containsMouse
}

请注意when上的Binding属性意味着它只在满足这些条件时才作为绑定激活,即。鼠标位于该区域上方,其中一个是"accepted buttons" is pressed

这个意味着当条件不满足时值会恢复,只是当值不满足时该值会停止更新。但是,如果您在其他地方有另一个绑定活动,那么可能会导致该值“快速恢复”,因为当Binding停止应用时,它将“接管”。

根据您使用的其他组件,这可能甚至不够,您可能需要在C ++中实现属性,以使它们按预期工作。