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

PySide2中QGraphicsView光标在QGraphicsProxyWidget上异常问题咨询

QGraphicsView光标在ProxyWidget上异常的问题分析与解决

问题本质

你遇到的情况是因为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:24:15