QML Canvas绘制一个简单的仪表盘

QML 的 Canvas 提供了一个 2D 画布,支持所有 HTML5 2D 上下文像素操作。使用 QML Canvas 应该避免频繁的更新和动画处理,如果可能的话,最好使用QQuickPaintedItem并通过QPainter在C ++中实现绘图,而不是使用更昂贵且性能可能更低的JavaScript和Context2D方法。

这次我试着画了一个简单的仪表盘,效果和完整代码如下(如果要好看的表盘,还是要配合贴图):

实现代码两个QML文件:

//MyDial.qml
import QtQuick 2.12
import QtQuick.Controls 2.12

//表盘
//目前只实现了简单的,一些细节还没做,如刻度的取值浮点数小数
Item {
    id: control

    property int lineWidth: 3
    property int fontPx: 16
    property color themeColor: "#00C1DE"

    property int padding: 20
    property int radius: (width/2<height)?(width/2-2*padding):(height-2*padding)
    property int half: control.radius+control.padding

    property double minValue: 0
    property double maxValue: 100
    property double currentValue: 0
    property int stepSize: 6
    property double stepValue: (control.maxValue-control.minValue)/(stepSize-1)
    property double stepAngle: Math.PI/(control.stepSize-1)

    onCurrentValueChanged: {
        canvas.requestPaint();
    }

    //背景刻度
    Canvas{
        id: canvas
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter

        width: control.half*2
        //底部也有一个padding
        height: control.half+control.padding

        onPaint: {
            let ctx=getContext("2d");
            ctx.lineWidth=control.lineWidth;
            ctx.font=String(control.fontPx)+"px SimHei bold"
            ctx.fillStyle=control.themeColor;
            ctx.strokeStyle=control.themeColor;
            ctx.lineCap="round";
            ctx.clearRect(0,0,width,height);

            //原点平移
            ctx.save();
            ctx.translate(control.half,control.half)
            ctx.beginPath();
            //radius-linewidth
            //x,y,r,起始角右侧,终止角顺时针旋转
            ctx.arc(0,0,control.radius,Math.PI,2*Math.PI);

            //绘制刻度
            ctx.save();
            ctx.rotate(Math.PI*1.5);
            for(let i=control.minValue;i<control.maxValue+1;i+=control.stepValue){
                ctx.moveTo(0,-control.radius+10);
                ctx.lineTo(0,-control.radius);
                ctx.fillText(String(i),-10,-control.radius+10+control.fontPx)

                ctx.rotate(control.stepAngle);
            }
            ctx.stroke();
            ctx.restore();

            ctx.beginPath();
            //绘制指针
            ctx.arc(0,0,5,0,2*Math.PI);
            ctx.rotate(Math.PI*1.5+control.currentValue*Math.PI/(control.maxValue-control.minValue));
            ctx.moveTo(0,-control.radius+15+control.fontPx);
            ctx.lineTo(0,-5);
            ctx.stroke();
            ctx.restore();
        }
    }

    function setValue(value){
        if(value<control.minValue||value>control.maxValue)
            return;
        control.currentValue=value;
    }
}
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    id: root
    visible: true
    width: 640
    height: 480
    title: qsTr("龚建波 1992")

    Column{
        anchors.centerIn: parent
        spacing: 20

        MyDial{
            id: dial
            width: root.width-40
            height: width/2

            //测试用,查看canvas范围
            Rectangle{
                anchors.fill: parent
                color: "transparent"
                radius: 10
                border.width: 2
                border.color: dial.themeColor
            }
        }
        Text{
            anchors.horizontalCenter: parent.horizontalCenter
            text: "当前值:"+String(dial.currentValue)
            font.pixelSize: 20
            color: dial.themeColor
        }
    }

    //测试用,点击增加值
    MouseArea{
        anchors.fill: parent
        onClicked:{
            //dial.setValue(100);
            if(dial.currentValue<dial.maxValue){
                dial.currentValue+=dial.stepValue;
            }else{
                dial.currentValue=dial.minValue;
            }
        }
    }
}
发布了110 篇原创文章 · 获赞 36 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/gongjianbo1992/article/details/104453526
QML