0

I am a beginner and I am working on a tool where users could rearrange row of files in a table widget with 2 columns.

Problem is when drag and dropping a row, the target gets deleted.

I found a solution in: Drag and drop rows within QTableWidget

But I could not seem to make it work on my code. Can someone point me where I should start? I couldn't understand where i should add the layout and the drag and drop event class.

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_())
    ```


Frederick
  • 117
  • 2
  • 9
  • 1
    You should use the subclass used in the answer (TableWidgetDragRows), instead of the basic QTableWidget. Note that you should **never** edit the output of `pyuic`, but use those files as explained in the official guide about [using Designer](https://www.riverbankcomputing.com/static/Docs/PyQt5/designer.html). – musicamante Jun 11 '20 at 15:13
  • Thanks @musicamante. So that means I need to make a separate subclass for the table widget right? For this part of his code: ``` layout = QHBoxLayout() self.setLayout(layout) self.table_widget = TableWidgetDragRows() layout.addWidget(self.table_widget) ``` I am not sure where to add this in my current code. – Frederick Jun 11 '20 at 16:17
  • In the example you've provided, yes. But, as said, you should *not* use that code (nor try to mimic it). Since you're using a very basic interface, I'd suggest to look for some tutorials on how to manually create a PyQt interface. You can still use a custom subclass in Designer, but that would require you to "promote" the QTableWidget you're using there (look for resources about "promoting QWidget"). – musicamante Jun 11 '20 at 16:36
  • Thank you @musicamante! I finally fixed it by promoting my tablewidget in designer. It gave me the idea that I just had to import the subclass. – Frederick Jun 12 '20 at 15:32
  • Further question though. If I convert my current python file into an executable file. How do I process the imported sub class? It's easy when they are just python files since they just need to be in the same folder. How does that work when the python file gets converted to an executable file? does it automatically import the subclass also into the file? – Frederick Jun 12 '20 at 15:43

1 Answers1

1

Fixed it. Had to promote my table widget and import the TableWidgetDragRows class here: 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_())
    ```
Frederick
  • 117
  • 2
  • 9