QML RangeSlider 组件:范围选择与双滑块样式

RangeSlider 和 Slider 很像,区别在于它有两个手柄:一个控制范围起点,一个控制范围终点。适合用来选区间,比如价格区间、时间范围、筛选条件等。这篇用两个例子演示基础用法和自定义样式。

  • RangeSlider 基础 --- 认识 first / second 两个滑块
  • RangeSlider 样式 --- 自定义轨道、选中区间和两个手柄

Demo 1:RangeSlider 基础

先放一个最简单的 RangeSlider,显示当前选中的范围。

演示代码

qml 复制代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

FadeInAnimation {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        Text {
            text: "当前范围: " + Math.round(rangeSlider.first.value) + " - " + Math.round(rangeSlider.second.value)
            font.pixelSize: 16
            Layout.alignment: Qt.AlignHCenter
        }

        RangeSlider {
            id: rangeSlider
            from: 0
            to: 100
            first.value: 20
            second.value: 80
            stepSize: 1
            Layout.fillWidth: true
        }

        Text {
            text: "拖动滑块来选择范围"
            font.pixelSize: 14
            Layout.alignment: Qt.AlignHCenter
        }

        Item { Layout.fillHeight: true }
    }
}

关键逻辑解析

RangeSlider 的核心属性:

  • from / to:整体取值范围。
  • first.value:左滑块(起点)的值。
  • second.value:右滑块(终点)的值。
  • stepSize:步长,设为 1 表示可以精确到整数。

取值显示时建议用 Math.round() 包一下,避免浮点精度导致界面出现 19.999999 这种数字。

Demo 2:RangeSlider 样式

默认样式比较素,实际项目中往往需要自己画轨道和选中区间。这个例子把轨道改成浅灰,选中区间改成绿色,两个手柄也做了统一样式。

演示代码

qml 复制代码
import QtQuick
import QtQuick.Controls.Basic
import QtQuick.Layouts

FadeInAnimation {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        Text {
            text: "当前范围: " + Math.round(customSlider.first.value) + " - " + Math.round(customSlider.second.value)
            font.pixelSize: 16
            Layout.alignment: Qt.AlignHCenter
        }

        RangeSlider {
            id: customSlider
            from: 0
            to: 100
            first.value: 20
            second.value: 80
            stepSize: 1
            Layout.fillWidth: true

            background: Rectangle {
                x: customSlider.leftPadding
                y: customSlider.topPadding + customSlider.availableHeight / 2 - height / 2
                width: customSlider.availableWidth
                height: 4
                radius: 2
                color: "#e0e0e0"

                Rectangle {
                    x: customSlider.first.visualPosition * parent.width
                    width: customSlider.second.visualPosition * parent.width - x
                    height: parent.height
                    color: "#4CAF50"
                    radius: 2
                }
            }

            first.handle: Rectangle {
                x: customSlider.leftPadding + customSlider.first.visualPosition
                   * (customSlider.availableWidth - width)
                y: customSlider.topPadding + customSlider.availableHeight / 2 - height / 2
                width: 20
                height: 20
                radius: 10
                color: customSlider.first.pressed ? "#e0e0e0" : "#ffffff"
                border.color: "#bdbebf"
                border.width: 1
            }

            second.handle: Rectangle {
                x: customSlider.leftPadding + customSlider.second.visualPosition
                   * (customSlider.availableWidth - width)
                y: customSlider.topPadding + customSlider.availableHeight / 2 - height / 2
                width: 20
                height: 20
                radius: 10
                color: customSlider.second.pressed ? "#e0e0e0" : "#ffffff"
                border.color: "#bdbebf"
                border.width: 1
            }
        }

        Item { Layout.fillHeight: true }
    }
}

关键逻辑解析

和 Slider 一样,RangeSlider 也开放 background 和 handle。但它有两个手柄,所以对应写法是 first.handle 和 second.handle。

选中区间的计算是重点:

qml 复制代码
x: customSlider.first.visualPosition * parent.width
width: customSlider.second.visualPosition * parent.width - x
  • 起点是 first.visualPosition 对应的位置。
  • 宽度是 second.visualPosition 的位置减去起点位置。

这样绿色区间就会跟着两个手柄实时变化。

两个手柄的样式可以分别定制。这个例子里样式完全一样,只是按下状态分别对应 customSlider.first.pressed 和 customSlider.second.pressed。

运行验证

  1. 用 Qt Creator 打开 qml_slider/CMakeLists.txt;
  2. 按 Ctrl+R 运行;
  3. 左侧导航切到 RangeSlider 相关 demo,拖动两个手柄看范围变化。

扩展复用方向

  • 在选中区间上方显示当前范围值,拖动时实时更新。
  • 把选中区间改成渐变,或者根据数值大小变色(比如温度范围用蓝到红)。
  • 限制两个手柄最小间距,防止它们重叠,可以在 onValueChanged 里做边界判断。

已验证环境:

相关推荐
zhanghaha131411 小时前
Qt 类本质就是 C++ 的类,只是 Qt 框架扩展了一套【QObject 对象模型】
qt
Cx330❀19 小时前
深入浅出 Qt 绘图机制:从 QPainter 到四大图像类解析
开发语言·qt·ui·性能优化·图形渲染
Littlehero_12120 小时前
QT自定义控件之水泥厂组态(源码开源)
开发语言·qt
代钦塔拉1 天前
【C++/Qt 进阶】设计模式系列(6):桥接模式——把“两个独立变化的维度“拆开
c++·qt·设计模式
156082072191 天前
银河麒麟 Qt 可执行文件打包说明
开发语言·驱动开发·qt
Quz1 天前
QML GridView 布局:网格排布与排列方向
qt
Quz1 天前
QML GridView 动态:增删过渡与滚动定位
qt
沫璃染墨2 天前
《Qt从零入门系列(十四):QThread多线程详解——从线程创建到客户端阻塞处理》
开发语言·c++·笔记·qt·ui·交互·线程
代钦塔拉2 天前
【C++/Qt 进阶】设计模式系列(5):适配器模式——给“不兼容的接口“贴一层翻译膜
c++·qt·设计模式
把我格子衫拿来2 天前
VTK 9.5 与 Qt 6 联合开发:从嵌入三维窗口到可维护的桌面架构
c++·python·qt·vtk·三维可视化