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);
}
}
我正在尝试使用 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);
}
}