QGraphicsItem.itemClipsChildrenToShape PySide2 中的问题
QGraphicsItem.itemClipsChildrenToShape issue in PySide2
我正在尝试结合使用 PySide2 和 PyQtGraph 创建 Smith 圆图 canvas。
按照上一个问题 (Pyqtgraph clip line) 中的描述,这样做的最佳方法似乎是使用 QGraphicsEllipseItem
绘制外圆,使用 QGraphicsPathItem
和 [=14 绘制所有内弧=],然后将它们添加到外圈并使用 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)
我的代码似乎大部分都在工作,如下图所示。
问题是内弧并没有完全被外圆包围。我原以为剪裁应该是绝对的,这样 children 就不能绘制在 parents 边界之外,但也许情况并非如此?
pyqtGraph 默认创建 cosmetic 笔,这些笔的宽度始终基于它们绘制的设备:如果您指定宽度等于的装饰笔0.5,它将始终具有该大小,无论用于视图的比例如何。
现在,问题的根源可以在关于 QGraphicsItem.shape()
的文档中找到,其中指定:
The outline of a shape can vary depending on the width and style of the pen used when drawing.
Qt 无法知道化妆笔的实际范围(因为它完全取决于绘画设备,并且同一场景可以有 多个 视图,每个视图都有自己的变换. 结果是它根据指定的笔宽计算 shape,even 如果它是化妆品。
由于您使用的值非常小,0.5 的笔宽实际上会变得 非常大,并且形状的范围会因该尺寸而大大增加,这就是它的原因似乎 children 不符合形状:如果你有一个 2x2 的椭圆,使用 0.5 的笔,得到的形状将是一个 2.5x2.5 的椭圆(因为笔的范围是其宽度的一半)。
解决方案是完全忽略 shape()
的默认行为,只使用子类 return 椭圆的形状:
class Ellipse(QGraphicsEllipseItem):
def shape(self):
path = QPainterPath()
path.addEllipse(self.rect())
return path
circle1 = Ellipse(-1, -1, 2, 2)
# ...
我正在尝试结合使用 PySide2 和 PyQtGraph 创建 Smith 圆图 canvas。
按照上一个问题 (Pyqtgraph clip line) 中的描述,这样做的最佳方法似乎是使用 QGraphicsEllipseItem
绘制外圆,使用 QGraphicsPathItem
和 [=14 绘制所有内弧=],然后将它们添加到外圈并使用 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)
我的代码似乎大部分都在工作,如下图所示。
问题是内弧并没有完全被外圆包围。我原以为剪裁应该是绝对的,这样 children 就不能绘制在 parents 边界之外,但也许情况并非如此?
pyqtGraph 默认创建 cosmetic 笔,这些笔的宽度始终基于它们绘制的设备:如果您指定宽度等于的装饰笔0.5,它将始终具有该大小,无论用于视图的比例如何。
现在,问题的根源可以在关于 QGraphicsItem.shape()
的文档中找到,其中指定:
The outline of a shape can vary depending on the width and style of the pen used when drawing.
Qt 无法知道化妆笔的实际范围(因为它完全取决于绘画设备,并且同一场景可以有 多个 视图,每个视图都有自己的变换. 结果是它根据指定的笔宽计算 shape,even 如果它是化妆品。
由于您使用的值非常小,0.5 的笔宽实际上会变得 非常大,并且形状的范围会因该尺寸而大大增加,这就是它的原因似乎 children 不符合形状:如果你有一个 2x2 的椭圆,使用 0.5 的笔,得到的形状将是一个 2.5x2.5 的椭圆(因为笔的范围是其宽度的一半)。
解决方案是完全忽略 shape()
的默认行为,只使用子类 return 椭圆的形状:
class Ellipse(QGraphicsEllipseItem):
def shape(self):
path = QPainterPath()
path.addEllipse(self.rect())
return path
circle1 = Ellipse(-1, -1, 2, 2)
# ...