PDA

View Full Version : Very slow repainting ofPixmaps in QGraphicsView images



drexiya
21st October 2009, 17:56
Using the QGraphicsView and QGraphicsScene to render pixmaps generated from a QImage. This is on QT 4.4.3.

The pixmaps are generated and placed onto the scene from a QGraphicsItemGroup derived class, and manipulated through the returned QGraphicsPixmapItem*.

The image is a long thin image, that is viewed by scrolling through and I draw graphics path items on.

This works fine on Windows, but experiences major problems in Linux. Scrolling is very slow. Also drawing onto the view is also very slow. In fact, the whole application slows down hugely. This has made the application unusable.

The application appears to be spending very little time generating the pixmaps and painting the QGraphicsItemGroup. The time spent drawing the path items is also insignificant.

It seems that it is redrawing the image itself that is very slow. If I override the GraphicsView::paintEvent function and put a timer in there, this is very slow. (400-800ms)

It this a known problem in Linux? It works fine in Windows. (The same paintEvent takes around 5-15ms max)

Has anyone else experienced this? Is there a workaround for Linux?


Code in : QGraphicsItemGroup - looks like this:

(note: this takes max 2-3 ms)


void BoreholeImage::paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget)
{

if (m_graphicsItem->type() == QGraphicsPixmapItem::Type) {
// We've already loaded the image to display.
QGraphicsItemGroup::paint(painter, option, widget);

// Is there anything to clean up? See below.
if (m_graphicsItemToDelete) {
delete m_graphicsItemToDelete;
m_graphicsItemToDelete = 0;
}

return;
}


m_stream->setSeekPosition(boundingRect().y());
QImage image = m_stream->getImage();
QPixmap pixmap = QPixmap::fromImage(image);
QGraphicsPixmapItem* pixmapItem = scene()->addPixmap(pixmap);
qDebug() << "BoreholeImage" << "pixmap at" << boundingRect().y();
pixmapItem->setPos(0.0, boundingRect().y());
pixmapItem->scale(1.0, boundingRect().height() / pixmap.height());
pixmapItem->setZValue(0.0);

removeFromGroup(m_graphicsItem);
scene()->removeItem(m_graphicsItem);

// Can't delete the unused rectItem here because this routine's caller
// uses it again after this routine returns. Delete it on the next call.
m_graphicsItemToDelete = m_graphicsItem;

m_graphicsItem = pixmapItem;
addToGroup(m_graphicsItem);
QGraphicsItemGroup::paint(painter, option, widget);
}

wysota
21st October 2009, 18:33
QPixmap::fromImage() is a very slow method, try to avoid it. On Windows this is practically a no-op, that's why it's fast there. Cache the data instead of generating it every time you need it. And certainly avoid conversion inside paint(). Adding and removing items inside a paint() routine is a very strange design anyway.

drexiya
21st October 2009, 19:00
Thanks Wysota,

I agree, it is a strange design - one that I inherited.

However, I timed this whole paint() routine as I was worried about the conversions and they are not significant compared to the delay I experience. This whole routine only takes a few ms.

I do cache the images - but only load them as and when needed. . The routine normally returns from the first return statement. However the paintEvent in QGraphicsView takes a long time - even when the pixmaps are cached?? The paint routines for the items within the view are very quick.

This section takes around 1ms on either platform, so I dont think the delay is here:


if (m_graphicsItem->type() == QGraphicsPixmapItem::Type)
{
// We've already loaded the image to display.
QGraphicsItemGroup::paint(painter, option, widget);

// Is there anything to clean up? See below.
if (m_graphicsItemToDelete) {
delete m_graphicsItemToDelete;
m_graphicsItemToDelete = 0;
}

return;
}

The actual painting on the screen seems to be slow, as opposed to the conversions/calculations etc.

wysota
21st October 2009, 19:13
If you have lots of items, then aggregated delay will be significant. Creating and deleting items in paint() is simply broken by design. If you want to find bottlenecks in your application, run it through a profiler. Also if you add an item during paint(), the scene index will have to be recalculated and then paint() will probably be called again if your new item intersects with the group item. So instead of speedup, you get a slowdown.