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

时间:2024-04-04 13:07:16

gitHub:sueRimn

源码:

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

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

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

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

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

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

贴上代码和注释:

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.鼠标按压拖动绘图-无预览路径(鼠标释放完成绘制)

代码和注释:

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

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中实现清理临时区域,因为如果不清理 ,画直线的时候没问题,但是在画矩形圆的时候会出现如下情况:

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

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

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

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

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

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

 纯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();
                }
             }
          }
     }

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