PYQT5 拖放行在 TableWidget 中未按预期工作

Posted

技术标签:

【中文标题】PYQT5 拖放行在 TableWidget 中未按预期工作【英文标题】:PYQT5 Drag and Drop Rows not Working as intended inside TableWidget 【发布时间】:2020-06-11 14:59:10 【问题描述】:

我是一名初学者,我正在开发一种工具,用户可以在其中重新排列具有 2 列的表格小部件中的文件行。

问题是当拖放一行时,目标被删除。

我找到了解决方案:Drag and drop rows within QTableWidget

但我似乎无法让它在我的代码上运行。有人可以指出我应该从哪里开始吗?我不明白应该在哪里添加布局和拖放事件类。

from PyQt5 import QtCore, QtGui, QtWidgets 
from PyQt5.QtGui import QIntValidator, QDropEvent
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QTableWidget, QAbstractItemView, QTableWidgetItem, QWidget, QHBoxLayout, QApplication
from PyQt5.QtCore import QSettings, Qt
from pathlib import Path
import os


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(647, 564)
        MainWindow.setAutoFillBackground(False)
        MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_4.setGeometry(QtCore.QRect(190, 130, 81, 31))
        self.pushButton_4.setStyleSheet("background-color: rgb(0, 255, 127);")
        self.pushButton_4.setObjectName("Browse")
        self.pushButton_4.clicked.connect(self.browseFiles)
        self.tableWidget_2 = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget_2.setGeometry(QtCore.QRect(300, 20, 321, 391))
        self.tableWidget_2.setAutoFillBackground(True)
        self.tableWidget_2.setFrameShape(QtWidgets.QFrame.Box)
        self.tableWidget_2.setEditTriggers(QtWidgets.QAbstractItemView.AnyKeyPressed|QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed|QtWidgets.QAbstractItemView.SelectedClicked)
        self.tableWidget_2.setDragEnabled(True)
        self.tableWidget_2.setAcceptDrops(True)
        self.tableWidget_2.viewport().setAcceptDrops(True)
        self.tableWidget_2.setDragDropOverwriteMode(False)
        self.tableWidget_2.setDropIndicatorShown(True)
        self.tableWidget_2.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
        self.tableWidget_2.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.tableWidget_2.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
        self.tableWidget_2.setAlternatingRowColors(True)
        self.tableWidget_2.setIconSize(QtCore.QSize(5, 5))
        self.tableWidget_2.setObjectName("tableWidget_2")
        self.tableWidget_2.setColumnCount(2)
        self.tableWidget_2.setRowCount(0)
        self.tableWidget_2.setHorizontalHeaderLabels(["Filename","Page Count"])
        self.tableWidget_2.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
        self.pushButton_4.raise_()
        self.tableWidget_2.raise_()
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton_4.setText(_translate("MainWindow", "Browse"))

    def browseFiles(self):
        self.pdfFiles = []
        lastPath = ""
        numRows = self.tableWidget_2.rowCount()
        options = QFileDialog.Options()
#        options |= QFileDialog.DontUseNativeDialog
        files, _ = QFileDialog.getOpenFileNames(MainWindow,"Select File(s)", "","Files (*.*)", options=options)
        for file in files:
            self.tableWidget_2.insertRow(numRows)
            self.tableWidget_2.setItem(numRows, 0, QtWidgets.QTableWidgetItem(file))
        if len(self.pdfFiles) > 0:
            lastPath = os.path.dirname(os.path.abspath(str(files)))
            self.lineEdit_3.setText(lastPath)
            self.disableButton()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)    
    MainWindow.show()
    MainWindow.setWindowTitle("ARCMAP")
    sys.exit(app.exec_())
    ```


【问题讨论】:

您应该使用答案中使用的子类 (TableWidgetDragRows),而不是基本的 QTableWidget。请注意,您应该永远不要编辑pyuic 的输出,而是按照有关using Designer 的官方指南中的说明使用这些文件。 谢谢@musicamante。所以这意味着我需要为表格小部件创建一个单独的子类,对吗?对于他的这部分代码:``` layout = QHBoxLayout() self.setLayout(layout) self.table_widget = TableWidgetDragRows() layout.addWidget(self.table_widget) ```我不确定在我当前的位置添加这个代码。 在您提供的示例中,是的。但是,如前所述,您应该使用该代码(也不要试图模仿它)。由于您使用的是非常基本的界面,因此我建议您查找一些有关如何手动创建 PyQt 界面的教程。您仍然可以在 Designer 中使用自定义子类,但这需要您“提升”您在那里使用的 QTableWidget(查找有关“提升 QWidget”的资源)。 谢谢@musicamante!我终于通过在设计师中推广我的表格小部件来修复它。它给了我一个想法,我只需要导入子类。 还有一个问题。如果我将当前的 python 文件转换为可执行文件。如何处理导入的子类?当它们只是 python 文件时很容易,因为它们只需要在同一个文件夹中。当 python 文件转换为可执行文件时,它是如何工作的?它会自动将子类也导入文件吗? 【参考方案1】:

修复它。必须在此处推广我的表格小部件并导入 TableWidgetDragRows 类:Drag and drop rows within QTableWidget。

from PyQt5 import QtCore, QtGui, QtWidgets 
from PyQt5.QtGui import QIntValidator, QDropEvent
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QTableWidget, QAbstractItemView, QTableWidgetItem, QWidget, QHBoxLayout, QApplication
from PyQt5.QtCore import QSettings, Qt
from pathlib import Path
import os

#import the tableWidgetDragRows in the link
from tablewidgetdragrows import TableWidgetDragRows


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(647, 564)
        MainWindow.setAutoFillBackground(False)
        MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_4.setGeometry(QtCore.QRect(190, 130, 81, 31))
        self.pushButton_4.setStyleSheet("background-color: rgb(0, 255, 127);")
        self.pushButton_4.setObjectName("Browse")
        self.pushButton_4.clicked.connect(self.browseFiles)
#edit the tableWidget from default to the imported sub class
        self.tableWidget_2 = TableWidgetDragRows(self.centralwidget)
        self.tableWidget_2.setGeometry(QtCore.QRect(300, 20, 321, 391))
        self.tableWidget_2.setAutoFillBackground(True)
        self.tableWidget_2.setFrameShape(QtWidgets.QFrame.Box)
        self.tableWidget_2.setEditTriggers(QtWidgets.QAbstractItemView.AnyKeyPressed|QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed|QtWidgets.QAbstractItemView.SelectedClicked)
#remove all drag and drop functions from your table widget so it would inherit from the imported subclass
#        self.tableWidget_2.setDragEnabled(True)
#        self.tableWidget_2.setAcceptDrops(True)
#        self.tableWidget_2.viewport().setAcceptDrops(True)
#        self.tableWidget_2.setDragDropOverwriteMode(False)
#        self.tableWidget_2.setDropIndicatorShown(True)
#        self.tableWidget_2.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
#        self.tableWidget_2.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
#        self.tableWidget_2.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
        self.tableWidget_2.setAlternatingRowColors(True)
        self.tableWidget_2.setIconSize(QtCore.QSize(5, 5))
        self.tableWidget_2.setObjectName("tableWidget_2")
        self.tableWidget_2.setColumnCount(2)
        self.tableWidget_2.setRowCount(0)
        self.tableWidget_2.setHorizontalHeaderLabels(["Filename","Page Count"])
        self.tableWidget_2.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
        self.pushButton_4.raise_()
        self.tableWidget_2.raise_()
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton_4.setText(_translate("MainWindow", "Browse"))

    def browseFiles(self):
        self.pdfFiles = []
        lastPath = ""
        numRows = self.tableWidget_2.rowCount()
        options = QFileDialog.Options()
#        options |= QFileDialog.DontUseNativeDialog
        files, _ = QFileDialog.getOpenFileNames(MainWindow,"Select File(s)", "","Files (*.*)", options=options)
        for file in files:
            self.tableWidget_2.insertRow(numRows)
            self.tableWidget_2.setItem(numRows, 0, QtWidgets.QTableWidgetItem(file))
        if len(self.pdfFiles) > 0:
            lastPath = os.path.dirname(os.path.abspath(str(files)))
            self.lineEdit_3.setText(lastPath)
            self.disableButton()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)    
    MainWindow.show()
    MainWindow.setWindowTitle("ARCMAP")
    sys.exit(app.exec_())
    ```

【讨论】:

以上是关于PYQT5 拖放行在 TableWidget 中未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

如何保存编辑的 PyQt5 TableWidget 单元格?

pyqt5-tablewidget 尾部添加行列

pyqt5-tablewidget 尾部添加行列

PYQT5 QTableWidget详细用法

在两个单独的 QTableWidgets 之间拖放行

Qtablewidget 去除黑色空间 PyQt5