如何在启用setAcceptDrops时检测QListWidget内部移动信号?
解决QListWidget自定义拖放后内部移动失效的问题
我明白你遇到的问题了——自定义了QListWidget的拖放事件后,外部文件能拖进来,但内部项的移动功能失效了。这是因为你当前的代码只处理了带有URL的拖放(也就是外部文件),完全忽略了QListWidget内部拖放的mime数据格式,导致内部移动的事件都被你ignore掉了。
修复思路
要同时支持外部文件拖入和内部项移动,我们需要在拖放事件处理中兼顾两种场景:
- 识别内部拖放的标志:拖放来源是当前ListWidget本身(
event.source() == self) - 内部拖放的逻辑交给QListWidget父类处理,不要自行忽略
- 保留原有外部URL拖入的处理逻辑
修改后的完整代码
import sys, os from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QListWidget, \ QVBoxLayout, QHBoxLayout, QAbstractItemView from PyQt5.QtCore import Qt class ListWidget(QListWidget): def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) self.setStyleSheet('''font-size:25px''') def dragEnterEvent(self, event): # 同时允许外部URL拖入 和 内部项拖放 if event.mimeData().hasUrls() or (event.source() == self): event.accept() else: event.ignore() def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.setDropAction(Qt.CopyAction) event.accept() elif event.source() == self: # 内部移动设置为移动动作 event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls(): event.setDropAction(Qt.CopyAction) event.accept() pdfFiles = [] for url in event.mimeData().urls(): if url.isLocalFile(): pdfFiles.append(str(url.toLocalFile())) self.addItems(pdfFiles) elif event.source() == self: # 内部移动交给父类处理,利用QListWidget自带的内部移动逻辑 super().dropEvent(event) else: event.ignore() class AppDemo(QWidget): def __init__(self): super().__init__() self.resize(1200, 800) data = ['Microsoft', 'Facebook', 'Google'] mainLayout = QHBoxLayout() self.lst = ListWidget() self.lst.addItems(data) self.lst.setStyleSheet(''' font-size:30px ''') self.lst.setDragDropMode(QAbstractItemView.InternalMove) mainLayout.addWidget(self.lst) self.setLayout(mainLayout) if __name__ == '__main__': app = QApplication(sys.argv) demo = AppDemo() demo.show() sys.exit(app.exec_())
关键修改说明
- dragEnterEvent:新增了
event.source() == self的判断,允许内部项的拖放事件进入 - dragMoveEvent:内部拖放时设置
Qt.MoveAction并接收事件,确保拖放过程中显示正确的光标状态 - dropEvent:内部拖放时调用
super().dropEvent(event),让QListWidget自己处理项的移动和排序,不需要我们重新实现逻辑
现在运行代码,你会发现既可以正常拖入外部文件,也能拖动内部的项进行重新排序了。
内容的提问来源于stack exchange,提问作者Jie Jenn
相关产品推荐
相关产品推荐

