qml绘制竖直刻度尺(加动态效果)

有一个需求要绘制表示深度刻度尺,联想到qml中的Slider有可以拖动的游标,再结合自定义的刻度,是不是可以实现呢?
链接: 参考博客

下面 附上实现代码:

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

//参考:https://blog.csdn.net/alongsxmx/article/details/97010914

Window {
    width: 640
    height: 800
    // id:root
    visible: true
    title: qsTr("竖直刻度显示")

    property double wValue: 0
    property int rulerWidth:30
    property int ticks: 0


    Slider{
        id:control
        property int currentY: 0
        from:34
        to:0
        x:120
        y:25
        value:wValue//50

        orientation:Qt.Vertical
        snapMode: Slider.SnapOnRelease
        stepSize: 0.1
        // tickmarksEnabled:true

        onValueChanged: {
            console.log("value:" + value)
            //console.log("va:" + control.visualPosition)
            //console.log("imageY:" + control.bottomPadding + control.visualPosition*(control.availableHeight - height))
        }

        //底色
        background: Rectangle{
            id:rect
            x:control.leftPadding + control.availableWidth / 2 - width / 2
            y:control.bottomPadding
            //parent.currentY= y
            //implicitWidth: 4
            implicitHeight: 800//800 +rulerWidth
            //width: implicitWidth
            //height: control.availableHeight
            //radius: 2

            //color: "#bdbebf"
            color: "#FFFFFF"//跟背景色一样的话可以使得主干条“看不见”

            //绿色滑动条
            // Rectangle{
            //     width:parent.width
            //     height: control.visualPosition*parent.height
            //     color: "#21be2b"
            //     radius: 2
            //     Component.onCompleted: {
            //         // console.log("")
            //     }
            // }

        }

        //圆形句柄
        // handle:Rectangle{
        //     id:handleRect
        //     x:control.leftPadding + control.availableWidth / 2 - width / 2
        //     y:control.bottomPadding + control.visualPosition*(control.availableHeight - height)
        //     implicitWidth: 26
        //     implicitHeight: 26
        //     radius: 13
        //     color: control.pressed ? "#f0f0f0" : "#FFFFFF"
        //     border.color: "#ad3e8f"
        //     Text {
        //         id: text
        //         anchors.centerIn: parent//在父控件中居中
        //         text: qsTr(String(control.value))
        //     }
        // }

        handle: Image{
            // width: 48
            // height: 48
            width: 40
            height: 40
            id:imageTri
            source: "qrc:/image/triangle.png"
            x:control.leftPadding + control.availableWidth / 2 - width / 2
            y:control.bottomPadding + control.visualPosition*(control.availableHeight - height)
            //implicitWidth: 26
            //implicitHeight: 26
        }

        Text {
            id: name
            font.bold: true
            font.pointSize:16
            height: 24
            x:control.leftPadding + control.availableWidth/2 - width / 2 - 36
            y:control.bottomPadding + control.visualPosition*(control.availableHeight - height)
            //anchors.centerIn: imageTri.verticalCenter//在父控件中居中
            text: qsTr(String(control.value.toFixed(1) / 1.0) /*+ "m"*/)
        }
    }

    Button{
        id:btn1
        text:"-"
        x:320
        y:200

        onClicked:{
            if(wValue > -100){
                ticks = 1.0 / 0.1
                wValue -= 1.0
                    animatesub.start()
                    console.log("jian:",control.visualPosition + " " + control.availableHeight)
            }
            else
                wValue = -100
        }
    }

    Button{
        id:btn2
        text:"+"
        x:450
        y:200

        onClicked:{
            if(wValue < 100){
                ticks = 3.5 / 0.1
                wValue += 3.5
                    paraAni.start()
                    console.log("Plus:",control.visualPosition + " " + control.availableHeight)
                }
            }
            else
                wValue = 100
        }
    }

    Canvas{
        id: canvas_ruler
        //anchors.fill: parent//这个导致了之前竖直刻度无法移动
        //anchors.fill: control
        anchors.margins:10
        contextType: "2d"
        renderTarget: Canvas.FramebufferObject

        z:5
        width: 50
        height: 800
        x:175
        y:22

        onPaint: {
            var ctx = getContext("2d");
            var value = wValue
            //ctx.fillRect(0, 0, width, height)
            draw(ctx,value)
        }

        //并行动画
        ParallelAnimation{
            id:paraAni
            NumberAnimation{
                //id:animatePlus
                target: imageTri
                properties: "y"
                from: imageTri.y - imageTri.width/2/10 * ticks
                to:imageTri.y
                duration: 300
            }

            NumberAnimation{
                target:name
                properties: "y"
                from:imageTri.y - imageTri.width/2/10 * ticks
                to:imageTri.y
                duration: 300
            }
        }

					//单独动画
            NumberAnimation{
                id:animatesub
                target: imageTri
                properties: "y"
                from:imageTri.y + imageTri.width/2/10
                to:imageTri.y
                duration: 500
            }
    }

    function draw(ctx,value ) {

        var config={
           // width: canvas_ruler.width /*- rulerWidth*/,
            //height: canvas_ruler.height /*- rulerWidth*/,

            // 刻度尺相关
            size: 50, // 刻度尺总刻度数
            x: 10, // 刻度尺x坐标位置
            y: rulerWidth, // 刻度尺y坐标位置
            w: 10, // 刻度线的间隔 5
            h: 10 // 刻度线基础长度
        }

        var size = 35//30//(config.size || 100) * 10 + 1//设置总刻度
        var x = rulerWidth
        var y = rulerWidth/* - 1*/
        var w = 22//config.w || 5
        var h = config.h || 10
        var offset = 3 // 上面数字的偏移量

        // 画之前清空画布
        ctx.clearRect(0, 0, config.width, config.height)
        ctx.fillStyle ="#F5DEB3"
        //ctx.fillStyle ="#FFFFFF"//底色
        //ctx.fillStyle = transientParent

        //ctx.fillRect(0, y,rulerWidth, /*config.height*/  size*w);//设置背景色的绘制宽高竖直
        //ctx.fillRect(x,0 , config.width,rulerWidth);//水平

        ctx.fillStyle ="#000000"
        ctx.strokeStyle = "#Aa64cf"
        ctx.lineWidth = 1
        ctx.font.pointSize = 15
        ctx.font.bold = true

        for (var i = 0; i < size ; i++) {  //画垂直
            ctx.beginPath()          // 开始一条路径
            // 移动到指定位置
            // ctx.moveTo(y,x + i * w)
            ctx.moveTo(0,x + i * w)//ok

            if (i % 5 == 0) {//刻度
                //console.log("wValue:",wValue)
                // 计算偏移量
                //offset = (String(i / 5).length * 6 / 2)
                //ctx.fillText();
                ctx.lineWidth = 2
                ctx.strokeStyle = "#d4237a"//"#7d5312"
                ctx.fillText(i==0?"0m":/*"-" + */String(i) +"m", y - h * 1.2+15 ,x + i * w - offset  );
                ctx.lineTo( y /*+ h * 2*/,x + i * w)
            } else {
                // 满5刻度时的刻度线略长于1刻度的
                ctx.strokeStyle = "#Aa64cf"
                ctx.lineWidth = 1
                ctx.lineTo(y-15 /*+ (i % 5 === 0 ? 1 : 0.6) * h*/,x + i * w)
            }

            // 画出路径
            ctx.stroke()
            ctx.closePath()
        }

    }
}

使用:创建一个qml工程,上述代码替换掉main.qml即可,其中图片文件自行更换。

效果:
效果图
动态效果:在这里插入图片描述

代码仅供参考,还是有较多可以优化的地方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值