QML Canvas - 为什么 requestPaint() 函数不调用绘画?

QML Canvas - Why is the requestPaint() function not calling the paint?

可重现的例子:

这里我用QML画了一条beizer曲线canvas。即使我显式更改开始值和结束值从而导致信号生成,绘制也只被调用一次。

也请查看输出。 为什么requestPaint()函数不调用paint?

Test.qml

import QtQuick 2.4

Canvas
{
    id: head; width: parent.width; height: parent.height

    property int    curveStartX: -1
    property int    curveStartY: -1
    property int    curveEndX: -1
    property int    curveEndY: -1

    Rectangle
    {
        id: startControlPoint
        x:  head.curveStartX; y: head.curveStartY; width: 15; height: 15; color: "red"; radius: 100

        onXChanged:  
        { 
           console.log("start called x1"); 
           head.requestPaint(); 
           console.log("start called x2")
        }

        onYChanged:  
        { 
           console.log("start called y1"); 
           head.requestPaint(); 
           console.log("start called y2")
        }
    }

    Rectangle
    {
        id: endControlPoint
        x: head.curveEndX; y: head.curveEndY; width: 15; height: 15; color: "red"; radius: 100
        onXChanged:  head.requestPaint ()
        onYChanged:  head.requestPaint ()
    }

    onPaint:
    {
        console.log ("Paint got called!")

        var ctx = getContext ("2d");
        ctx.beginPath ();
        ctx.clearRect (0, 0, head.height, head.width);
        ctx.fill ();

        ctx.strokeStyle = head.curveColor
        ctx.lineWidth   = 2;

        ctx.beginPath ();
        // start point of the curve.
        ctx.moveTo (head.curveStartX, head.curveStartY)
        ctx.bezierCurveTo (startControlPoint.x, startControlPoint.y,
                           endControlPoint.x, endControlPoint.y,
                           head.curveEndX, head.curveEndY);
        ctx.stroke ();
    }
}

main.qml

import QtQuick 2.4
import QtQuick.Window 2.2

Window
{
    visible: true
    height: 500
    width: 500

    Test
    {
        id: what
    }

    Component.onCompleted:
    {
        what.curveStartX = 0
        what.curveStartY = 0

        what.curveEndX = 50
        what.curveEndY = 50
        /////////////////////////////////////////
        what.curveStartX = 10
        what.curveStartY = 10

        what.curveEndX = 60
        what.curveEndY = 60
    }
}

输出:

QML debugging is enabled. Only use this in a safe environment.
qml: start called x1
qml: start called x2
qml: start called y1
qml: start called y2
qml: start called x1
qml: start called x2
qml: start called y1
qml: start called y2
qml: start called x1
qml: start called x2
qml: start called y1
qml: start called y2
qml: Paint got called!

requestPaint() only requests that the Canvas is repainted. If you take a look into QQuickCanvasItem::requestPaint():

void QQuickCanvasItem::requestPaint()
{
    markDirty(d_func()->canvasWindow);
}

可以看到调用了QQuickCanvasItem::markDirty():

void QQuickCanvasItem::markDirty(const QRectF& rect)
{
    Q_D(QQuickCanvasItem);
    if (!d->available)
        return;

    d->dirtyRect |= rect;

    polish();
}

依次调用 QQuickItem::polish():

void QQuickItem::polish()
{
    Q_D(QQuickItem);
    if (!d->polishScheduled) {
        d->polishScheduled = true;
        if (d->window) {
            QQuickWindowPrivate *p = QQuickWindowPrivate::get(d->window);
            bool maybeupdate = p->itemsToPolish.isEmpty();
            p->itemsToPolish.insert(this);
            if (maybeupdate) d->window->maybeUpdate();
        }
    }
}

因此,只要场景图形决定准备就绪,就会发出 paint() 信号。信号在 QQuickCanvasItem::updatePolish().

中发出