You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 08:12:04