QGraphicsScene.items()仅匹配pos()点而非包含点的问题排查
QGraphicsItemGroup 场景点匹配异常的原因分析
问题描述
现有一个包含多个MyItem项的QGraphicsScene,MyItem是QGraphicsItemGroup,其子项包含一个以局部原点为中心的QGraphicsEllipseItem,所有MyItem在场景中渲染正常。调用scene.items(scene_pos, selection_mode)时出现异常行为:
| selection_mode | 行为 |
|---|---|
Qt.ContainsItemShape | 返回空列表 |
Qt.IntersectsItemShape | 仅当item.pos()==scene_pos时返回该项 |
Qt.ContainsItemBoundingRect | 返回空列表 |
Qt.IntersectsItemBoundingRect | 仅当item.pos()==scene_pos时返回该项 |
即使将scene_pos替换为其周围的小QRectF,结果仍一致。按ItemSelectionMode文档预期,IntersectsItemBoundingRect应返回相交或包含的项,但实际仅匹配pos()点——比如半径100的椭圆父项pos()为(1000,1000),scene_pos(1001,1001)本应在椭圆内,却无法匹配,仅当scene_pos为(1000,1000)时才有效。
核心原因
问题出在QGraphicsItemGroup的默认boundingRect和shape实现上:
QGraphicsItemGroup默认不会自动计算子项的组合边界形状,它的boundingRect()默认只返回一个包含自身原点(即pos()对应的点)的极小矩形,几乎等同于一个点。- 同理,它的
shape()默认也只是一个包含原点的点形状,而非所有子项形状的组合。
这就导致:不管子项的椭圆范围多大,ItemGroup自身的边界和形状都只围绕它的pos()点。所以只有当查询点正好落在ItemGroup的pos()上时,才会被判定为相交或包含;其他位置哪怕在子项椭圆内部,也无法触发匹配逻辑。
解决方法
要让ItemGroup正确响应基于子项的点/区域查询,必须重写它的boundingRect()和shape()方法:
- 重写
boundingRect():遍历所有子项,计算它们在ItemGroup坐标系下的边界,合并成一个包含所有子项的矩形。QRectF MyItem::boundingRect() const override { QRectF groupRect; for (QGraphicsItem *child : childItems()) { groupRect = groupRect.united(child->mapToParent(child->boundingRect()).boundingRect()); } return groupRect; } - 重写
shape():合并所有子项的形状,生成ItemGroup的组合路径。QPainterPath MyItem::shape() const override { QPainterPath groupPath; for (QGraphicsItem *child : childItems()) { groupPath.addPath(child->mapToParent(child->shape())); } return groupPath; }
重写后,scene.items()就能基于子项的实际形状和边界来匹配查询点/区域,符合预期行为。
内容的提问来源于stack exchange,提问作者spraff
相关产品推荐
相关产品推荐

