QML学习笔记-纯qml实现canvas画板功能-鼠标画图

xiaoxiao2025-04-19  9

gitHub:sueRimn

源码:

qml-draw-canvas (随笔画)  qml-draw-canvs-press(按压随笔画)qml-draw-canvas-path(预览路径)

用纯qml实现canvas画板功能,用鼠标进行画图,可以画直线,画圆,画矩形,画弧线。

由于canvas画图会有延迟和卡顿,建议还是结合c++实现画图功能。

以下gif效果都没有录进鼠标

1.鼠标点击画图-无预览路径(两点实现)

贴上代码和注释:

property real startX property real startY property real stopX property real stopY property color color: colorTools.paintColor property var paintType: ["line","rect","circle","curve"]//自定义绘制类型 property var clickPoint: []//多边形画图的存点数组 未实现 property int clickNum: 0//鼠标点击 Row{ id:colorTools//颜色提取工具 anchors{ horizontalCenter: parent.horizontalCenter top: parent.top topMargin: 8 } property color paintColor: "#33b5e5"//设置初始画笔颜色 spacing: 4; // Repeater{//四个colorSquare // model: ["#33B5E5", "#99CC00", "#FFBB33", "#FF4444"]//modelData 颜色数据 // ColorSquare{ // id:red; // color: modelData; // active: parent.paintColor == color//当选中一个colorSquare时,当前画笔颜色为选中的颜色 // onClicked: { // parent.paintColor = color // } // } // } Button { text: "Clear" onClicked: { canvas.clear() } } Button{ text: "line"; onClicked: { paintType = "line"; //canvas.requestPaint(); } } Button{ text: "rect" onClicked: { paintType = "rect"; // canvas.requestPaint(); } } Button{ text: "circle" onClicked: { paintType = "circle"; // canvas.requestPaint(); } } Button{ text: "curve" onClicked: { paintType = "curve"; // canvas.requestPaint(); } } } Rectangle{ anchors.fill: canvas border.color: "#666" border.width: 4; } Canvas{ id:canvas; anchors{ left: parent.left; right:parent.right; top:colorTools.bottom; bottom: parent.bottom; margins: 8 } //鼠标点击坐标位置 function clear() { var ctx = getContext("2d"); ctx.reset(); canvas.requestPaint(); } onPaint: { var ctx = getContext("2d") ctx.lineWidtn = 5 ctx.strokeStyle = canvas.color;//轮廓颜色 //ctx.fillStyle = canvas.color;//填充颜色 ctx.beginPath() if(paintType === "line"){ ctx.moveTo(startX,startY) startX = area.mouseX; startY = area.mouseY; ctx.lineTo(stopX,stopY) stopX = area.mouseX; stopY = area.mouseY; } if(paintType === "rect"){ //ctx.fillRect(startX,startY,stopX-startX,stopY-startY)//填充类型 //ctx.clearRect(0,0,width,height) ctx.strokeRect(startX,startY,stopX-startX,stopY-startY)//非填充 } if(paintType === "circle"){ ctx.arc(startX,startY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2)),0,360,false) } if(paintType === "curve"){ ctx.arcTo(startX,startY,stopX,stopY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2))) } // ctx.fill();//完成填充 ctx.stroke() } MouseArea{ id:area; anchors.fill: parent; onClicked: {//存点 遍历 //clickPoint.push({"x":mouseX,"y":mouseY})//多边形绘制存点 多边形未实现 clickNum++; for(var i = 0;i<clickPoint.length;i++){ var point = clickPoint[i]; } if(clickNum == 1){ startX = mouseX; startY = mouseY; } if(clickNum == 2){ clickNum = 0; stopX = mouseX; stopY = mouseY; canvas.requestPaint(); } } } } }

2.鼠标按压拖动绘图-无预览路径(鼠标释放完成绘制)

代码和注释:

property real startX property real startY property real stopX property real stopY property color color: colorTools.paintColor property var paintType: ["line","rect","circle","curve"] property var clickPoint: [] property int clickNum: 0 Row{ id:colorTools//颜色提取工具 anchors{ horizontalCenter: parent.horizontalCenter top: parent.top topMargin: 8 } property color paintColor: "#33b5e5"//设置初始画笔颜色 spacing: 4; // Repeater{//四个colorSquare // model: ["#33B5E5", "#99CC00", "#FFBB33", "#FF4444"]//modelData 颜色数据 // ColorSquare{ // id:red; // color: modelData; // active: parent.paintColor == color//当选中一个colorSquare时,当前画笔颜色为选中的颜色 // onClicked: { // parent.paintColor = color // } // } // } Button { text: "Clear" onClicked: { canvas.clear() } } Button{ text: "line"; onClicked: { paintType = "line"; //canvas.requestPaint(); } } Button{ text: "rect" onClicked: { paintType = "rect"; // canvas.requestPaint(); } } Button{ text: "circle" onClicked: { paintType = "circle"; // canvas.requestPaint(); } } Button{ text: "curve" onClicked: { paintType = "curve"; // canvas.requestPaint(); } } } Rectangle{ anchors.fill: canvas border.color: "#666" border.width: 4; } Canvas{ id:canvas; anchors{ left: parent.left; right:parent.right; top:colorTools.bottom; bottom: parent.bottom; margins: 8 } //鼠标点击坐标位置 function clear() {//此清除有问题 var ctx = getContext("2d"); ctx.reset(); canvas.requestPaint(); } onPaint: { var ctx = getContext("2d") ctx.lineWidtn = 10 ctx.strokeStyle = canvas.color; // ctx.fillStyle = canvas.color;//若想要填充的 此不注释 ctx.beginPath() if(paintType === "line"){ ctx.moveTo(startX,startY) startX = area.mouseX; startY = area.mouseY; ctx.lineTo(stopX,stopY) stopX = area.mouseX; stopY = area.mouseY; } if(paintType === "rect"){ //ctx.fillRect(startX,startY,stopX-startX,stopY-startY)//填充类型 //ctx.clearRect(0,0,width,height) ctx.strokeRect(startX,startY,stopX-startX,stopY-startY)//非填充 } if(paintType === "circle"){ ctx.arc(startX,startY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2)),0,360,false) } if(paintType === "curve"){//未实现 ctx.arcTo(startX,startY,stopX,stopY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2))) } //ctx.fill(); ctx.stroke() } MouseArea{ id:area; anchors.fill: parent; // onClicked: {//存点 遍历 // clickPoint.push({"x":mouseX,"y":mouseY}) // clickNum++; // for(var i = 0;i<clickPoint.length;i++){ // var point = clickPoint[i]; // } // if(clickNum == 1){ // startX = mouseX; // startY = mouseY; // } // if(clickNum == 2){ // clickNum = 0; // stopX = mouseX; // stopY = mouseY; // canvas.requestPaint(); // } // } onPressed: { startX = mouseX; startY = mouseY; } onMouseXChanged: { stopX = mouseX; } onMouseYChanged: { stopY = mouseY; } onReleased: { canvas.requestPaint()//重绘 } // onPositionChanged: { // canvas.requestPaint()//重绘 这句话不注释 会有预览路径 但是临时区没有清理 需要在cpp中进行清除 // } } }

3.鼠标按压拖动绘制-有预览路径

因为想要绘制的过程中有预览路径,需要在cpp中实现清理临时区域,因为如果不清理 ,画直线的时候没问题,但是在画矩形圆的时候会出现如下情况:

cpp中如何画,可以参考这篇博文:https://blog.csdn.net/foruok/article/details/32698603

第三种方法可以在qml中有预览路径的同时也清理临时图区,只不过只能存在一个图元,也就是画了直线之后画圆,直线就会消失。所以还是建议结合c++中的QQuickPaintedItem方法等进行清理临时图区。这个链接有三个实例提供参考 https://www.aliyun.com/jiaocheng/173346.html ,上面那个链接就是对第一个实例的解释

以下代码我做了临时图元的简单清理,但是画线段的时候由于清理了,所以画不出来了,所以还是建议看博客结合cpp

通过gif可以看到录制把临时图元都看到了,但是在实际绘制的时候却看不到的,?

 纯Qml代码如下:

property real startX property real startY property real stopX property real stopY property color color: colorTools.paintColor property var paintType: ["line","rect","circle","curve"] property bool isMouseMoveEnable: false //是否允许鼠标移动绘制事件 Row{ id:colorTools//颜色提取工具 anchors{ horizontalCenter: parent.horizontalCenter top: parent.top topMargin: 8 } property color paintColor: "#33b5e5"//设置初始画笔颜色 spacing: 4; // Repeater{//四个colorSquare // model: ["#33B5E5", "#99CC00", "#FFBB33", "#FF4444"]//modelData 颜色数据 // ColorSquare{ // id:red; // color: modelData; // active: parent.paintColor == color//当选中一个colorSquare时,当前画笔颜色为选中的颜色 // onClicked: { // parent.paintColor = color // } // } // } Button { text: "Clear" onClicked: { canvas.clear() } } Button{ text: "line"; onClicked: { paintType = "line"; //canvas.requestPaint(); } } Button{ text: "rect" onClicked: { paintType = "rect"; // canvas.requestPaint(); } } Button{ text: "circle" onClicked: { paintType = "circle"; // canvas.requestPaint(); } } Button{ text: "curve" onClicked: { paintType = "curve"; // canvas.requestPaint(); } } } Rectangle{ anchors.fill: canvas border.color: "#666" border.width: 4; } Canvas{ id:canvas; anchors{ left: parent.left; right:parent.right; top:colorTools.bottom; bottom: parent.bottom; margins: 8 } //鼠标点击坐标位置 function clear() {//此清除有问题 var ctx = getContext("2d"); ctx.reset(); canvas.requestPaint(); } onPaint: { var ctx = getContext("2d") ctx.lineWidtn = 10 ctx.strokeStyle = canvas.color; // ctx.fillStyle = canvas.color;//若想要填充的 此不注释         if(isMouseMoveEnable)         ctx.clearRect(0,0,width,height) //这句话要换成一个只清理临时的对象         ctx.beginPath()       if(paintType === "line")       { ctx.moveTo(startX,startY) startX = area.mouseX; startY = area.mouseY; ctx.lineTo(stopX,stopY) stopX = area.mouseX; stopY = area.mouseY; } if(paintType === "rect") { //ctx.fillRect(startX,startY,stopX-startX,stopY-startY)//填充类型 //ctx.clearRect(0,0,width,height) ctx.strokeRect(startX,startY,stopX-startX,stopY-startY)//非填充 } if(paintType === "circle") { ctx.arc(startX,startY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2)),0,Math.PI*2) } if(paintType === "curve"){ //未实现 ctx.arcTo(startX,startY,stopX,stopY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2))) } //ctx.fill(); ctx.stroke() } MouseArea{ id:area; anchors.fill: parent; onPressed: { //第一次点击鼠标记录起始点 startX = mouse.x; startY = mouse.y; isMouseMoveEnable=true } onReleased: { stopX = mouse.x; stopY = mouse.y; isMouseMoveEnable=false } onPositionChanged: { //鼠标移动动态记录结束点,并且绘制 if(isMouseMoveEnable) { // console.log("mouse posiont changed....") stopX = mouse.x; stopY = mouse.y; canvas.requestPaint(); } } } }

同样的,也可以改成鼠标点击绘制时有预览路径,结合上面的方法可以修改

转载请注明原文地址: https://www.6miu.com/read-5028644.html

最新回复(0)