AKA:Canvas requestPaint()太慢了; requestAnimationFrame()太快
我正在尝试创建一个尽可能快地重新绘制的QML Canvas - 在主UI渲染循环中每次更新一次 - 以创建FPS计时器。
我最初写了这个简单的测试:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
visible:true; width:100; height:100
Canvas {
anchors.fill:parent
onPaint: console.log(+new Date)
}
}
我只收到一次回调。所以我添加了requestPaint()
:
onPaint: {
console.log(+new Date)
requestPaint()
}
没有变化:我仍然只收到一个回调。如果我使用markDirty()
,则相同。如果我在画布上每次回调都画了一些东西,那就相同了。
所以我搬到了requestAnimationFrame()
:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
visible:true; width:100; height:100
Canvas {
anchors.fill:parent
Component.onCompleted: crank()
function crank(){
console.log(+new Date)
requestAnimationFrame(crank)
}
}
}
现在我得到回调,但太多了。平均而言,我每毫秒获得77次回调,在一毫秒内有多达127次回调。如此多的回调,应用程序中没有任何其他内容显示,甚至最初都没有。即使我删除了console.log()
,也证明我没有受到限制。
如何让“我的画布”每次“每帧”重绘一次,以便我可以半精确地测量FPS?为什么requestPaint()
实际上不起作用?为什么requestAnimationFrame()
显然无用?
答案 0 :(得分:2)
您的方法存在的问题是您要求onPaint
绘画,这不起作用,
因为onPaint
事件是从内部触发的
QQuickItem::polish()
void QQuickItem::polish()
{
Q_D(QQuickItem);
if (!d->polishScheduled) {
d->polishScheduled = true;
if (d->window) {
QQuickWindowPrivate *p = QQuickWindowPrivate::get(d->window);
bool maybeupdate = p->itemsToPolish.isEmpty();
p->itemsToPolish.append(this);
if (maybeupdate) d->window->maybeUpdate();
}
}
}
在此通话期间,d->polishScheduled
设置为true,如果再次拨打requestPaint()
,则不会发生任何操作。您需要异步触发它。例如,使用间隔为0的Timer
。
import QtQuick 2.0
Canvas {
id: canvas
width: 200
height: 200
property real angle
property int fps
Timer {
id: repaintTimer
running: false
interval: 0
onTriggered: {
angle += 0.01
canvas.requestPaint()
}
}
Timer {
interval: 1000
running: true
repeat: true
onTriggered: {
console.log(fps)
fps = 0
}
}
onPaint: {
var ctx = getContext("2d")
ctx.save()
ctx.clearRect(0, 0, width, height)
ctx.moveTo(100, 100)
ctx.translate(100,100)
ctx.rotate(angle)
ctx.beginPath()
ctx.lineTo(40, 10)
ctx.lineTo(40, 40)
ctx.lineTo(10, 40)
ctx.lineTo(10, 10)
ctx.closePath()
ctx.stroke()
ctx.restore()
fps += 1
repaintTimer.start()
}
}
另一个Timer
来记录fps。当我在qmlscene
中运行此代码时,我得到60 fps。
答案 1 :(得分:1)
在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);
}
}