qml实现 裁剪进度条

发布于:2025-07-04 ⋅ 阅读:(11) ⋅ 点赞:(0)

 我们需要实现一个垂直进度条效果,但使用图片裁剪的方式。具体需求: 1. 图片位置固定,容器对齐其左边和下边,宽度和图片相同。 2. 容器背景透明,调整裁剪容器的高度,使其有高度进度条的感觉(从下往上增长)。 实现思路: - 固定图片的位置(例如,在某个Item内定位)。 - 创建一个裁剪容器,宽度与图片相同,高度由进度值控制(从0到图片高度)。 - 裁剪容器内放置图片,并将图片的底部与裁剪容器的底部对齐(因为进度是从下往上增长,所以图片需要向上移动)。 - 裁剪容器设置`clip: true`,这样图片超出裁剪容器的部分将被隐藏。 具体步骤: 1. 用一个Item作为图片的容器(固定位置)。 2. 在容器内,再创建一个Item作为裁剪容器(宽度与图片相同,高度由进度值控制)。 3. 裁剪容器内放置图片,并设置图片的y坐标为:-(图片高度 - 裁剪容器高度),这样图片的底部就会与裁剪容器的底部对齐。 注意:图片的锚定或位置设置要确保底部对齐。 假设我们有一张高度为200px的图片,进度为50%时,裁剪容器高度为100px,此时图片的y坐标应为-100px(即向上移动100px),这样图片的底部就对齐了裁剪容器的底部,而裁剪容器只显示图片的下半部分(从下往上显示了一半)。 我们将通过一个进度值(0.0到1.0)来控制裁剪容器的高度(0到图片高度)。

import QtQuick 2.7
import QtQuick.Controls 1.4
 import QtQuick.Controls.Styles 1.4
ApplicationWindow {
    id: mainWindow
    width: 800
    height: 600
    visible: true
    title: "图片裁剪进度条 - 修正版"
    color: "#121212"

    // 图片源 - 使用渐变图片模拟进度条
    property string imageSource: "qrc:/image/a.png"

    // 进度值 (0.0 - 1.0)
    property real progress: 0.5

    // 图片属性
    property int imageWidth: 50
    property int imageHeight: 200

    // 主布局
    Item {
        anchors.fill: parent

        // 状态信息 - 显示在顶部
        Text {
            anchors.top: parent.top
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.topMargin: 20
            text: "图片裁剪进度条 - 固定在左下角"
            font.bold: true
            font.pixelSize: 18
            color: "#4CAF50"
        }

        // ==============================================
        // 图片容器 - 固定在左下角 (核心修正部分)
        // ==============================================
        Item {
            id: imageContainer
            width: imageWidth  // 宽度与图片相同
            height: imageHeight // 高度与图片相同
            anchors.left: parent.left // 对齐父元素左边
            anchors.bottom: parent.bottom // 对齐父元素底边
            anchors.margins: 20 // 边距

            // 背景网格 - 帮助可视化
            Rectangle {
                anchors.fill: parent
                color: "transparent"
                border.color: "#333"
                border.width: 1

                // 网格线
                Canvas {
                    anchors.fill: parent
                    onPaint: {
                        var ctx = getContext("2d")
                        ctx.clearRect(0, 0, width, height)
                        ctx.strokeStyle = "#333"
                        ctx.lineWidth = 1

                        // 绘制水平线
                        for (var y = 0; y <= height; y += 10) {
                            ctx.beginPath()
                            ctx.moveTo(0, y)
                            ctx.lineTo(width, y)
                            ctx.stroke()
                        }

                        // 绘制垂直线
                        for (var x = 0; x <= width; x += 10) {
                            ctx.beginPath()
                            ctx.moveTo(x, 0)
                            ctx.lineTo(x, height)
                            ctx.stroke()
                        }
                    }
                }
            }

            // ==============================================
            // 核心修正:裁剪容器实现进度条效果
            // ==============================================
            Item {
                id: cropContainer
                width: parent.width // 宽度与图片相同
                height: imageHeight * progress // 高度由进度值控制
                anchors.left: parent.left // 对齐左边
                anchors.bottom: parent.bottom // 对齐底边
                clip: true // 关键:启用裁剪

                // 图片元素
                Image {
                    id: progressImage
                    source: imageSource
                    sourceSize.width: imageWidth // 原始宽度
                    sourceSize.height: imageHeight // 原始高度
                    asynchronous: true // 异步加载

                    // 关键修正:图片底部对齐容器底部
                    anchors.bottom: parent.bottom
                }
            }

            // 当前进度文本
            Text {
                anchors.top: parent.top // 锚定到容器顶部
                anchors.topMargin: -30 // 在图片上方显示
                anchors.horizontalCenter: parent.horizontalCenter // 水平居中
                text: Math.round(progress * 100) + "%" // 显示百分比
                font.pixelSize: 20 // 字体大小
                font.bold: true // 粗体
                color: "white" // 文本颜色
                style: Text.Outline // 文本轮廓
                styleColor: "#000" // 轮廓颜色
            }

            // 边框装饰
            Rectangle {
                anchors.fill: parent // 与图片容器相同大小
                color: "transparent" // 透明背景
                border.color: "#4CAF50" // 边框颜色
                border.width: 2 // 边框宽度
                radius: 4 // 圆角半径
            }
        }

        // ==============================================
        // 控制面板 - 在右侧显示
        // ==============================================
        Column {
            id: controlPanel
            width: 300
            anchors.left: imageContainer.right // 在图片容器右侧
            anchors.bottom: parent.bottom // 对齐底部
            anchors.margins: 30 // 边距
            spacing: 20 // 子元素间距

            // 标题
            Text {
                text: "进度控制" // 标题文本
                font.bold: true // 粗体
                font.pixelSize: 24 // 字体大小
                color: "#4CAF50" // 标题颜色
            }

            // 进度滑块
            Column {
                width: parent.width
                spacing: 5

                // 滑块标签
                Text {
                    text: "进度值: " + Math.round(progress * 100) + "%" // 显示当前进度
                    font.pixelSize: 18 // 字体大小
                    color: "white" // 文本颜色
                }

                // 进度滑块
                Slider {
                    id: progressSlider
                    width: parent.width // 宽度填满
                    minimumValue: 0.0 // 最小值
                    maximumValue: 1.0 // 最大值
                    value: progress // 当前值
                    onValueChanged: progress = value // 值改变时更新进度

                    // 自定义滑块样式
                    style: SliderStyle {
                        groove: Rectangle {
                            implicitHeight: 8 // 滑槽高度
                            radius: 4 // 圆角
                            color: "#333" // 背景色

                            // 进度填充
                            Rectangle {
                                height: parent.height
                                width: control.value * parent.width // 根据进度填充
                                radius: 4 // 圆角
                                gradient: Gradient {
                                    GradientStop { position: 0.0; color: "#4CAF50" } // 绿色
                                    GradientStop { position: 0.5; color: "#2196F3" } // 蓝色
                                    GradientStop { position: 1.0; color: "#FF9800" } // 橙色
                                }
                            }
                        }

                        // 滑块手柄
                        handle: Rectangle {
                            width: 24 // 宽度
                            height: 24 // 高度
                            radius: 12 // 圆形
                            color: control.pressed ? "white" : "#f0f0f0" // 按下时白色,否则浅灰色
                            border.color: "#4CAF50" // 边框颜色
                            border.width: 2 // 边框宽度

                            // 中心点
                            Rectangle {
                                anchors.centerIn: parent
                                width: 8
                                height: 8
                                radius: 4
                                color: "#4CAF50"
                            }
                        }
                    }
                }
            }

            // 预设按钮
            Grid {
                columns: 3 // 3列布局
                spacing: 10 // 按钮间距
                width: parent.width

                // 预设按钮文本
                property var presets: [
                    {text: "0%", value: 0.0},
                    {text: "25%", value: 0.25},
                    {text: "50%", value: 0.5},
                    {text: "75%", value: 0.75},
                    {text: "100%", value: 1.0},
                    {text: "随机", value: -1}
                ]

                // 生成预设按钮
                Repeater {
                    model: controlPanel.presets

                    Button {
                        width: (controlPanel.width - 20) / 3 // 平均宽度
                        text: modelData.text // 按钮文本

                        // 点击事件
                        onClicked: {
                            if (modelData.value === -1) {
                                // 随机值
                                progress = Math.random().toFixed(2)
                            } else {
                                // 预设值
                                progress = modelData.value
                            }
                        }

                        // 按钮样式
                        style: ButtonStyle {
                            background: Rectangle {
                                radius: 5 // 圆角
                                color: control.pressed ? "#4CAF50" : "#333" // 按下时绿色,否则深灰
                                border.color: "#4CAF50" // 边框颜色
                                border.width: 1 // 边框宽度
                            }
                            label: Text {
                                text: control.text // 按钮文本
                                color: "white" // 文本颜色
                                horizontalAlignment: Text.AlignHCenter // 水平居中
                                verticalAlignment: Text.AlignVCenter // 垂直居中
                            }
                        }
                    }
                }
            }

            // 动画控制
            Row {
                spacing: 15

                // 开始动画按钮
                Button {
                    text: "开始动画"
                    onClicked: progressAnimation.start()

                    style: ButtonStyle {
                        background: Rectangle {
                            radius: 5
                            color: control.pressed ? "#4CAF50" : "#333"
                            border.color: "#4CAF50"
                            border.width: 1
                        }
                        label: Text {
                            text: control.text
                            color: "white"
                        }
                    }
                }

                // 暂停动画按钮
                Button {
                    text: "暂停动画"
                    onClicked: progressAnimation.pause()

                    style: ButtonStyle {
                        background: Rectangle {
                            radius: 5
                            color: control.pressed ? "#FF9800" : "#333"
                            border.color: "#FF9800"
                            border.width: 1
                        }
                        label: Text {
                            text: control.text
                            color: "white"
                        }
                    }
                }

                // 停止动画按钮
                Button {
                    text: "停止动画"
                    onClicked: progressAnimation.stop()

                    style: ButtonStyle {
                        background: Rectangle {
                            radius: 5
                            color: control.pressed ? "#F44336" : "#333"
                            border.color: "#F44336"
                            border.width: 1
                        }
                        label: Text {
                            text: control.text
                            color: "white"
                        }
                    }
                }
            }
        }
    }

    // ==============================================
    // 动画效果 - 自动改变进度值
    // ==============================================
    NumberAnimation {
        id: progressAnimation
        target: mainWindow
        property: "progress"
        from: 0.0
        to: 1.0
        duration: 3000 // 3秒完成
        easing.type: Easing.InOutQuad // 平滑的缓动效果
        loops: Animation.Infinite // 无限循环
        running: false // 默认不运行
    }
}