I'm trying to draw a point on the window by using QImage
, and update the position of this point as fast as possible(less than 1ms every update). I've wrote the code below and run it, but the result is it's too slow(about 50ms every update). I searched the bottleneck and found the cause of this slowness is calling QWidget.update()
takes too long. So I figured out as long as using Widget.update()
it won't be faster. So I think I need another way. Is there any faster way to do this? All of the codes and the result are the following.
我正在尝试使用QImage在窗口上绘制一个点,并尽可能快地更新这个点的位置(每次更新少于1ms)。我已经编写了下面的代码并运行它,但是结果是它太慢了(每次更新大约50ms)。我搜索了瓶颈,发现这个缓慢的原因是调用QWidget.update()太长了。所以我知道只要使用Widget.update()就不会更快。所以我想我需要另一种方法。有更快的方法吗?所有的代码和结果如下。
result:
结果:
qimageBehaviorFor*Question.pro
qimageBehaviorFor*Question.pro
######################################################################
# Automatically generated by qmake (3.1) Wed Mar 29 15:18:09 2017
######################################################################
TEMPLATE = app
TARGET = qimageBehaviorFor*Question
INCLUDEPATH += .
QT += widgets
# Input
HEADERS += qimageBehaviorFor*Question.h
SOURCES += qimageBehaviorFor*Question.cpp
qimageBehaviorFor*Question.h
qimageBehaviorFor*Question.h
#include <iostream>
#include <QApplication>
#include <QWidget>
#include <QTimer>
#include <QPainter>
#include <QPushButton>
#include <QImage>
#include <QTime>
class MyWidget : public QWidget {
Q_OBJECT
private:
QImage *image;
int px, py;
uchar d[100*100*4];
QTimer *timer;
QTime time;
public:
MyWidget();
void paintEvent(QPaintEvent * event);
public slots:
void doPaint();
};
qimageBehaviorFor*Question.cpp
qimageBehaviorFor*Question.cpp
#include "qimageBehaviorFor*Question.h"
int my_counter = 0;
MyWidget::MyWidget() : QWidget(0), px(0), py(0){
image = new QImage(d, 100, 100, QImage::Format_ARGB32);
for(int cnt = 0, a, r, g, b; cnt < 100*100*4;){
a = 255; //alpha
r = 0; //red
g = 0; //green
b = 0; //blue
d[cnt] = b; cnt++;
d[cnt] = g; cnt++;
d[cnt] = r; cnt++;
d[cnt] = a; cnt++;
}
// connect QTimer.timeout to my doPaint method
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(doPaint()));
timer->start(1);
};
void MyWidget::doPaint(){
// manipulate the positions of the points
if(px < 100){
int cnt = 0, b = 255, g = 255, r = 255, a = 255;
d[4 * px + cnt] = b; cnt++;
d[4 * px + cnt] = g; cnt++;
d[4 * px + cnt] = r; cnt++;
d[4 * px + cnt] = a; cnt++;
px++;
}
// update the window
update();
};
void MyWidget::paintEvent(QPaintEvent * event){
QPainter painter(this);
painter.drawImage(0, 0, *image);
}
int main(int argc, char *argv[]){
QApplication app(argc, argv);
MyWidget *widget = new MyWidget();
widget->show();
return app.exec();
}
2 个解决方案
#1
1
After googling couple of hours, I found more faster way. It becomes incredibly very fast(once 20FPS is now about 500FPS).What I'm using now is QGraphicsView Framework
and QPixmap
and QGraphicsPixmapItem
. However I don't know this is the right or efficient way, if it isn't please correct me. And if you know there is more faster way please let me know. Any way I show you the code. I hope it could help someone who fight same problem.
在谷歌上搜索了几个小时之后,我发现了更快捷的方法。它变得非常快(曾经是20FPS,现在是500FPS)。我现在使用的是QGraphicsView框架QPixmap和QGraphicsPixmapItem。但是我不知道这是正确的还是有效的方法,如果不是请纠正我。如果你知道有更快的方法请让我知道。不管怎样,我给你看代码。我希望它能帮助那些与同样问题抗争的人。
qgraphicsSceneExample.h
qgraphicsSceneExample.h
#include <iostream>
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QTimer>
#include <QPainter>
#include <QPushButton>
#include <QImage>
#include <QTime>
#include <QStyleOptionGraphicsItem>
#include <QWidget>
#include <QPixmap>
#include <QGraphicsPixmapItem>
class MyView : public QGraphicsView {
Q_OBJECT
private:
QGraphicsScene *scene;
QImage *image;
QPixmap *pixmap;
QGraphicsPixmapItem *gpixmapItem;
int px, py;
uchar d[100*100*4];
QTimer *timer;
QTime time;
public:
MyView();
//void paintEvent(QPaintEvent * event);
public slots:
void doPaint();
};
qgraphicsSceneExample.cpp
qgraphicsSceneExample.cpp
#include "qgraphicsSceneExample.h"
int my_counter = 0;
MyView::MyView() : px(0), py(0){
image = new QImage(d, 100, 100, QImage::Format_ARGB32);
for(int cnt = 0, a, r, g, b; cnt < 100*100*4;){
a = 255; //alpha
r = 0; //red
g = 0; //green
b = 0; //blue
d[cnt] = b; cnt++;
d[cnt] = g; cnt++;
d[cnt] = r; cnt++;
d[cnt] = a; cnt++;
}
// connect QTimer.timeout to my doPaint method
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(doPaint()));
scene = new QGraphicsScene(0);
pixmap = new QPixmap(QPixmap::fromImage(*image));
gpixmapItem = scene->addPixmap(*pixmap);
this->setScene(scene);
timer->start(1);
};
void MyView::doPaint(){
// manipulate the positions of the points
if(px < 100){
int cnt = 0, b = 255, g = 255, r = 255, a = 255;
d[4 * px + cnt] = b; cnt++;
d[4 * px + cnt] = g; cnt++;
d[4 * px + cnt] = r; cnt++;
d[4 * px + cnt] = a; cnt++;
px++;
}
pixmap = new QPixmap(QPixmap::fromImage(*image));
gpixmapItem->setPixmap(*pixmap);
std::cout << my_counter++ << "\n";
};
int main(int argc, char *argv[]){
QApplication app(argc, argv);
MyView *myView = new MyView();
myView->show();
return app.exec();
}
#2
0
Consider changing the incrementation of Px to more than +1, +5 for example. that will reduce the calls of doPaint() function by 5 times. and will speed up the drawing. Because your problem is that you are updating the drawing a lot, 100 times.
考虑将Px的增量更改为大于+1,+5。这将使doPaint()函数的调用减少5倍。并将加快绘图速度。因为你的问题是你更新了很多,100次。
P.S : you should also stop the timer to stop calling doPaint() function when the drawing is finished. because it is called every 1ms. since timer.start(1)
will emit timeout()
signal every 1ms.
P。您还应该在绘图完成时停止计时器,停止调用doPaint()函数。因为它每1ms被调用一次。因为timer.start(1)将每1ms发出timeout()信号。
Edit: Consider also changing the timeout that is very light (an update every 1ms <=> 1000 FPS).
编辑:还可以考虑更改非常轻的超时(每1ms更新一次<=> 1000 FPS)。
#1
1
After googling couple of hours, I found more faster way. It becomes incredibly very fast(once 20FPS is now about 500FPS).What I'm using now is QGraphicsView Framework
and QPixmap
and QGraphicsPixmapItem
. However I don't know this is the right or efficient way, if it isn't please correct me. And if you know there is more faster way please let me know. Any way I show you the code. I hope it could help someone who fight same problem.
在谷歌上搜索了几个小时之后,我发现了更快捷的方法。它变得非常快(曾经是20FPS,现在是500FPS)。我现在使用的是QGraphicsView框架QPixmap和QGraphicsPixmapItem。但是我不知道这是正确的还是有效的方法,如果不是请纠正我。如果你知道有更快的方法请让我知道。不管怎样,我给你看代码。我希望它能帮助那些与同样问题抗争的人。
qgraphicsSceneExample.h
qgraphicsSceneExample.h
#include <iostream>
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QTimer>
#include <QPainter>
#include <QPushButton>
#include <QImage>
#include <QTime>
#include <QStyleOptionGraphicsItem>
#include <QWidget>
#include <QPixmap>
#include <QGraphicsPixmapItem>
class MyView : public QGraphicsView {
Q_OBJECT
private:
QGraphicsScene *scene;
QImage *image;
QPixmap *pixmap;
QGraphicsPixmapItem *gpixmapItem;
int px, py;
uchar d[100*100*4];
QTimer *timer;
QTime time;
public:
MyView();
//void paintEvent(QPaintEvent * event);
public slots:
void doPaint();
};
qgraphicsSceneExample.cpp
qgraphicsSceneExample.cpp
#include "qgraphicsSceneExample.h"
int my_counter = 0;
MyView::MyView() : px(0), py(0){
image = new QImage(d, 100, 100, QImage::Format_ARGB32);
for(int cnt = 0, a, r, g, b; cnt < 100*100*4;){
a = 255; //alpha
r = 0; //red
g = 0; //green
b = 0; //blue
d[cnt] = b; cnt++;
d[cnt] = g; cnt++;
d[cnt] = r; cnt++;
d[cnt] = a; cnt++;
}
// connect QTimer.timeout to my doPaint method
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(doPaint()));
scene = new QGraphicsScene(0);
pixmap = new QPixmap(QPixmap::fromImage(*image));
gpixmapItem = scene->addPixmap(*pixmap);
this->setScene(scene);
timer->start(1);
};
void MyView::doPaint(){
// manipulate the positions of the points
if(px < 100){
int cnt = 0, b = 255, g = 255, r = 255, a = 255;
d[4 * px + cnt] = b; cnt++;
d[4 * px + cnt] = g; cnt++;
d[4 * px + cnt] = r; cnt++;
d[4 * px + cnt] = a; cnt++;
px++;
}
pixmap = new QPixmap(QPixmap::fromImage(*image));
gpixmapItem->setPixmap(*pixmap);
std::cout << my_counter++ << "\n";
};
int main(int argc, char *argv[]){
QApplication app(argc, argv);
MyView *myView = new MyView();
myView->show();
return app.exec();
}
#2
0
Consider changing the incrementation of Px to more than +1, +5 for example. that will reduce the calls of doPaint() function by 5 times. and will speed up the drawing. Because your problem is that you are updating the drawing a lot, 100 times.
考虑将Px的增量更改为大于+1,+5。这将使doPaint()函数的调用减少5倍。并将加快绘图速度。因为你的问题是你更新了很多,100次。
P.S : you should also stop the timer to stop calling doPaint() function when the drawing is finished. because it is called every 1ms. since timer.start(1)
will emit timeout()
signal every 1ms.
P。您还应该在绘图完成时停止计时器,停止调用doPaint()函数。因为它每1ms被调用一次。因为timer.start(1)将每1ms发出timeout()信号。
Edit: Consider also changing the timeout that is very light (an update every 1ms <=> 1000 FPS).
编辑:还可以考虑更改非常轻的超时(每1ms更新一次<=> 1000 FPS)。