开源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:[email protected]"  // 使用你的图片路径

    // 最小值和最大值
    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);
        }
    }
}

相关推荐
萌萌哒草头将军12 分钟前
🚀🚀🚀 Openapi:全栈开发神器,0代码写后端!
前端·javascript·next.js
萌萌哒草头将军18 分钟前
🚀🚀🚀 Prisma 爱之初体验:一款非常棒的 ORM 工具库
前端·javascript·orm
拉不动的猪41 分钟前
SDK与API简单对比
前端·javascript·面试
runnerdancer43 分钟前
微信小程序蓝牙通信开发之分包传输通信协议开发
前端
山海上的风1 小时前
Vue里面elementUi-aside 和el-main不垂直排列
前端·vue.js·elementui
星火撩猿1 小时前
ubantu中下载编译安装qt5.15.3
开发语言·qt
电商api接口开发1 小时前
ASP.NET MVC 入门指南二
前端·c#·html·mvc
亭台烟雨中1 小时前
【前端记事】关于electron的入门使用
前端·javascript·electron