PySide2 中的 QGraphicsItem.itemClipsChildrenToShape 问题

Posted

技术标签:

【中文标题】PySide2 中的 QGraphicsItem.itemClipsChildrenToShape 问题【英文标题】:QGraphicsItem.itemClipsChildrenToShape issue in PySide2 【发布时间】:2021-11-16 21:56:54 【问题描述】:

我正在尝试使用 PySide2 和 PyQtGraph 的组合创建史密斯圆图画布。 如上一个问题 (Pyqtgraph clip line) 中所述,执行此操作的最佳方法似乎是使用QGraphicsEllipseItem 绘制外圆,使用QGraphicsPathItemQPainterPath 绘制所有内弧,然后将它们添加到外圈并使用ItemClipsChildrenToParent 夹住它们。

这是我的代码:

rline = [0.2, 0.5, 1.0, 2.0, 5.0]
xline = [0.2, 0.5, 1, 2, 5]

circle1 = QGraphicsEllipseItem(-1, -1, 2, 2)
circle1.setPen(mkPen('b', width=0.5))
circle1.setFlag(circle1.ItemClipsChildrenToShape)

pathItem = QGraphicsPathItem()
path = QPainterPath()
path.moveTo(1, 0)

for r in rline:
    raggio = 1./(1+r)
    path.addEllipse(1, -raggio, -raggio*2, raggio*2)

for x in xline:
    path.arcTo(1-x, 0, x*2, x*2, 90, 180)
    path.moveTo(1, 0)
    path.arcTo(1-x, 0, x*2, -x*2, 90, 180)

pathItem.setPath(path)
pathItem.setPen(mkPen('b', width = 0.5))
pathItem.setParentItem(circle1)

如下图所示,我的代码似乎大部分都在工作。

问题是内圆弧并没有完全被外圆约束。我原以为剪裁应该是绝对的,这样孩子们就不能在父母的界限之外画画,但也许不是这样?

【问题讨论】:

【参考方案1】:

pyqtGraph 默认创建 cosmetic 笔,这些笔的宽度始终基于它们绘制的设备:如果您指定宽度等于 0.5 的化妆笔,它将 总是不管视图使用的比例是多少。

现在,问题的根源可以在有关QGraphicsItem.shape()的文档中找到,其中指定:

形状的轮廓可能会因绘图时使用的笔的宽度和样式而异。

Qt 无法知道化妆笔的实际范围(因为它完全依赖于绘图设备,并且同一个场景可以有多个视图,每个视图都有自己的变换。结果是它根据指定的笔宽计算 shape,如果是装饰性的 even

由于您使用的值非常小,因此 0.5 笔宽度实际上变得非常大,并且形状的范围大大增加了该尺寸,这就是为什么看起来孩子们不考虑形状:如果您有一个 2x2 的椭圆,使用 0.5 的笔,生成的形状将是一个 2.5x2.5 的椭圆(因为笔的范围是其宽度的一半)。

解决办法是完全忽略shape()的默认行为,只使用子类返回椭圆的形状:

class Ellipse(QGraphicsEllipseItem):
    def shape(self):
        path = QPainterPath()
        path.addEllipse(self.rect())
        return path

circle1 = Ellipse(-1, -1, 2, 2)
# ...

【讨论】:

以上是关于PySide2 中的 QGraphicsItem.itemClipsChildrenToShape 问题的主要内容,如果未能解决你的问题,请参考以下文章

如何断开 PySide2 中的按钮单击信号?

Qt 获取QGraphicsItem在屏幕上的位置,在QGraphicsItem中获取全局位置,转换为screenPos

从 QGraphicsItem 上的上下文菜单操作中获取事件

PySide/PyQT5:如何从 QGraphicsItem 发出信号?

使用 PyInstaller 打包后 PySide2 应用程序中的路径错误

父子QGraphicsItem绘图示例,及与ros中rviz的不同