Question

QGraphicsPixmapItem, like QGraphicsItem, has a method update(x0, y0, width, height), in order to redraw a pixmap only partly on a QGraphicsScene. Calling this will schedule a paint() (in Qt's event loop) on the QGraphicsItem, and after this paint() is executed the boundingbox (x,y,width,height) will be redrawn to the QGraphcisScene.

The unfortunate part is that there is no way to schedule the paint-event with a boundingbox, meaning that QGraphicsPixmapItem::paint() is forced to repaint the whole QPixmap, therefore reimplementing this paint()-method in a subclass gives no way to only partly update the QPixmap, therefore making a small (local) update to the QPixmap unacceptably slow.

Such a subclass would look something like this:

class LocallyUdatablePixmapItem : public QGraphicsPixmapItem {
private:
    QImage ℑ
public:
    LocallyUdatablePixmapItem(QImage &img) : QGraphicsPixmapItem(), image(img) {}

    paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QStyle *widget) {
         //locall update, unfortunately without a boundig box :( therefore -> slow
    }
};

Another option would be to keep the 'internal QPixmap' of the QGraphicsPixmapItem, and draw the QImage to it partly, like this:

//some initialization of variables
QGraphicsScene scene = ...;
QImage img = ...; //some image data that I wish to manipulate from time to time
QPixmap pixmap  = QPixmap::fromImage(this->shown);
QPainter painter = new QPainter(&this->pixmap);
QGraphicsPixmapItem item = this->addPixmap(this->pixmap);
item->setPixmap(this->pixmap);
//this should not matter, but actually it does, as I will explain shortly
//delete painter;
//painter = new QPainter(item->pixmap());

//For some reason I decide to update (manimulate) img within a small boundigbox
int x0, y0, width, height; //bounding box, assume they are set to whatever is appropriate for the previous update
painter->drawImage (x0, y0, img, x0, y0, width, height);
//now the pixmap is updated, unfortunately the item is not. This does not affect it:
item->update(x0, y0, width, height);
//nor does this:
item->update();
//but this, which makes the whole thing slow, does:
item.setPixmap(&pixmap);

Given I that I needed to set the pixmap to fix it, I assumed it was somehow not set in the initialization, therefore uncommenting the mentioned lines before seemed like a nice idea. Unfortunately, the drawImage() call then segfaults into:

QPaintDevice: Cannot destroy paint device that is being painted

I would like to have an alternative to the "item.setPixmap(&pixmap);", which does not redraw the whole thing, but does work nicely. Any input is very well appreciated :)

Was it helpful?

Solution

Before I propose a solution, a few thoughts:

First, the Graphics View framework is intended to be a solution for displaying many graphic objects, so one large image isn't really that fitting. Of course, I realize your example is probably just a contrived one, so this point might not really apply. Second, since the framework is very transform-centric, it might not make sense to only redraw parts of a QGraphicsItem unless all the transforms are identity, there is no scrolling, etc.

Anyways, if you only want to draw part of a QGraphicsItem, you could simply store the rect that needs to be updated, and access it from inside your paint() method. For example:

CustomItem::setPaintRect(const QRectF &rect)
{
    paintRect = rect;
    update();
}

CustomItem::paint(QPainter *painter /* etc. */)
{
    painter->fillRect(paintRect, brush);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top