PySide2中QGraphicsView光标在QGraphicsProxyWidget上异常问题咨询
问题本质
你遇到的情况是因为QGraphicsProxyWidget的光标优先级高于QGraphicsView的viewport——哪怕你给内部的QLabel加了WA_TransparentForMouseEvents,ProxyWidget本身还是会处理光标相关的事件逻辑,会覆盖你在mouseReleaseEvent里给viewport设置的箭头光标。另外,当鼠标离开ProxyWidget时,QGraphicsView的ScrollHandDrag模式会自动恢复手型光标,而你的释放事件没有拦截这个默认行为,所以才会出现离开后反而显示手型的情况。
可行的解决方案
我给你几个按推荐程度排序的解决办法:
1. 强制同步所有ProxyWidget的光标
在QGraphicsView的mouseReleaseEvent里,除了设置viewport的光标,还遍历场景里的所有ProxyWidget,把它们的光标也改成箭头:
def mouseReleaseEvent(self, event): QGraphicsView.mouseReleaseEvent(self, event) target_cursor = Qt.ArrowCursor self.viewport().setCursor(target_cursor) # 遍历场景里的ProxyWidget,强制同步光标 for item in self.main_scene.items(): if isinstance(item, QGraphicsProxyWidget): item.setCursor(target_cursor)
这个方法最简单直接,能一次性解决所有ProxyWidget的光标冲突问题。
2. 自定义ProxyWidget处理光标事件
如果不想遍历所有Item,可以写一个自定义的QGraphicsProxyWidget,在它的鼠标释放和hover离开事件里主动同步viewport的光标:
class CustomProxy(QGraphicsProxyWidget): def __init__(self, parent=None): super().__init__(parent) def mouseReleaseEvent(self, event): super().mouseReleaseEvent(event) # 获取当前场景关联的视图 view = self.scene().views()[0] view.viewport().setCursor(Qt.ArrowCursor) self.setCursor(Qt.ArrowCursor) def hoverLeaveEvent(self, event): super().hoverLeaveEvent(event) view = self.scene().views()[0] view.viewport().setCursor(Qt.ArrowCursor) self.setCursor(Qt.ArrowCursor)
然后在你的InfoBox里替换原来的ProxyWidget:
proxy = CustomProxy(self) widget = QLabel("TEST!") widget.setAttribute(Qt.WA_TransparentForMouseEvents) proxy.setWidget(widget)
这个方式更精准,只针对你创建的ProxyWidget生效。
3. 补充QGraphicsView的hover事件处理
除了mouseReleaseEvent,还要在视图的hover进入和离开事件里做光标重置,确保鼠标在ProxyWidget上时也能显示箭头:
def hoverEnterEvent(self, event): super().hoverEnterEvent(event) # 检查鼠标是否落在ProxyWidget或其子项上 hover_item = self.itemAt(event.pos()) while hover_item: if isinstance(hover_item, QGraphicsProxyWidget): self.viewport().setCursor(Qt.ArrowCursor) break hover_item = hover_item.parentItem() def hoverLeaveEvent(self, event): super().hoverLeaveEvent(event) self.viewport().setCursor(Qt.ArrowCursor)
这个方法能覆盖鼠标在ProxyWidget上的所有场景,包括hover状态下的光标显示。
为什么之前的设置无效?
你给QLabel加的WA_TransparentForMouseEvents只是让QLabel不处理鼠标事件,但QGraphicsProxyWidget本身还是会响应hover和鼠标释放事件,它的光标设置会优先于viewport的。而且当鼠标离开ProxyWidget时,QGraphicsView的ScrollHandDrag模式会自动切换回手型光标,这个默认行为没有被你的mouseReleaseEvent覆盖,所以才会出现离开后显示手型的情况。
内容的提问来源于stack exchange,提问作者EVRR

