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

如何为包含子路径的QGraphicsPolygonItem设置正确的Shape?

问题描述

尝试绘制一个带有若干连接点的多边形,但在设置其Shape时,路径中出现了CircleItem的偏移阴影效果,这并非预期结果。

原代码

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import pyqtSignal as Signal
from PyQt5.QtCore import pyqtProperty as Property
from PyQt5.QtNetwork import *

class CircleItem(QGraphicsPathItem):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        # self.setFlags(QGraphicsItem.ItemIsMovable|QGraphicsItem.ItemIsSelectable)
        self.setBrush(Qt.red)

        path = QPainterPath()
        path.addEllipse(-20, -20, 40, 40)
        self.setPath(path)

class PolyItem(QGraphicsPolygonItem):
    def __init__(self):
        super().__init__()

        poly = QPolygonF([
            QPointF(200, 0),
            QPointF(120, 150)
        ])

        self.circles = []
        for pt in poly:
            c = CircleItem(self)
            c.setPos(pt)
            self.circles.append(c)

        self.setPolygon(poly)

    def shape(self) -> QPainterPath:
        path = QPainterPath()
        path.addPolygon(self.polygon())

        for c in self.circles:
            path.addPath(c.path())

        return path

    def boundingRect(self) -> QRectF:
        return self.shape().boundingRect()

    def paint(self, painter: QPainter, option: 'QStyleOptionGraphicsItem', widget) -> None:
        painter.drawRect(self.boundingRect())

        painter.setPen(Qt.blue)
        painter.drawPath(self.shape())
        return super().paint(painter, option, widget)

class View(QGraphicsView):
    def __init__(self):
        super().__init__()
        pl = PolyItem()
        self.setScene(QGraphicsScene())
        self.scene().addItem(pl)

if __name__ == '__main__':
    app = QApplication([])
    win = View()
    win.show()
    app.exec()

运行结果

运行结果截图

解决方案

问题根源有两点:

  • shape方法中直接添加CircleItem的路径时,未将子项的局部路径转换为父项坐标系下的路径,导致路径位置偏移,出现错位阴影。
  • paint方法额外绘制了shape路径,和子项CircleItem的自动绘制产生重叠。

修正后的代码

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import pyqtSignal as Signal
from PyQt5.QtCore import pyqtProperty as Property
from PyQt5.QtNetwork import *

class CircleItem(QGraphicsPathItem):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        # self.setFlags(QGraphicsItem.ItemIsMovable|QGraphicsItem.ItemIsSelectable)
        self.setBrush(Qt.red)

        path = QPainterPath()
        path.addEllipse(-20, -20, 40, 40)
        self.setPath(path)

class PolyItem(QGraphicsPolygonItem):
    def __init__(self):
        super().__init__()

        poly = QPolygonF([
            QPointF(200, 0),
            QPointF(120, 150)
        ])

        self.circles = []
        for pt in poly:
            c = CircleItem(self)
            c.setPos(pt)
            self.circles.append(c)

        self.setPolygon(poly)

    def shape(self) -> QPainterPath:
        path = QPainterPath()
        path.addPolygon(self.polygon())

        for c in self.circles:
            # 将CircleItem的局部路径转换为父项坐标系下的路径
            path.addPath(c.path().translated(c.pos()))

        return path

    def boundingRect(self) -> QRectF:
        return self.shape().boundingRect()

    def paint(self, painter: QPainter, option: 'QStyleOptionGraphicsItem', widget) -> None:
        painter.drawRect(self.boundingRect())

        # 移除重复的shape绘制,子项会自动完成自身渲染
        # painter.setPen(Qt.blue)
        # painter.drawPath(self.shape())
        return super().paint(painter, option, widget)

class View(QGraphicsView):
    def __init__(self):
        super().__init__()
        pl = PolyItem()
        self.setScene(QGraphicsScene())
        self.scene().addItem(pl)

if __name__ == '__main__':
    app = QApplication([])
    win = View()
    win.show()
    app.exec()

说明

  1. 在shape方法中,通过c.path().translated(c.pos())将CircleItem的局部路径平移到它在PolyItem中的实际位置,确保碰撞检测路径的准确性。
  2. 注释掉paint方法中绘制shape的代码,依赖子项的自动绘制避免重复渲染,消除错位阴影。

内容的提问来源于stack exchange,提问作者jett chen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:47:54