关于C#:QGraphicsPixmapItem

QGraphicsPixmapItem

QGraphicsPixmapItem与QGraphicsItem一样,具有方法update(x0,y0,width,height),以便仅在QGraphicsScene上部分重绘像素图。调用此函数将在QGraphicsItem上调度一次paint()(在Qt的事件循环中),并且在执行此paint()之后,边界框(x,y,宽度,高度)将重绘到QGraphcisScene。

不幸的是,没有办法使用边界框来计划paint-event,这意味着QGraphicsPixmapItem :: paint()被强制重新绘制整个QPixmap,因此在子类中重新实现此paint()方法可以无法仅部分更新QPixmap,因此对QPixmap进行较小的(本地)更新速度过慢,这是无法接受的。

这样的子类看起来像这样:

1
2
3
4
5
6
7
8
9
10
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
    }
};

另一个选择是保留QGraphicsPixmapItem的"内部QPixmap",并部分向其绘制QImage,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//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);

考虑到我需要设置像素图来修复它,我以为它在初始化中没有设置,因此取消注释前面提到的行似乎是个不错的主意。不幸的是,drawImage()调用随后会分段进入:

QPaintDevice:无法销毁正在绘制的绘制设备

我想替代" item.setPixmap(


在我提出解决方案之前,有几点想法:

首先,Graphics View框架旨在作为一种用于显示许多图形对象的解决方案,因此一个大图像并不是那么合适。当然,我知道您的示例可能只是人为的,因此这一点可能并不适用。其次,由于该框架非常以转换为中心,因此除非所有转换都是同一性,没有滚动等,否则仅重绘QGraphicsItem的一部分可能没有意义。

无论如何,如果只想绘制QGraphicsItem的一部分,则可以简单地存储需要更新的rect,然后从paint()方法内部对其进行访问。例如:

1
2
3
4
5
6
7
8
9
10
CustomItem::setPaintRect(const QRectF &rect)
{
    paintRect = rect;
    update();
}

CustomItem::paint(QPainter *painter /* etc. */)
{
    painter->fillRect(paintRect, brush);
}