I have a timer that triggers paintEvent in every 100ms. I draw a pixmap in paintEvent.
QPainter painter;
painter.begin(this);
painter.drawPixmap(0,0,"mypixmap");
painter.end();
Image pixels being corrupted as the number of paintEvent invocations increases. QT adds additional redundant pixels in paintEvent call.
It can't draw the image on exactly the same pixels in each update.
I tried setting painter anti-aliasing to true but this didn't change the result.
Is there a solution for that problem?
Thanks
Related
Drawing on a widget in Qt is simple. First you create a QPixmap, assign a QPainter to it, draw with the QPainter, and at the end set the pixmap to the widget.
For example,
QPixmap pixmap(ui->label->width(), ui->label->height());
pixmap.fill(background_color);
QPainter painter(&pixmap)
painter.setpen(foreground_color);
//painter.drawLine(....) etc.
ui->label->setPixmap(pixmap);
So far so good.
However, what if the pixmap is very large, and I have to change a very small portion of it very often? In my case I profiled it to be my bottleneck. Instead of creating a new pixmap and copying the old onto it, we can load the existing pixmap and only make the necessary changes to it. However, it is also still very slow.
Pixmap pixmap = *(ui->label->pixmap()); // takes almost zero time
QPainter painter(&pixmap); // takes up 40% of the time
//draw stuff with painter // takes almost zero time
ui->label->setPixmap(pixmap); // takes up 60% of the time
Even if I re-use the painter so that I don't have to create it again every time, I still have to call setPixMap(pixmap), otherwise the image is not refreshed.
Is there a way around it?
Must I embed an OpenGL window or something similar, or is there a way with just using native Qt classes? Note, that the change in the image is very small and takes up an insignificant amount of time, it's the redrawing of the whole pixmap which is time-consuming. As I don't know beforehand where I'll be making the changes, splitting the pixmap up onto multiple small labels would be very complicated.
If you're using a large QLabel, then it would be better using a QGraphicsScene and QGraphicsView.
The scene allows you to add items, and the view is a widget which is like a window looking into the scene.
You could start by adding a QGraphicsPixmapItem, but I think you'd be better off deriving from QGraphicsItem, storing a QPixmap and rendering the image in its paint function.
Here's an example of the derived class header
class MyImage : public QGraphicsItem
{
public:
MyImage(QGraphicsItem* parent);
QRectF boundingRect();
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
protected:
void QGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
private:
QPixmap m_pixmap;
}
In the paint function, use the QPainter to draw m_pixmap;
I would like to draw inside a Qt QFrame, however the QFrame will have a border. As far as I understand, the paintEvent receives a QPainter which is associated to the whole frameRect, so I will have to offset my paint operations of the border. Is this correct? Is there a way of getting a QPainter already associated to the inner part of the widget, without the (variable in size) border?
you have to consider the contentsRect contentsRect()-> Returns the area inside the widget's margins.using the return value rect of contensRect() you can restrict to draw anything inside the rect.
One way to do this would be to embed a QWidget inside the QFrame, place it in a simple QVBoxLayout layout or QStackedLayout layout with no margins and paint the QWidget instead. You'll probably get better performance if you simply offset your painting, though.
How to get the font metrics of a QPainter outside paintEvent drawing method? I would need this before painting on the screen.
If you need to do text layout outside of your paint event, just create a QFontMetrics from the font you will be using.
The Scenario is I am getting Rects of Images over the socket and I need to draw it in a Scrollable Canvas. at the moment I am using a QGraphicsScene and drawing using QGraphicsPixmapItem but after few times when one pixmap overlaps another there is no need to keep the bottom one. and I dont know any simple way to find out the overlapped item and delete it. so its supposed to take huge memory if overlapping goes on like this.
there exists another way out. Make a QWidget and put it in a QScrollArea now draw the QWidget using a QPainter (outside paintEvent ?). If I draw it outside paintEvent I need to inherit the QWidget and make a custom one. pass it a Pixmap and let it draw in its own paintEvent by calling update()
Any critiques ? any other Straight forward solutions there ?
I am new to QT. i am working on the Graphics.
i am using QWidget for drawing graphics(For drawing graphics in QWidget paint event). i need to draw background and foreground graphics. Background is fixed graphics. foregrounds i am drawing lines.
Each 100 millisecond i need to draw 20points. This drawing time is 8 sec. Total i need to draw 1600 points (total points represents the contentious line).
i am using QTimer to invoke this drawing in each 100ms. first few drawing drawn very fast. in the middle of the drawing it's become slow.
the problem is i need to draw all the foreground and background in each 100ms.
Please help me to fix the problem. if any one have sample code please provide. Thanks in advance.
Is there any way to draw only partial area ie. only particular modified region of the graphics?
QPainter-drawing can be very slow without hardware support. Using QGraphicsView won't help if all lines are visible, since it internally uses QPainter anyway.
If you just have to draw 20 new points (or lines) per update and per update background gets cleared so you have to render everything again, there are few things you could try:
1) Disable background autofill. See: QWidget::autoFillBackground
Add something like this to your widget init:
setAutoFillBackground(false);
setAttribute(Qt::WA_OpaquePaintEvent, true);
setAttribute(Qt::WA_NoSystemBackground, true);
Now on the first update render background and first lines. For next updates just skip rendering background and render only new lines.
2) Use double buffering. For example, create QImage of the size of your widget.
.h
private:
QImage m_targetImage;
.cpp
// constructor
m_targetImage = QImage(width(), height(), QImage::Format_ARGB32);
// paint event
// draw to image
QPainter p;
p.begin(&m_targetImage);
static bool firstUpdate = true;
if (firstUpdate)
{
// draw background)
p.drawImage(...);
firstUpdate = false;
}
// draw latest lines
p.drawLines(....);
p.end();
// draw image in widget paint
QPainter painter;
painter.begin(this);
painter.drawImage(0, 0, m_targetImage);
painter.end();
3) Use QGLWidget if possible. Inherit your widget from QGLWidget instead of QWidget. This method doesn't work on all platforms and speed increase might not be enough. Also using OpenGL brings all kind of new problems.