开源QML控件:进度条滑动控件(含源码下载链接)

在许多应用程序中,进度条控件用于显示任务的完成进度或实时更新的数据。通常,进度条控件带有滑块,用户可以通过拖动滑块来手动调整进度。

为什么选择自定义滑动条?

在许多应用程序中,我们可以使用系统或框架提供的原生控件来构建进度条,但原生控件在某些情况下可能并不完美。例如:

  1. 滑块无法精准控制:原生滑动条控件通常不能很好地应对步长控制问题,用户拖动滑块时可能会遇到进度更新不精确的情况,或者滑块位置无法精准控制。

  2. 选中操作复杂:某些原生控件可能存在滑块选中操作的问题,尤其是在不同平台或分辨率下,滑块的可选中状态可能不一致,导致用户体验不流畅。

  3. 进度条样式限制:使用原生控件时,进度条的样式可能受到框架限制,无法完全符合项目的设计需求。若需要多个不同风格的进度条,原生控件的定制能力可能不足。

因此,封装自定义滑动条控件,能够灵活地控制进度条和滑块的表现,避免原生控件在一些特定场景下的局限性,还可以根据项目需求方便地切换多种不同风格的进度条。

进度条控件的基本功能

此控件具有以下几个基本功能:

  • 进度条拖动:用户通过滑动滑块来改变进度,进度条和滑块的宽度都会实时更新。
  • 步长控制 :设置一个步长(stepSize),确保进度在每次更新时只按预定的步幅变化,避免细微的变化影响用户体验。
  • 进度值更新信号 :每次进度更新时,控件会触发 currentValueChanged 信号,通知外部获取当前的进度值。
  • 滑块位置限制:滑块不会超出进度条的左右边界。
  • 支持外部设置进度值 :控件提供了一个 setProgressValue(value) 方法,让外部代码能够直接设置进度条的值。

源码下载链接

qml 复制代码
通过网盘分享的文件:Slider.7z
链接: https://pan.baidu.com/s/1qpWrfX7P8pz1e3a26mczUg?pwd=jkcf 提取码: jkcf

核心代码讲解

下面是优化后的 QML 代码,我们通过该代码实现了一个进度条滑动控件,支持步长和滑动拖动控制。

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

Item {
    id: progressBar
    width: 140
    height: 20

    // 信号:每次进度更新时触发,返回当前进度
    signal currentValueChanged(real progress)

    // 步长单位
    property real stepSize: 0.05  // 假设步长为 0.05

    property real currValue : 0 // 当前进度值

    property string sliderImageSource: "file:btn_nan@2x.png"  // 使用你的图片路径

    // 最小值和最大值
    property real minValue: 0    // 最小值
    property real maxValue: 10    // 最大值

    property real handleSize: 15   // 滑块大小

    // 标志位,防止死循环
    property bool isDragging: false

    // 背景进度条
    Rectangle {
        id: backgroundBar
        width: progressBar.width
        height: 10
        color: "#878585"  // 进度条背景色
        anchors.verticalCenter: parent.verticalCenter
        radius: 5
    }

    // 当前进度条
    Rectangle {
        id: currentProgress
        width: 0  // 初始宽度为 0
        height: 10
        color: "#a60078ff"  // 当前进度条颜色
        anchors.verticalCenter: parent.verticalCenter
        radius: 5
    }

    // 设置滑块图像作为 handle
    Item {
        width: handleSize
        height: handleSize
        anchors.verticalCenter: parent.verticalCenter

        Image {
            id: sliderImage
            width: parent.width
            height: parent.height
            source: sliderImageSource
            anchors.left: parent.left
        }

        MouseArea {
            id: handleArea
            anchors.fill: parent
            drag.target: parent

            // 按下后开始监控鼠标的移动
            onPressed: {
                isDragging = true
                updateProgress()
                progressBar.dragging()
            }

            // 鼠标移动时更新滑块位置并更新进度条
            onPositionChanged: {
                // 限制 handle 的位置,使其不超出进度条的范围
                if (parent.x < 0) {
                    parent.x = 0;  // 保证滑块不会超出左边界
                } else if (parent.x > progressBar.width - parent.width) {
                    parent.x = progressBar.width - parent.width;  // 保证滑块不会超出右边界
                }

                // 更新进度条的当前进度
                updateProgress()
            }

            // 松开鼠标时更新进度
            onReleased: {
                isDragging = false;
                updateProgress()
                progressBar.dragging()
            }

            // 更新进度条的当前进度
            function updateProgress() {
                // 计算滑块的中心位置
                let sliderCenter = parent.x + parent.width / 2;

                // 计算当前进度条宽度:进度条的右边界以滑块的中心为分界
                let progress = sliderCenter / progressBar.width;

                // 将进度限制在 minValue 和 maxValue 之间
                progress = Math.min(Math.max(progress, 0), 1);  // 限制在 [0, 1] 范围内

                // 根据进度计算当前值,并根据 minValue 和 maxValue 映射到相应范围
                let currentValue = minValue + (progress * (maxValue - minValue));

                // 检查进度是否超过步长单位
                if (Math.abs(currentValue - previousValue) >= stepSize) {
                    // 四舍五入 currentValue 到与 stepSize 相同的小数位数
                    let decimalPlaces = getDecimalPlaces(stepSize);
                    let roundedValue = roundToDecimal(currentValue, decimalPlaces);

                    // 更新进度条宽度
                    currentProgress.width = progress * progressBar.width;  // 更新当前进度条宽度

                    // 发射当前值更新信号
                    currentValueChanged(roundedValue);

                    currValue = roundedValue;

                    // 更新上次的值
                    previousValue = roundedValue;

                    // 打印当前值
                    console.log("当前值:" + roundedValue);
                }
            }

            // 上次进度值,用于比较是否超过步长
            property real previousValue: minValue  // 默认时保持与步长一样的长度

            // 获取 stepSize 的小数位数
            function getDecimalPlaces(value) {
                let stringValue = value.toString();
                if (stringValue.indexOf('.') === -1) return 0;
                return stringValue.split('.')[1].length;
            }

            // 四舍五入到指定的小数位
            function roundToDecimal(value, decimalPlaces) {
                let multiplier = Math.pow(10, decimalPlaces);
                return Math.round(value * multiplier) / multiplier;
            }
        }
    }

    // 新增接口:设置进度值
    function setProgressValue(value) {
        // 确保 value 在 minValue 和 maxValue 之间
        value = Math.min(Math.max(value, minValue), maxValue);

        // 根据传入的进度值更新进度
        let progress = (value - minValue) / (maxValue - minValue);

        // 计算滑块的新位置
        let newPosition = progress * progressBar.width;

        // 更新滑块位置
        sliderImage.parent.x = newPosition - sliderImage.width / 2;

        // 更新进度条宽度
        currentProgress.width = newPosition;

        // 发射进度更新信号
        currentValueChanged(value);

        // 更新当前值
        currValue = value;
    }
}

优化说明

  • 滑块位置限制 :通过检查滑块的 x 坐标,确保滑块不会超出进度条的左右边界,避免出现不可选择的滑块位置。
  • 步长控制 :通过 stepSize 属性设置步长,确保进度变化不会太细微,提供更精确的控制。
  • 拖动过程平滑:拖动过程中通过实时更新滑块位置来确保用户体验流畅。
  • 进度更新信号 :每次进度更新时,都会触发 currentValueChanged 信号,方便外部代码进行监听和处理。

使用实例

qml 复制代码
import QtQuick 2.15
import QtQuick.Controls 2.15
import "path/to/your/custom/progressbar.qml" as ProgressBar

ApplicationWindow {
    visible: true
    width: 600
    height: 400

    MySlider{
        id: myProgressBar
        width: 300
        height: 40
        minValue: 0
        maxValue: 100
        stepSize: 0.1
        scale: 2
        anchors.centerIn: parent
        onCurrentValueChanged: {
            console.log("进度更新为:" + progress);
        }
    }
}

相关推荐
一只大侠的侠4 小时前
Flutter开源鸿蒙跨平台训练营 Day 10特惠推荐数据的获取与渲染
flutter·开源·harmonyos
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
猫头虎7 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端