我正在尝试使用 QGraphicsScene 的给定边界来剪辑 QGraphicsPixmapItem。但是,我认为我并不真正理解剪切的工作原理,据我所知,当您在 QGraphicsPixmapItem 的绘制方法中将 setClipRect 应用于图像时,它应该剪切图像。
我有这个类,它充当查看器:
class ImageViewer(QGraphicsView):
def __init__(self, parent, tab):
super().__init__(parent)
self.setScene(QGraphicsScene(self))
def displayImage(self, image):
rgb_image = image.convert('RGB')
data = rgb_image.tobytes()
qim = QImage(data, rgb_image.size[0], rgb_image.size[1], QImage.Format_RGB888)
pixmap = QPixmap(qim)
self.scene().clear()
scene_rect = QRectF(0, 0, pixmap.width(), pixmap.height())
self.setSceneRect(scene_rect)
pixmapItem = ImagePixmapItem(pixmap, self.sceneRect())
self.scene().addItem(pixmapItem)
self.fitInView(self.sceneRect(), Qt.KeepAspectRatio)
self.drawBorder()
pixmapItem.rotate()
在这里,我有我的图像、QPixmap 并定义了 pixmapItem,它是继承自 QGraphicsPixmapItem 的自定义类。我还画了一个边框只是为了看看我的场景的边界在哪里。
class ImagePixmapItem(QGraphicsPixmapItem):
def __init__(self, pixmap, scene_rect):
super().__init__(pixmap)
self.scene_rect = scene_rect
def paint(self, painter, option, widget):
painter.setClipRect(self.scene_rect)
super().paint(painter, option, widget)
def rotate(self):
self.setTransformOriginPoint(self.boundingRect().center())
rotation_angle = 45
self.setRotation(rotation_angle)
现在,我的图像尺寸为 1000x1000。启动程序后场景的分辨率也为 1000x1000。当我使用旋转方法旋转图像时,理论上,方形图像应该占用比 1000x1000 更多的空间。一旦整个程序启动以及我在场景中滚动或移动,绘图方法就会被调用。我预计 setClipRect 会剪辑我的图像。场景之外的部分不应显示。然而,它根本不起作用。
我被困在这里,不知道问题是什么。
在
paint()
中收到的QPainter已经处于转换项目的上下文中,包括其父级和视图以及其自身的转换。
如果此时调用
painter.drawRect()
,它最终会显示一个 rotated 矩形。这就是为什么使用 setClipRect()
是没有意义的,因为矩形与已经变换的矩阵正交。
一个可能的解决方案是获取实际场景 mapped 到项目变换,并使用
setClipPath()
和包含该映射矩形的 QPainterPath(实际上是 QPolygonF,因为变换也可以具有透视)。
def paint(self, painter, option, widget):
map = self.mapFromScene(self.scene_rect)
path = QPainterPath()
path.addPolygon(map)
painter.setClipPath(path)
super().paint(painter, option, widget)
另一种可能性,正如 ekhumoro 所建议的那样,是添加一个顶级 QGraphicsRectItem 充当剪辑蒙版(通过设置 ItemClipsChildrenToShape
标志),并将所有需要剪辑的元素添加为该项目的子项。最后,只要需要剪切
所有项目,您就可以覆盖drawForeground()
并在所有内容上方绘制一个空心QRegion。这样就根本不需要实现裁剪了。
class ImageViewer(QGraphicsView):
...
def drawForeground(self, qp, rect):
viewRect = self.mapToScene(self.viewport().rect()).boundingRect().toRect()
mask = QRegion(viewRect) - QRegion(self.sceneRect().toRect())
qp.setClipRegion(mask)
qp.fillRect(viewRect, self.palette().base())