PyQt5父子QGraphicsItem悬停事件独立触发方案问询
解决QGraphicsRectItem父子项悬停事件独立与同步移动问题
问题分析
- 悬停事件触发父项的原因:QGraphicsItem的事件默认会向上传递给父级,你的代码中调用了
super().hoverEnterEvent(event)和super().hoverLeaveEvent(event),这会让事件继续传播到父项,导致父项的悬停事件被触发。 - 子项直接加场景导致移动异常:QGraphicsItem如果设置了父项,绝对不能再手动添加到场景,父项会自动管理子项的场景归属和坐标变换。直接添加子项到场景会破坏父子间的坐标依赖,移动父项时子项的位置计算会出错。
解决方案
1. 阻止悬停事件向上传播
在子类的悬停事件处理函数中,不要调用父类的对应方法,或者调用event.accept()明确终止事件传播,这样子项的悬停事件就不会触发父项的事件。
2. 正确设置父子与场景的关系
只需要将父项添加到场景,子项通过父项的构造函数设置父关系后,会自动成为场景的一部分,无需单独调用scene.addItem()添加子项。
修改后的代码示例
import sys from PyQt5 import QtCore, QtWidgets, QtGui class HoverRectItem(QtWidgets.QGraphicsRectItem): def __init__(self, x, y, width, height, parent=None, fill=QtCore.Qt.blue, highlight=QtCore.Qt.red, name=''): super().__init__(x, y, width, height, parent=parent) self.fill_brush = QtGui.QBrush(QtGui.QColor(fill)) self.hover_brush = QtGui.QBrush(QtGui.QColor(highlight)) self.setBrush(self.fill_brush) self.name = name self.setAcceptHoverEvents(True) def hoverEnterEvent(self, event): print(f"{self.name} hover enter") self.setBrush(self.hover_brush) self.update() # 阻止事件向上传播 event.accept() def hoverLeaveEvent(self, event): print(f"{self.name} hover leave") self.setBrush(self.fill_brush) self.update() # 阻止事件向上传播 event.accept() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) scene = QtWidgets.QGraphicsScene() # 创建父项并添加到场景 central_rect = HoverRectItem(0, 0, 100, 50, parent=None, name='central') scene.addItem(central_rect) central_rect.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable) # 创建子项,仅设置父关系,无需添加到场景 input_rect = HoverRectItem(-30, 0, 20, 50, parent=central_rect, name='input') output_rect = HoverRectItem(110, 0, 20, 50, parent=central_rect, name='output') view = QtWidgets.QGraphicsView(scene) view.setWindowTitle("QGraphicsItem Hover Example") view.show() app.exec_()
关键改动说明
- 移除了悬停事件中的
super()调用,改用event.accept()终止事件传播,确保子项悬停不会触发父项的对应事件,实现悬停独立。 - 删除了子项的
scene.addItem()调用,子项通过父子关系自动加入场景,保证父项移动时子项的坐标变换完全同步,解决运动状态异常问题。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

