QML Canvas.requestAnimationFrame 爆炸

QML Canvas.requestAnimationFrame explodes

我正在尝试使用 QML Canvas.requestAnimationFrame 绘制一些自定义动画。我预计所提供的回调会为每一帧调用一次,大约每秒 60 次。我的代码是:

Canvas {
    id: canvas

    width: 600
    height: 600

    function draw() {
    }

    Component.onCompleted: {
        var i = 1;

        function drawFrame() {
            requestAnimationFrame(drawFrame)
            console.log("Frame callback: " + i++)
            draw()
        }

        drawFrame()
    }

    onPaint: {
        draw()
    }

}

我看到回调的调用频率更高。几秒钟后计数器达到 70000,此后应用程序完全没有响应。

我做错了什么?

您的 drawFrame() 函数将自身作为回调函数传递给渲染,您陷入了循环。您要么只想按需渲染,例如在用户输入后将资源保持在最低限度,要么您有一些逻辑会改变每一帧,或者您只需要连续渲染。

如果您想要基于时间的渲染,只需使用 Timer:

import QtQuick 2.4

Canvas  {
    id: cvs
    width: 600; height: 600
    contextType: "2d"
    property real i : 0

    onPaint: {
        console.timeEnd("t")
        if (context) {
            context.clearRect (0, 0, width, height)
            context.fillRect(i, 50, 50, 50 + i)
        }
        console.time("t")
    }

    Timer {
        interval: 1
        repeat: true
        running: true

        onTriggered: {
            cvs.i = (cvs.i + 0.1) % cvs.width
            cvs.requestPaint()
        }
    }
}

编辑:

刚刚更新了代码:

onPaint 调用与显示帧速率同步,即使计时器间隔设置为 1 毫秒,从日志中可以看出 运行 上面的示例。 事实上,分配给 onTriggered 信号的整个块每毫秒执行一次,但 requestPaint() 确保同步渲染调用以获得最佳性能,就像 requestAnimationFrame() 对 HTML canvas。

显然,QML.Canvas 中的 requestAnimationFrame() 没有按预期工作并且没有太多文档...

希望对您有所帮助!

只是关于这个主题的一个小更新。我在处理项目时遇到了与 Qt qml Canvas 和 requestAnimationFrame 相同的问题。我找到的解决方案是将渲染策略切换为 Threaded 并使用 onPainted 信号。带有我的更新的 qCring 代码示例如下所示:

import QtQuick 2.4

Canvas  {
    id: cvs
    width: 600; height: 600

    //renderStrategy: Canvas.Cooperative // Will work as well but animation chops on my computer from time to time
    renderStrategy: Canvas.Threaded

    contextType: "2d"
    property real i : 0

    function animate() {
        cvs.i = (cvs.i + 0.1) % cvs.width;
    }

    onPaint: {
        console.timeEnd( "t" )
        if ( context ) {
            context.clearRect( 0, 0, width, height )
            context.fillRect( i, 50, 50, 50 + i )
        }
        console.time("t")

        cvs.requestAnimationFrame(animate);
    }

    onPainted: {
        cvs.requestPaint();
    }
}

Qt 5.9 之前有 bug with requestAnimationFrame()。此错误已修复。

此代码按预期工作并希望保持 canvas 不断重绘。

Canvas {
    width:100; height:100;
    property var ctx
    onAvailableChanged: if (available) ctx = getContext('2d');
    onPaint: {
        if (!ctx) return;
        ctx.clearRect(0, 0, width, height);
        // draw here
        requestAnimationFrame(paint);
    }
}