QGraphicsLayoutItem子项拖放事件未触发问题求助
问题解决:QGraphicsItem布局内拖放事件不触发
核心问题诊断
你的代码存在三个关键问题导致拖放事件失效:
- 事件判断逻辑错误:自定义Scene的
dropEvent中直接访问item.setAcceptDrops属性判断是否接收拖放,这是错误的,应该调用item.acceptDrops()方法。 - 事件传递被阻断:
RectGroup设置了setHandlesChildEvents(False),加上QGraphicsLayoutItem的层级关系,导致子项无法接收到拖放事件。 - 子项未发起拖拽:
CustomRect没有实现拖拽启动逻辑,无法触发完整的拖放流程。
修改后的完整代码
from PySide6 import QtCore from PySide6.QtWidgets import * from PySide6.QtGui import QDrag, QMouseEvent class CustomRect(QGraphicsRectItem): def __init__(self, parent=None): super(CustomRect, self).__init__(parent) self.setRect(0.0, 0.0, 80.0, 80.0) self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemSendsGeometryChanges) self.setAcceptDrops(True) def mousePressEvent(self, event): # 启动拖拽流程 if event.button() == QtCore.Qt.LeftButton: drag = QDrag(self) mime_data = QtCore.QMimeData() mime_data.setText(self.parentItem().childItems()[1].widget().text()) drag.setMimeData(mime_data) drag.exec(QtCore.Qt.MoveAction) super().mousePressEvent(event) def dragEnterEvent(self, e): if e.mimeData().hasText(): e.acceptProposedAction() def dropEvent(self, e): # 此处可添加拖放后的位置交换逻辑 source_text = e.mimeData().text() target_text = self.parentItem().childItems()[1].widget().text() print(f"拖放动作:{source_text} → {target_text}") e.acceptProposedAction() class MyProxy(QGraphicsProxyWidget): def dragEnterEvent(self, e): if e.mimeData().hasText(): e.acceptProposedAction() def dropEvent(self, e): # 将事件转发到父组处理 self.parentItem().dropEvent(e) e.acceptProposedAction() def dragMoveEvent(self, e): if e.mimeData().hasText(): e.acceptProposedAction() class RectGroup(QGraphicsItemGroup): def __init__(self, text, parent=None): super(RectGroup, self).__init__(parent) # 移除事件阻断,让子项能正常接收事件 # self.setHandlesChildEvents(False) self.addToGroup(CustomRect()) label = QLabel(text) self.proxy = MyProxy() self.proxy.setAcceptDrops(True) self.proxy.setWidget(label) self.proxy.setPos(30, 30) self.addToGroup(self.proxy) self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemSendsGeometryChanges) self.setAcceptDrops(True) def dropEvent(self, e): # 将事件转发到鼠标位置对应的子项 child = self.itemAt(e.pos()) if child: child.dropEvent(e) e.acceptProposedAction() def dragEnterEvent(self, e): if e.mimeData().hasText(): e.acceptProposedAction() def dragMoveEvent(self, e): if e.mimeData().hasText(): e.acceptProposedAction() class Item(QGraphicsLayoutItem): def __init__(self, graphics_group, parent=None): super(Item, self).__init__(parent) self.gg = graphics_group self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def sizeHint(self, hint, size=QtCore.QSizeF()): return self.gg.boundingRect().size() def setGeometry(self, rect): self.gg.setPos(rect.topLeft()) super().setGeometry(rect) class Container(QGraphicsWidget): def __init__(self, parent=None): super(Container, self).__init__(parent) self.setAcceptDrops(True) self.layout = QGraphicsGridLayout() self.setLayout(self.layout) def add_item(self, item, row, col): self.layout.addItem(item, row, col) class MyScene(QGraphicsScene): def dragEnterEvent(self, e): if e.mimeData().hasText(): e.acceptProposedAction() def dropEvent(self, e): item = self.itemAt(e.scenePos()) # 正确判断目标项是否接受拖放 if item and item.acceptDrops(): try: item.dropEvent(e) except RuntimeError: pass def dragMoveEvent(self, e): if e.mimeData().hasText(): e.acceptProposedAction() class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.central_widget = QWidget(self) central_layout = QHBoxLayout() self.central_widget.setLayout(central_layout) self.setCentralWidget(self.central_widget) self.resize(500, 500) view = QGraphicsView() scene = MyScene() view.setScene(scene) container = Container() scene.addItem(container) for i in range(3): rg = RectGroup(f"foo_{i}", container) f = Item(rg) container.add_item(f, i, 0) central_layout.addWidget(view) app = QApplication([]) main = MainWindow() main.show() app.exec()
关键修改说明
- CustomRect添加拖拽启动逻辑:重写
mousePressEvent,创建QDrag对象并传递MIME数据,触发拖放流程。 - 修正Scene事件判断:用
item.acceptDrops()替代属性访问,正确判断目标项是否接受拖放。 - 调整事件传递路径:移除
RectGroup的setHandlesChildEvents(False),让子项能接收事件;MyProxy的dropEvent转发到父组,父组再转发到对应子项。 - 完善Item类:添加
sizePolicy,确保布局能正确管理项的大小。
内容的提问来源于stack exchange,提问作者n00n
相关产品推荐
相关产品推荐

