I am trying to use QML Canvas.requestAnimationFrame
to draw some custom animation. I expected that the provided callback is called once for each frame, about 60 times per second. The code I have is:
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()
}
}
What I see is that the callback is called way more often. The counter reaches 70000 in a few seconds, after which the application becomes entirely unresponsive.
What am I doing wrong?
Your drawFrame()
function passes itself as callback function for rendering and you're caught in a loop. You either want to render on demand only like for example after user input to keep resources at a minimum, or you have some logic that changes every frame or you just need continuous rendering.
If time-based rendering is what you want, just use a 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()
}
}
}
Just updated the code:
onPaint
calls are synced to the display frame rate even though the timer interval is set to 1ms as can be seen from the log when running the sample above.
In fact the whole block assigned to the onTriggered
signal is executed every millisecond but requestPaint()
makes sure to synchronize rendering calls for best performance just like requestAnimationFrame()
does for the HTML canvas.
Apparently, requestAnimationFrame()
inside the QML.Canvas doesn't work as expected and there's not much documentation...
Hope this helps!
Just a small update on this topic. I've encountered same problem with the Qt qml Canvas and requestAnimationFrame
while I was working on my project. The solution I've found is to switch the render strategy to Threaded
and use onPainted
signal. The example of qCring's code with my updates looks like this:
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With