简体   繁体   中英

How to draw a rectangle in QtQuick/QML canvas by press and draging

I want to draw some rectangles on the top of the image, which is painted by QQuickPaintedItem subclass and created in QML. I use the canvas to draw the rectangles, which can be translated and scaled with the image by using mouse. The following code doesn't work:

 Canvas{
    id:canvas
    anchors.fill:parent
    // zoom in/out managed by mouse wheel
    property double dx:0.0
    property double dy:0.0
    property double sx:1.0
    property double sy:1.0
    // mapped mouse position will be displayed on the left top of the window
    property double mx:0
    property double my:0
    // mapped mouse postion when last left buttion pressed
    property double lastx:0.0
    property double lasty:0.0
    // flag
    property bool drawing:false

    // map x,y to my coordinate
    function mapToPaint(x,y)
    {
        var mx=(x-dx)/sx;
        var my=(y-dy)/sy;
        return {"x":mx,"y":my};
    }


    onPaint:{
        var ctx = canvas.getContext("2d");
        ctx.lineWidth = 1
        ctx.strokeStyle = Qt.lighter(root.color)
        ctx.clearRect (0, 0, width, height);
        ctx.save();
        // transform to my coordinate
        ctx.translate(dx,dy);
        ctx.scale(sx,sy);
        // draw a rect
        // !! I hope drawing can be displayed when mouse moving,
        // !! but the rect wasn't displayed after the mouse button 
        // !! was released. Instead many rectangles will be showed when 
        // !! I rolled the mouse wheel after the press-drag operation.
        if(drawing)
            ctx.rect(lastx,lasty,mx-lastx,my-lasty);
        ctx.stroke();
        ctx.restore();
}
MouseArea {
    id:area
    anchors.fill: parent
    hoverEnabled:true
    preventStealing:true
    property double factor: 1.2
    onPressed:
    {

        if (mouse.button == Qt.LeftButton)
        {
            var p=canvas.mapToPaint(mouse.x,mouse.y);
            canvas.lastx=p.x;
            canvas.lasty=p.y;
            canvas.drawing=true
        }
    }

    onWheel:
    {
        if(wheel.angleDelta.y > 0)  // zoom in
            var zoomFactor = factor
        else                        // zoom out
            zoomFactor = 1/factor   

        canvas.sx*=zoomFactor;
        canvas.sy*=zoomFactor;
        canvas.dx=wheel.x-(wheel.x-canvas.dx)*zoomFactor;
        canvas.dy=wheel.y-(wheel.y-canvas.dy)*zoomFactor;
        canvas.requestPaint();
    }
    onPositionChanged:
    {
        var p=canvas.mapToPaint(mouse.x,mouse.y);
        canvas.mx=p.x;
        canvas.my=p.y;
        // I hope the rectangle can be showed when draging
        // but it didn't work!! why?
        // mouse.button == Qt.LeftButton is always false!!!
        // so I have to use the canvas.drawing flag
        // if (mouse.button == Qt.LeftButton)
        if(canvas.drawing)
            canvas.requestPaint();
    }

When I pressed and drag the mouse, I got the following picture:

here

update:

using ctx.strokeRect instead of ctx.rect, I got the right rectangle, but still can not receive the mouse buttion in onPositionChanged.

here

In general what you want to do if you need a live preview of your rectangle (or any other object), you need to create a temporary rectangle to draw on top of your canvas when you click on it, while you move the mouse you just resize that one rectangle to the size of you mouse position delta and when you let go of the mouse you actually paint the rectangle on the canvas and remove the preview.

That is what I would do, and creating a temporary rectangle in QML is pretty straight forward so I guess you should be fine with implementing it yourself?

You can of course draw all updates on the canvas, but since it's not that easy to just delete the last update, it's easier to use this approach with a temporary overlay, I guess.

//handle Painted
Canvas{
    id:canvas
    anchors.fill:parent
    // zoom in/out managed by mouse wheel
    property double dx:0.0
    property double dy:0.0
    property double sx:1.0
    property double sy:1.0
    // mapped mouse position will be displayed on the left top of the window
    property double mx:0
    property double my:0
    // mapped mouse postion when last left buttion pressed
    property double lastx:0.0
    property double lasty:0.0
    // flag
    property bool drawing:false

    // map x,y to my coordinate
    function mapToPaint(x,y)
    {
        var mx=(x-dx)/sx;
        var my=(y-dy)/sy;
        return {"x":mx,"y":my};
    }

    function clear(){
        var ctx = canvas.getContext("2d");
        ctx.reset();
        canvas.requestPaint();

    }
    onPaint:{
        var ctx = canvas.getContext("2d");
        ctx.lineWidth = 1
        ctx.strokeStyle = 'blue'

        ctx.save();
        // transform to my coordinate
        ctx.translate(dx,dy);
        ctx.scale(sx,sy);
        // draw a rect
        // !! I hope drawing can be displayed when mouse moving,
        // !! but the rect wasn't displayed after the mouse button
        // !! was released. Instead many rectangles will be showed when
        // !! I rolled the mouse wheel after the press-drag operation.

        if(drawing)
            ctx.rect(lastx,lasty,mx-lastx,my-lasty);
        ctx.stroke();
        ctx.restore();

    }
}

    MouseArea {
        id:area
        anchors.fill: parent
        hoverEnabled:true
        preventStealing:true
        property double factor: 1.2
        onPressed:
        {


            var p=canvas.mapToPaint(mouse.x,mouse.y);
            canvas.lastx=p.x;
            canvas.lasty=p.y;
            canvas.drawing=true

        }

        onPositionChanged:
        {
            canvas.clear();
            var p=canvas.mapToPaint(mouse.x,mouse.y);
            canvas.mx=p.x;
            canvas.my=p.y;
            // I hope the rectangle can be showed when draging
            // but it didn't work!! why?
            // mouse.button == Qt.LeftButton is always false!!!
            // so I have to use the canvas.drawing flag
            // if (mouse.button == Qt.LeftButton)
            if(canvas.drawing)
                canvas.requestPaint();
        }
        onReleased: {
            canvas.clear();
            console.log(canvas.lastx,canvas.lasty,canvas.mx,canvas.my);
            canvas.drawing=false
        }

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM