PDA

View Full Version : Scaled QGraphicsView incredibely slow if background pixmap large (4000x4000 pixel)



Jocker16
13th January 2010, 12:22
Hello,

following situation:
I have a QGraphicsScene, where the background is a large image (i.e. larger than 4000x4000 pixel).
I've tried several approaches but they are all too slow:
1. Background Pixmap is a QGraphicsPixmapItem at the z-Level -1.
2. QGraphicsScene::drawBackground(...) is used for drawing the background pixmap
3. QGraphicsView::setViewport(new QGLWidget)

Problem with 1 and 2 in scaled mode (scale=0.5): Moving the viewport with the scrollBars takes approximatly 2 seconds (I need almost smooth moving)
Problem with 3: The moving is incredible fast, but the pixmap is completely black (too large???)

I've tried also the following:
QGraphicsView::drawBackground, where I am using a pre calculated transformed pixmap:
void MyGraphicsView::drawBackground( QPainter* pPainter, const QRectF& rect )
{
if ( m_Scale == 1 ) {
QGraphicsView::drawBackground( pPainter, rect );
}
else {
pPainter->resetTransform();
QRectF visibleRect( horizontalScrollBar()->value(), verticalScrollBar()->value(), viewport()->width(), viewport()->height() );
pPainter->drawPixmap( visibleRect, m_ScaledPixmap, visibleRect );
}
}

The problem with this approach is, that the painting has an automatic clipping, and this clipping is set to the scene coordinates.

Anybody a suggestion, how I can draw a precalculated scaled pixmap in the background?

wysota
13th January 2010, 12:47
You have to remember that when you scale, the background has to be rescaled as well which takes time. When you reimplement drawBackground() I don't see you do any scaling. Do you want the background to scale or not? If not, then maybe you should do this instead:


QGraphicsView view;
QPalette p = view.viewport()->palette();
p.setBrush(QPalette::Base, QBrush(QPixmap("mypixmap")));
view.viewport()->setPalette(p);

Jocker16
13th January 2010, 13:52
Why would I usually need to rescale the pixmap? Usually this should work fine:

QGraphicsScene* pScene = new QGraphicsScene();
pScene->addPixmap( "/home/user/myImage.ppm" );
QGraphicsView* view = new QGraphicsView( pScene );
view->scale(0.5, 0.5);

then the view shows of course the scene scaled by 0.5. But if the pixmap is large, the scrolling through the view is far too slow.

Jocker16
13th January 2010, 17:05
Ok I've solved it now ;)
that's the what I needed to do:



void MyGraphicsView::drawBackground( QPainter* pPainter, const QRectF& rect )
{
if ( m_Scale == 1 ) {
QGraphicsView::drawBackground( pPainter, rect );
}
else {
pPainter->resetTransform();
QRectF visibleRect( horizontalScrollBar()->value(), verticalScrollBar()->value(), viewport()->width(), viewport()->height() );
pPainter->drawPixmap( QPoint(0, 0), m_ScaledPixmap, visibleRect );
}
}


m_ScaledPixmap is my pre-scaled pixmap. Naturally it takes some time, until the pre-scaled pixmap is computed, but therefore the scrolling works completely smooth...

wysota
13th January 2010, 17:26
But if the pixmap is large, the scrolling through the view is far too slow.

Because the pixmap has to be scaled each time you repaint it :) At least enable caching of the item (a better approach would be to cut the pixmap into several smaller ones and then enable caching). But I don't see what it has to do with the background...

Jocker16
13th January 2010, 18:18
And which caching should I use? ItemCoordinateCache or DeviceCoordinateCache?
I'm not sure which one is better here.

wysota
13th January 2010, 18:44
It depends whether you will want to scale the item or not. DeviceCoordinateCache will recompute the cache each time the effective scale of the item changes but it will retain full quality of the item.. ItemCoordinateCache will not recompute the cache but quality of the item will degrade.