如何在可重用的 QML 组件中保留绑定?

How to preserve bindings in a re-usable QML component?

我试图在我的滑块组件中保留双重绑定逻辑,这样它的行为与内置的一样 Slider:

import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

Window {
    ColumnLayout {
        SimpleSlider { id: sslider0; value: .3 }
        SimpleSlider { id: sslider1; value: 1 - sslider0.value }
        Slider { id: slider0; value: .3 }
        Slider { id: slider1; value: 1 - slider0.value }
    }
}

不幸的是,它没有:

这是我的 SimpleSlider.qml:

import QtQuick 2.4

Item {
    id: simple_slider
    property real value: .5
    property real min_value: 0
    property real max_value: 1

    width: childrenRect.width
    height: childrenRect.height

    function linear(a, b, x) { return (x - a) / (b - a) }
    function mix(a, b, x)    { return a * (1 - x) + b * x }

    FontMetrics { id: fontMetrics }

    Rectangle {
        id: main_box
        width: Math.max(txt_label.width + 10, 50)
        height: fontMetrics.height + 10
        radius: 2
        color: "darkgrey"
    }

    Rectangle {
        id: filled_box
        width: linear(min_value, max_value, value) * main_box.width
        height: main_box.height
        radius: main_box.radius
        color: "orange"
    }

    Text {
        id: txt_label
        text: value.toFixed(3)
        anchors.centerIn: main_box
    }

    MouseArea {
        property real xval: simple_slider.value

        id: drag_slider
        anchors.fill: parent
        onPositionChanged: xval = get_value_from_pos(mouse.x)
        function get_value_from_pos(x) {
            var v = Math.min(Math.max(linear(0, main_box.width, x), 0), 1)
            return mix(min_value, max_value, v)
        }
    }

    Binding {
        target: simple_slider
        property: "value"
        value: drag_slider.xval
    }
}

原因很明显:我在这里覆盖绑定:onPositionChanged: xval = get_value_from_pos(mouse.x)(并由 QT_LOGGING_RULES="qt.qml.binding.removal.info=true" 确认)

但是虽然我确定了问题的核心,但我不确定如何处理它。

可能有一个扭曲的设计,我会使用位置更改状态将其变成基于声明的形式,但是当我的滑块也接受来自 [=16= 的值时,我会遇到类似的问题](这将需要在其 onAccepted 回调中以类似的方式更新值)。

JarMan 的提示很好。我试图解决您示例中的双向绑定问题,但没有成功。因此,我向您展示了样式化的标准滑块: 这是我的 SimpleSlider.qml:

import QtQuick 2.15
import QtQuick.Templates 2.15 as T

T.Slider {
    id: slider

    width: 200
    height: 40

    background: Rectangle {
        color: "darkgrey"

        Rectangle {
            width: slider.visualPosition * parent.width
            height: parent.height
            color: "orange"
        }
    }

    Text {
        text: slider.value.toFixed(3)
        anchors.centerIn: slider
    }
}

已编辑 SimpleSlider.qml:

import QtQuick 2.15
import QtQml 2.15

Item {
    id: simple_slider
    property real value: .5
    property real tempValue: value
    property real min_value: 0
    property real max_value: 1
    width: childrenRect.width
    height: childrenRect.height

    function linear(a, b, x) { return (x - a) / (b - a) }
    function mix(a, b, x)    { return a * (1 - x) + b * x }

    FontMetrics { id: fontMetrics }

    Rectangle {
        id: main_box
        width: Math.max(txt_label.width + 10, 50)
        height: fontMetrics.height + 10
        radius: 2
        color: "darkgrey"
    }

    Rectangle {
        id: filled_box
        width: linear(min_value, max_value, tempValue) * main_box.width
        height: main_box.height
        radius: main_box.radius
        color: "orange"
    }

    Text {
        id: txt_label
        text: tempValue.toFixed(3)
        anchors.centerIn: main_box
    }

    MouseArea {
        ///property real xval: simple_slider.value

        id: drag_slider
        anchors.fill: parent
        onPositionChanged: tempValue = get_value_from_pos(mouse.x)
        onReleased: tempValue = Qt.binding(function() { return value })

        function get_value_from_pos(x) {
            var v = Math.min(Math.max(linear(0, main_box.width, x), 0), 1)
            return mix(min_value, max_value, v)
        }
    }

    Binding on value {
        when: drag_slider.pressed
        value: tempValue
        restoreMode: Binding.RestoreBinding

    }
}