如何根据QGraphicsScene形状裁剪QGraphicsPixmapItem?
问题原因与解决方案
问题根源
你在ImagePixmapItem的paint方法中直接使用场景坐标系的scene_rect调用painter.setClipRect(),但此时painter已经应用了item的旋转变换,坐标系已发生偏移,导致裁剪区域和预期的场景边界不匹配,所以无法正确裁剪超出场景的部分。
解决方案1:转换坐标系后设置裁剪(推荐)
修改ImagePixmapItem的paint方法,将场景矩形转换为item局部坐标系下的矩形,再设置裁剪区域:
class ImagePixmapItem(QGraphicsPixmapItem): def __init__(self, pixmap, scene_rect): super().__init__(pixmap) self.scene_rect = scene_rect def paint(self, painter, option, widget): # 将场景坐标系的矩形转换为item局部坐标系下的矩形 scene_rect_in_item = self.mapFromScene(self.scene_rect).boundingRect() painter.setClipRect(scene_rect_in_item) super().paint(painter, option, widget) def rotate(self): self.setTransformOriginPoint(self.boundingRect().center()) rotation_angle = 45 self.setRotation(rotation_angle)
原理:mapFromScene()方法会把场景坐标系中的矩形转换为item自身的局部坐标系,此时设置的裁剪区域会和场景边界精准对应,旋转后超出场景的部分会被正确裁剪。
解决方案2:在视图层面全局裁剪
如果希望整个视图只显示场景范围内的内容,也可以直接在ImageViewer中重写paintEvent,在视图层面实现裁剪:
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() def paintEvent(self, event): painter = QPainter(self.viewport()) # 将场景矩形转换为视图坐标系下的矩形 view_clip_rect = self.mapFromScene(self.sceneRect()).boundingRect() painter.setClipRect(view_clip_rect) super().paintEvent(event)
这种方式无需修改item的代码,所有超出场景边界的内容都会被视图裁剪掉。
内容的提问来源于stack exchange,提问作者ajfeuak
相关产品推荐
相关产品推荐

