有一个需求要绘制表示深度刻度尺,联想到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即可,其中图片文件自行更换。
效果:
动态效果:
代码仅供参考,还是有较多可以优化的地方。