Qt QML Canvas.requestAnimationFrame分解

Qt QML Canvas.requestAnimationFrame分解,qt,canvas,qml,qtquick2,Qt,Canvas,Qml,Qtquick2,我正在尝试使用QMLCanvas.requestAnimationFrame来绘制一些自定义动画。我希望提供的回调每帧调用一次,大约每秒调用60次。我的密码是: Canvas { id: canvas width: 600 height: 600 function draw() { } Component.onCompleted: { var i = 1; function drawFrame() {

我正在尝试使用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()
函数将自身传递为用于渲染的回调函数,您陷入了一个循环。您可能希望仅在用户输入后按需渲染,以将资源保持在最小值,或者您有一些逻辑更改每个帧,或者您只需要连续渲染

如果您需要基于时间的渲染,只需使用
计时器

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
调用与显示帧速率同步,即使计时器间隔设置为1ms,运行上述示例时可以从日志中看到这一点。 事实上,分配给
onTriggered
信号的整个块每毫秒执行一次,但是
requestPaint()
确保同步渲染调用以获得最佳性能,就像
requestAnimationFrame()
对HTML画布所做的那样

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


希望这有帮助

这只是一个关于这个话题的小更新。当我在项目中工作时,我在Qt-qml画布和
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之前存在一个异常。此错误已修复

此代码按预期和期望工作,以保持画布不断重画

画布{
宽度:100;高度:100;
属性变量ctx
onAvailableChanged:if(可用)ctx=getContext('2d');
onPaint:{
如果(!ctx)返回;
ctx.clearRect(0,0,宽度,高度);
//在这里画
请求动画帧(绘制);
}
}

我认为您必须避免代码中的递归。相关:感谢您的回复-但您的示例似乎没有实际使用requestAnimationFrame?至少在HTML画布中,使用requestAnimationFrame的优势在于,您的代码以最佳速率被调用。你是说Qt中的requestAnimationFrame被破坏了,应该避免吗?是的,你是对的。在HTML/JS中这是可行的,在QML中则不然。我刚刚更新了答案