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

如何在启用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_())

关键修改说明

  1. dragEnterEvent:新增了event.source() == self的判断,允许内部项的拖放事件进入
  2. dragMoveEvent:内部拖放时设置Qt.MoveAction并接收事件,确保拖放过程中显示正确的光标状态
  3. dropEvent:内部拖放时调用super().dropEvent(event),让QListWidget自己处理项的移动和排序,不需要我们重新实现逻辑

现在运行代码,你会发现既可以正常拖入外部文件,也能拖动内部的项进行重新排序了。

内容的提问来源于stack exchange,提问作者Jie Jenn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 10:22:26