QGraphicsObject需要显式更新才能重新绘制

2024-06-16 11:00:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个QGraphicsPixmapItem,它的内容随着鼠标点击而改变。当所有交互事件都在派生自QGraphicsPixmapItem的类中处理时,一切都非常好:

import numpy as np
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QApplication, QGraphicsPixmapItem, QGraphicsScene, QGraphicsView, QMainWindow

class MyQGraphicsPixmapItem(QGraphicsPixmapItem):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.setNewImage()

  def setNewImage(self):
    im = np.random.randint(255, size=(256, 256), dtype=np.uint8)
    pix = QPixmap.fromImage(QImage(im, im.shape[1], im.shape[0], QImage.Format_Grayscale8))
    self.setPixmap(pix)

  def mousePressEvent(self, event):
    self.setNewImage()

app = QApplication([])
window = QMainWindow()
window.setGeometry(100, 100, 400, 400)
view = QGraphicsView()
scene = QGraphicsScene()
gpix = MyQGraphicsPixmapItem()
scene.addItem(gpix)
view.setScene(scene)
window.setCentralWidget(view)
window.show()
app.exec()

但是,我不必在类中处理事件,而是希望能够在其他地方处理它们,通常是回调。在this answer中,提供了两个选项:使用QGraphicsObject,或者使用场景事件过滤器,这是强烈建议的,因为前者的权重很大。然而,在AFAIU中,场景事件过滤器使一个图形项目的事件被另一个图形项目处理;我想要一个更一般的QWidget可以处理事件的方法。所以我认为在我的例子中,我需要使用QGraphicsObject

我对上面的脚本做了一个简单的修改,将QGraphicsPixmapItem包装成QGraphicsObject。但是,令我惊讶的是,单击时图像不会刷新

import numpy as np
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QApplication, QGraphicsObject, QGraphicsPixmapItem, QGraphicsScene, QGraphicsView, QMainWindow

class MyQGraphicsObject(QGraphicsObject):

  def __init__(self, gpix):
    super().__init__(gpix)
    self.gpix = gpix
    self.setNewImage()

  def setNewImage(self):
    im = np.random.randint(255, size=(256, 256), dtype=np.uint8)
    pix = QPixmap.fromImage(QImage(im, im.shape[1], im.shape[0], QImage.Format_Grayscale8))
    self.gpix.setPixmap(pix)
    # self.update()  # needs to be uncommented to refresh

  def mousePressEvent(self, event):
    self.setNewImage()

  def boundingRect(self):
    return self.gpix.boundingRect()

  def paint(self, painter, option, widget):
    return self.gpix.paint(painter, option, widget)

app = QApplication([])
window = QMainWindow()
window.setGeometry(100, 100, 400, 400)
view = QGraphicsView()
scene = QGraphicsScene()
opix = MyQGraphicsObject(QGraphicsPixmapItem())
scene.addItem(opix)
view.setScene(scene)
window.setCentralWidget(view)
window.show()
app.exec()

只有手动添加self.update()图像才会刷新。当然,这解决了这个问题,但我有一种感觉,这不应该被需要,我错误地使用了QGraphicsObject。是这样,还是实际需要手册


Tags: fromimportselfviewdefnp事件scene
1条回答
网友
1楼 · 发布于 2024-06-16 11:00:59

调用update()方法是正确的


TL;博士

在哪些情况下需要调用update?

每当开发人员需要调用paint()方法(或小部件上的paintEvent)时

为什么在QGraphicsPixmapItem中不需要调用它,但在QGraphicsObject中却需要调用它?

在QGraphicsPixmap中,正在调用update()方法,您可以验证是否修改了the source code

void QGraphicsPixmapItem::setPixmap(const QPixmap &pixmap)
{
    Q_D(QGraphicsPixmapItem);
    prepareGeometryChange();
    d->pixmap = pixmap;
    d->hasShape = false;
    update();
}

换句话说,在QGraphicsItem中,您不再需要调用它,因为setPixmap方法已经调用了它,而QGraphicsObject没有它,因此有必要调用update()来强制调用paint方法

相关问题 更多 >