Search code examples
pythonpyqt5qtablewidgetqlistwidget

pyqt5 override dropEvent python


I am trying to add drag and drop functionality to a small application. Getting data from a QlistWidget and Dropping the data on a QTableWidget. I should override the dropEvent of QTableWidget in order to add some other functions when dropping the data. But i have trouble, i think i can not get the text() of the object gotten from the ListWidget. here is the code:

class Table(QtWidgets.QTableWidget):
    def __init__(self,r,c, parent=None):
        super().__init__(r,c,parent)    
        self.init_ui()

    def init_ui(self):            
        self.setAcceptDrops(True)
        self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)

    """def dragMoveEvent(self, e):            
        e.setDropAction(QtCore.Qt.MoveAction)
        e.accept()

    def dragEnterEvent(self,e):            
        e.accept()"""      



    def dropEvent(self,e):            
        data = e.mimeData()
        a=e.pos()
        row = self.rowAt(a.y())
        col = self.columnAt(a.x())
        self.setItem(row,col,QtWidgets.QTableWidgetItem(data.text()))

        print(row,col)
        print(type(data.text()))
        print(e.source())
        x = data.text()
        print(x)
        e.accept()
`

Solution

  • The data that is transmitted from a QListWidget through the drag-and-drop is not given through text(), because an item has much more information identified by the roles, in addition you can drag several items. The data is transmitted using the MIME type application/x-qabstractitemmodeldatalist and the solution is to decode it as shown below:

    from PyQt5 import QtCore, QtWidgets
    
    
    class TableWidget(QtWidgets.QTableWidget):
        def __init__(self, r,c, parent=None):
            super(TableWidget, self).__init__(r,c, parent)
            self.setAcceptDrops(True)
            self.setDragDropMode(QtWidgets.QAbstractItemView.DropOnly)
    
    
        def dropEvent(self, event):
            md = event.mimeData()
            fmt = "application/x-qabstractitemmodeldatalist"
            if md.hasFormat(fmt):
                encoded = md.data(fmt)
                stream = QtCore.QDataStream(encoded, QtCore.QIODevice.ReadOnly)
                table_items = []
                while not stream.atEnd():
                    # row and column where it comes from
                    row = stream.readInt32()
                    column = stream.readInt32()
                    map_items = stream.readInt32()
                    it = QtWidgets.QTableWidgetItem()
    
                    for i in range(map_items):
                        role = stream.readInt32()
                        value = QtCore.QVariant()
                        stream >> value
                        it.setData(role, value)
                    table_items.append(it)
    
                for it in table_items:
                    print(it, it.text())
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            list_widget = QtWidgets.QListWidget()
            list_widget.setAcceptDrops(False)
            list_widget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
            list_widget.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)
            for i in range(10):
                it = QtWidgets.QListWidgetItem("item-{}".format(i))
                list_widget.addItem(it)
    
            table_widget = TableWidget(5, 10)
            central_widget = QtWidgets.QWidget()
            hlay = QtWidgets.QHBoxLayout(central_widget)
            hlay.addWidget(list_widget)
            hlay.addWidget(table_widget)
            self.setCentralWidget(central_widget)
    
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())