我有一个应用程序,需要以指定的帧速率(模拟旧机器)逐像素绘制。其中一个注意点是主机引擎在后台线程中运行,以确保UI在模拟期间保持响应和可用性。
目前,我正在尝试使用类似以下代码的东西:
这个方法效果很好,而且速度惊人地快。然而,存在一个问题。更新函数会安排一个paintEvent,但它可能不会立即发生。实际上,根据Qt文档,一堆paintEvent可能被"合并"。
我看到的负面影响是,在模拟几分钟后,屏幕停止更新(图像似乎冻结,尽管模拟仍在运行),直到我做一些强制屏幕更新的事情,例如切换窗口大小。
我尝试使用QTimer等类似机制来使渲染效果在GUI线程中,以便我可以强制立即更新,但这导致了无法接受的性能问题。
有没有更好的方法在固定时间间隔内不断地将像素绘制到小部件上?最好使用纯Qt解决方案。
目前,我正在尝试使用类似以下代码的东西:
class QVideo : public QWidget {
public:
QVideo(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f), screen_image_(256, 240, QImage::Format_RGB32) {
}
void draw_frame(void *data) {
// render data into screen_image_
}
void start_frame() {
// do any pre-rendering prep work that needs to be done before
// each frame
}
void end_frame() {
update(); // force a paint event
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawImage(rect(), screen_image_, screen_image_.rect());
}
QImage screen_image_;
};
这个方法效果很好,而且速度惊人地快。然而,存在一个问题。更新函数会安排一个paintEvent,但它可能不会立即发生。实际上,根据Qt文档,一堆paintEvent可能被"合并"。
我看到的负面影响是,在模拟几分钟后,屏幕停止更新(图像似乎冻结,尽管模拟仍在运行),直到我做一些强制屏幕更新的事情,例如切换窗口大小。
我尝试使用QTimer等类似机制来使渲染效果在GUI线程中,以便我可以强制立即更新,但这导致了无法接受的性能问题。
有没有更好的方法在固定时间间隔内不断地将像素绘制到小部件上?最好使用纯Qt解决方案。
编辑:由于一些人选择摆出态度而不是阅读整个问题,我将澄清问题。我不能使用QWidget::repaint
,因为它有一个限制,必须从与事件循环相同的线程中调用。否则,没有更新发生,而是会得到如下的qDebug消息:
QPixmap: It is not safe to use pixmaps outside the GUI thread
QPixmap: It is not safe to use pixmaps outside the GUI thread
QWidget::repaint: Recursive repaint detected
QPainter::begin: A paint device can only be painted by one painter at a time.
QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent
QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent
编辑:为了演示问题,我创建了这个简单的示例代码:
QVideo.h
#include <QWidget>
#include <QPainter>
class QVideo : public QWidget {
Q_OBJECT;
public:
QVideo(QWidget *parent = 0, Qt::WindowFlags f = 0) : QWidget(parent, f), screen_image_(256, 240, QImage::Format_RGB32) {
}
void draw_frame(void *data) {
// render data into screen_image_
// I am using fill here, but in the real thing I am rendering
// on a pixel by pixel basis
screen_image_.fill(rand());
}
void start_frame() {
// do any pre-rendering prep work that needs to be done before
// each frame
}
void end_frame() {
//update(); // force a paint event
repaint();
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawImage(rect(), screen_image_, screen_image_.rect());
}
QImage screen_image_;
};
main.cc:
#include <QApplication>
#include <QThread>
#include <cstdio>
#include "QVideo.h"
struct Thread : public QThread {
Thread(QVideo *v) : v_(v) {
}
void run() {
while(1) {
v_->start_frame();
v_->draw_frame(0); // contents doesn't matter for this example
v_->end_frame();
QThread::sleep(1);
}
}
QVideo *v_;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QVideo w;
w.show();
Thread t(&w);
t.start();
return app.exec();
}
我肯定愿意探索不使用临时的QImage
进行渲染的选项。它只是Qt
中似乎唯一具有直接像素写入接口的类。