QML Canvas 绘制进度条(环形和波浪水球)

效果展示:

代码链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/TestQml_20220210_ProgressBar

环形进度条代码:

import QtQuick 2.12
import QtQuick.Controls 2.12

//canvas绘制环形进度条
//龚建波 2022-02-10
Item {
    id: control

    implicitWidth: 160
    implicitHeight: 160

    property real from: 0 //最小值
    property real to: 100 //最大值
    property real value: 0 //当前值
    property real percent: (value-from)/(to-from) //百分比[0,1]
    //
    property int canvasMargin: 3
    property int canvasWidth: width < height ? width : height
    property int canvasRadius: canvasWidth / 2 - canvasMargin
    property int lineWidth: 16
    property int lineBorder: 6
    property color bgColor: "#0486FF"
    property color valueColor: "#0486FF"
    //
    property real _valueAngle: Math.PI/2+Math.PI*2*percent
    on_ValueAngleChanged: canvas.requestPaint()
    //
    property real speed: 0.1
    property real offset: 0

    Canvas {
        id: canvas
        width: canvasWidth
        height: canvasWidth
        onPaint: {
            var ctx = getContext("2d");
            ctx.clearRect(0, 0, canvasWidth, canvasWidth);
            ctx.lineCap = "round";

            drawBg(ctx);
            drawValue(ctx);
        }

        //context.arc(x,y,r,sAngle,eAngle,counterclockwise);
        //x:圆的中心的x坐标。
        //y:圆的中心的y坐标。
        //r:圆的半径。
        //sAngle:起始角,以弧度计。(弧的圆形的三点钟位置是0度)。
        //eAngle:结束角,以弧度计。
        //counterclockwise:可选参数。False=顺时针,true=逆时针。
        function drawBg(ctx)
        {
            var color_offset = offset>Math.PI?(1-(offset-Math.PI)/Math.PI):(offset/Math.PI);

            ctx.beginPath();
            ctx.arc(canvasWidth/2, canvasWidth/2, canvasRadius-lineWidth/2-lineBorder, 0, 2*Math.PI);
            ctx.lineWidth = lineWidth+lineBorder*2;
            ctx.strokeStyle = Qt.lighter(bgColor, 1.7+0.2*color_offset);
            ctx.stroke();

            ctx.beginPath();
            ctx.arc(canvasWidth/2, canvasWidth/2, canvasRadius-lineWidth/2-lineBorder, 0, 2*Math.PI);
            ctx.lineWidth = lineWidth;
            ctx.strokeStyle = Qt.lighter(bgColor, 1.6+0.2*color_offset);
            ctx.stroke();
        }

        function drawValue(ctx)
        {
            //ctx.save();
            //带阴影效果时cpu占用明显增高
            //ctx.shadowColor= valueColor;
            //ctx.shadowBlur= lineWidth/4;
            ctx.beginPath();
            ctx.arc(canvasWidth/2, canvasWidth/2, canvasRadius-lineWidth/2-lineBorder, Math.PI/2, _valueAngle, false);
            ctx.lineWidth = lineWidth;
            ctx.strokeStyle = valueColor;
            ctx.stroke();
            //ctx.restore();
        }

        Text {
            id: txt
            anchors.centerIn: parent
            font.family: "Microsoft YaHei"
            font.pixelSize: (canvasWidth-lineWidth)/6;
            font.bold: true
            color: valueColor
            text: qsTr("%1 %").arg(control.percent.toFixed(2)*100);
        }
    }

    //用定时器刷新
    Timer {
        running: visible
        repeat: true
        interval: 35
        onTriggered:{
            //波浪移动
            offset += speed;
            offset %= Math.PI*2;
            canvas.requestPaint();
        }
    }
    /*NumberAnimation {
        target: control
        running: visible
        loops: -1
        property: "offset"
        from: 0
        duration: 2000
        to: Math.PI*2
    }
    onOffsetChanged: canvas.requestPaint();*/
}

波浪进度球代码:

import QtQuick 2.12
import QtQml 2.12
import QtQuick.Controls 2.12

//canvas绘制波浪进度球
//龚建波 2022-02-10
Item {
    id: control

    implicitHeight: 160
    implicitWidth: 160

    property real from: 0 //最小值
    property real to: 100 //最大值
    property real value: 0 //当前值
    property real percent: (value-from)/(to-from) //百分比[0,1]
    //
    property int canvasMargin: 3
    property int canvasWidth: width < height ? width : height
    //
    property int fontPx: 34
    property string fontFamily: "Arial"
    property color waveColor: "#0486FF"
    property int waveBorder: 6
    property int waveRadius: canvasWidth / 2 - canvasMargin - waveBorder
    //
    property real waveWidth: 0.05   //波浪宽度,数越小越宽
    property real waveHeight: 5     //波浪高度,数越大越高
    property real speed: 0.1        //波浪速度,数越大速度越快
    property real offset: 0         //波浪x偏移量,用于动画

    Canvas {
        id: canvas
        width: canvasWidth
        height: canvasWidth
        onPaint: {
            var ctx = getContext("2d");
            ctx.clearRect(0, 0, canvasWidth, canvasWidth);
            ctx.lineCap = "round";

            ctx.save();
            ctx.beginPath();
            ctx.arc(canvasWidth/2, canvasWidth/2, waveRadius+waveBorder-canvasMargin, 0, 2*Math.PI);
            ctx.lineWidth = waveBorder;
            var color_offset = offset>Math.PI?(1-(offset-Math.PI)/Math.PI):(offset/Math.PI);
            ctx.strokeStyle = Qt.lighter(waveColor, 1.5+0.3*color_offset);
            ctx.stroke();

            var progress_text = qsTr("%1 %").arg(parseInt(percent*100));
            ctx.font = fontPx + "px '" + fontFamily + "'";
            ctx.textAlign = "center";
            ctx.fillStyle = waveColor;
            //canvas字体高度和居中还有点问题
            ctx.fillText(progress_text, canvasWidth/2, canvasWidth/2+fontPx/2-5);

            ctx.save();
            ctx.beginPath();
            ctx.lineWidth = 0;
            ctx.arc(canvasWidth/2, canvasWidth/2, waveRadius, 0, 2*Math.PI);
            ctx.clip();
            drawWave(ctx, waveColor, 0, 0, false);
            ctx.clip();
            ctx.font = fontPx + "px '" + fontFamily + "'";
            ctx.textAlign = "center";
            ctx.fillStyle = "white";
            ctx.fillText(progress_text, canvasWidth/2, canvasWidth/2+fontPx/2-5);
            ctx.restore();
        }

        //画笔,颜色,x偏移,y偏移,角度值取反
        function drawWave(ctx, w_color, x_offset, y_offset, reverse)
        {
            ctx.beginPath();
            var x_base = canvasWidth/2-waveRadius;
            var y_base = canvasWidth/2+waveRadius-waveRadius*2*percent;
            //正弦波浪,横坐标步进为5px,右侧多加5是为了填补不足步进的部分
            for(var x_value = 0; x_value <= waveRadius*2 + 5; x_value += 5){
                var y_value = waveHeight*Math.sin((reverse?-1:1)*(x_value)*waveWidth+offset+x_offset)+y_offset;
                ctx.lineTo(x_base+x_value, y_base+y_value);
            }
            //左右底部围城实心
            ctx.lineTo(canvasWidth/2+waveRadius, canvasWidth/2+waveRadius);
            ctx.lineTo(canvasWidth/2-waveRadius, canvasWidth/2+waveRadius);
            ctx.closePath();
            ctx.fillStyle = w_color;
            ctx.fill();
        }
    }

    //用定时器刷新
    Timer {
        running: visible
        repeat: true
        interval: 35
        onTriggered:{
            //波浪移动
            offset += speed;
            offset %= Math.PI*2;
            canvas.requestPaint();
        }
    }
    /*NumberAnimation {
        target: control
        running: visible
        loops: -1
        property: "offset"
        from: 0
        duration: 2000
        to: Math.PI*2
    }
    onOffsetChanged: canvas.requestPaint();*/
}

  • 19
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值