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

PyQt5 QTableWidget拖放报错:Trying to construct invalid type

解决PyQt5 QTableWidget拖放文件时的无效类型错误

问题描述

尝试为PyQt5的QTableWidget实现拖放功能时,出现大量类似如下的错误:

Trying to construct an instance of an invalid type, type id: 793994105
Trying to construct an instance of an invalid type, type id: 793011571
Trying to construct an instance of an invalid type, type id: 53299009 
Trying to construct an instance of an invalid type, type id: 339825483
Trying to construct an instance of an invalid type, type id: 846557999
Trying to construct an instance of an invalid type, type id: 594112103
Trying to construct an instance of an invalid type, type id: 694380910
Trying to construct an instance of an invalid type, type id: 863265134
Trying to construct an instance of an invalid type, type id: 842025326
Trying to construct an instance of an invalid type, type id: 858735433
Trying to construct an instance of an invalid type, type id: 891630128
Trying to construct an instance of an invalid type, type id: 624046145
Trying to construct an instance of an invalid type, type id: 610667786

目标是解决该错误,实现拖放PDF等文件时触发print语句。

原始代码

from PyQt5 import QtCore, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(353, 320)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(48, 50, 256, 192))
        self.tableWidget.setAcceptDrops(True)
        self.tableWidget.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.tableWidget.setDefaultDropAction(QtCore.Qt.CopyAction)
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setRowCount(0)

        types = ['text/uri-list']
        types.extend(self.tableWidget.mimeTypes())
        self.tableWidget.mimeTypes = lambda: types

        MainWindow.setCentralWidget(self.centralwidget)
        self.tableWidget.viewport().installEventFilter(self.tableWidget)


    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.Drop and
            event.mimeData().hasUrls()):
            print('Dropped')
            return True
        return super().eventFilter(source, event)

    
if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Window = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(Window)
    Window.show()
    sys.exit(app.exec_())

尝试过的无效方法

直接在Ui类中实现拖放事件方法,无任何效果:

def dragEnterEvent(self, event):
    print('dragged')

def dropEvent(self, event):
    print('dropped')

错误原因

  1. 破坏MIME类型系统:直接替换self.tableWidget.mimeTypes为lambda函数,导致Qt内部无法正确处理拖放的MIME类型,引发无效类型错误。
  2. 事件处理上下文错误:Ui_MainWindow继承自object而非Qt的QObject子类,无法正确处理事件过滤器的super()调用,且直接实现的dragEnterEvent/dropEvent不会被Qt的事件循环触发。
  3. 事件过滤器安装对象错误:将事件过滤器安装到tableWidget本身,但处理逻辑在Ui类中,上下文不匹配。

解决方案

方案一:自定义QTableWidget子类(推荐)

通过继承QTableWidget重写拖放事件,直接处理文件拖放:

from PyQt5 import QtCore, QtWidgets

class CustomTableWidget(QtWidgets.QTableWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
        self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.setDefaultDropAction(QtCore.Qt.CopyAction)
        self.setColumnCount(2)
        self.setRowCount(0)

    def dragEnterEvent(self, event):
        # 仅接受包含文件URL的拖放事件
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
            print('文件已拖入窗口')
        else:
            super().dragEnterEvent(event)

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            # 获取所有拖放的文件路径
            for url in event.mimeData().urls():
                file_path = url.toLocalFile()
                print(f'拖放文件路径:{file_path}')
            event.acceptProposedAction()
            print('文件拖放完成')
        else:
            super().dropEvent(event)

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()

    def setupUi(self):
        self.setObjectName("MainWindow")
        self.resize(353, 320)
        self.centralwidget = QtWidgets.QWidget(self)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = CustomTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(48, 50, 256, 192))
        self.tableWidget.setObjectName("tableWidget")
        self.setCentralWidget(self.centralwidget)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

方案二:使用事件过滤器

在QMainWindow子类中安装事件过滤器,处理表格视口的拖放事件:

from PyQt5 import QtCore, QtWidgets

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()
        # 给表格的视口安装事件过滤器
        self.tableWidget.viewport().installEventFilter(self)

    def setupUi(self):
        self.setObjectName("MainWindow")
        self.resize(353, 320)
        self.centralwidget = QtWidgets.QWidget(self)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(48, 50, 256, 192))
        self.tableWidget.setAcceptDrops(True)
        self.tableWidget.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.tableWidget.setDefaultDropAction(QtCore.Qt.CopyAction)
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setRowCount(0)
        self.tableWidget.setObjectName("tableWidget")
        self.setCentralWidget(self.centralwidget)

    def eventFilter(self, source, event):
        if source == self.tableWidget.viewport():
            if event.type() == QtCore.QEvent.DragEnter:
                if event.mimeData().hasUrls():
                    event.acceptProposedAction()
                    print('文件已拖入窗口')
                    return True
            elif event.type() == QtCore.QEvent.Drop:
                if event.mimeData().hasUrls():
                    for url in event.mimeData().urls():
                        print(f'拖放文件:{url.toLocalFile()}')
                    event.acceptProposedAction()
                    print('文件拖放完成')
                    return True
        return super().eventFilter(source, event)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

效果验证

运行上述任一代码后,拖放PDF或其他文件到表格区域,控制台会打印拖放相关信息,且不会再出现无效类型的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:27:21