QML Canvas.requestAnimationFrame 爆炸
Posted
技术标签:
【中文标题】QML Canvas.requestAnimationFrame 爆炸【英文标题】:QML Canvas.requestAnimationFrame explodes 【发布时间】: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,之后应用程序完全没有响应。
我做错了什么?
【问题讨论】:
我认为你必须避免代码中的递归。 相关:***.com/q/39353234/405017 【参考方案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);
【讨论】:
以上是关于QML Canvas.requestAnimationFrame 爆炸的主要内容,如果未能解决你的问题,请参考以下文章
Qt/QML - 在 C++ 中注册 QML 类型会使 QML 代码不起作用