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')
错误原因
- 破坏MIME类型系统:直接替换
self.tableWidget.mimeTypes为lambda函数,导致Qt内部无法正确处理拖放的MIME类型,引发无效类型错误。 - 事件处理上下文错误:
Ui_MainWindow继承自object而非Qt的QObject子类,无法正确处理事件过滤器的super()调用,且直接实现的dragEnterEvent/dropEvent不会被Qt的事件循环触发。 - 事件过滤器安装对象错误:将事件过滤器安装到
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
相关产品推荐
相关产品推荐

