QML Canvas.requestAnimationFrame爆炸

时间:2015-06-08 12:30:06

标签: qt canvas qml qtquick2

我正在尝试使用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,之后应用程序完全没有响应。

我做错了什么?

3 个答案:

答案 0 :(得分:2)

您的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()
        }
    }
}

编辑:

刚刚更新了代码:

即使定时器间隔设置为1ms,

onPaint调用也会同步到显示帧速率,这可以从运行上面示例的日志中看出。 实际上,分配给onTriggered信号的整个块每毫秒执行一次,但requestPaint()确保同步渲染调用以获得最佳性能,就像{canvas}对{Photoshop}那样。requestAnimationFrame()

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

希望这有帮助!

答案 1 :(得分:1)

关于此主题的一个小更新。在我处理项目时,我遇到了与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();
    }
}

答案 2 :(得分:0)

在Qt 5.9之前有一个bug with requestAnimationFrame()。这个错误已得到修复。

此代码按预期工作,并希望不断重绘画布。

browser.ignoreSynchronization = false;