【问题标题】:QML Canvas.requestAnimationFrame explodesQML Canvas.requestAnimationFrame 爆炸
【发布时间】:2015-06-08 12:30:05
【问题描述】:

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

我做错了什么?

【问题讨论】:

标签: qt canvas qml qtquick2


【解决方案1】:

您的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 画布所做的那样。

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

希望这会有所帮助!

【讨论】:

  • 感谢您的回复-但您的示例似乎实际上并未使用 requestAnimationFrame?至少在 HTML Canvas 中,使用 requestAnimationFrame 的优势在于您的代码以最佳速率被调用。你是说 Qt 中的 requestAnimationFrame 坏了,应该避免吗?
  • 是的,你是对的。在 HTML/JS 中这有效,在 QML 中则无效。我刚刚更新了答案
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    此代码按预期工作并保持画布不断重绘。

    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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      • 2022-01-18
      • 2013-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多