如何将 QML Slider 的 mouseArea 限制为仅手柄?

How to restrict the mouseArea of a QML Slider to the handle only?

我想使用 QtQuick.Controls 实现 Slider,其中只有 handle 是可点击的并且可以用来拖动 handle。如果您单击 groove,则不会发生任何事情,handle 应该保留在原处。如何将 SlidermouseArea 限制为仅 handle

在下面的例子中 Slider 是整体可点击的 Slider widthheight:

import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3

Window {
    id: mainItem
    width: 800
    height: 400
    visible: true

    Slider{
        id: autoSlider
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        maximumValue: 1.0
        value: 0
        updateValueWhileDragging : false

        style: SliderStyle {
            groove: Rectangle {
                implicitWidth: 350
                implicitHeight: 8
                color: "gray"
                radius: 8
            }
            handle: Rectangle {
                anchors.centerIn: parent
                color: control.pressed ? "white" : "lightgray"
                border.color: "gray"
                border.width: 2
                implicitWidth: 45
                implicitHeight: 45
                radius: 12
            }
        }
    }
}

我考虑过更改“..\qml\QtQuick\Controls”文件夹中的 Slider.qml 模板,但我真的不知道该怎么做。

我所有的搜索努力都一无所获。任何帮助将不胜感激。

我可能是错的,但我认为这违背了所有桌面平台上滑块的行为,出于可用性原因需要考虑这一点。除此之外,让我们试试:

diff --git a/src/controls/Slider.qml b/src/controls/Slider.qml
index 20d1102..da6f051 100644
--- a/src/controls/Slider.qml
+++ b/src/controls/Slider.qml
@@ -258,7 +258,7 @@ Control {
         }

         onPositionChanged: {
-            if (pressed)
+            if (pressed && handleHovered)
                 updateHandlePosition(mouse, preventStealing)

我们不希望手柄位置在开始时未悬停时发生变化,因为这意味着鼠标在手柄之外。

             var point = mouseArea.mapToItem(fakeHandle, mouse.x, mouse.y)
@@ -272,18 +272,21 @@ Control {
             if (handleHovered) {
                 var point = mouseArea.mapToItem(fakeHandle, mouse.x, mouse.y)
                 clickOffset = __horizontal ? fakeHandle.width/2 - point.x : fakeHandle.height/2 - point.y
+
+                pressX = mouse.x
+                pressY = mouse.y
+                updateHandlePosition(mouse, !Settings.hasTouchScreen)
             }
-            pressX = mouse.x
-            pressY = mouse.y
-            updateHandlePosition(mouse, !Settings.hasTouchScreen)
         }

接下来,在onPressed句柄的if (handleHovered)条件内移动句柄位置更新。

         onReleased: {
-            updateHandlePosition(mouse, Settings.hasTouchScreen)
-            // If we don't update while dragging, this is the only
-            // moment that the range is updated.
-            if (!slider.updateValueWhileDragging)
-                range.position = __horizontal ? fakeHandle.x : fakeHandle.y;
+            if (handleHovered) {
+                updateHandlePosition(mouse, Settings.hasTouchScreen)
+                // If we don't update while dragging, this is the only
+                // moment that the range is updated.
+                if (!slider.updateValueWhileDragging)
+                    range.position = __horizontal ? fakeHandle.x : fakeHandle.y;
+            }
             clickOffset = 0
             preventStealing = false
         }

最后,对 onReleased 处理程序进行类似的更改。

这会让你得到你想要的,尽管在边缘有点粗糙——字面意思。我认为交互不是 100%,但请尝试一下。通过更多的试验,您应该能够让它完美地工作。

另一个 hacky 选项是修改 Slider.qml 以在手柄的任一侧具有 MouseArea 滑块本身之上。这些中的每一个都将填充手柄两侧的可用 space,有效地窃取凹槽会为这些区域接收的所有鼠标事件。