Python: How to track ListItems that were drag and dropped from one ListWidget onto another with PyQt

StackOverflow https://stackoverflow.com/questions/22700416

  •  22-06-2023
  •  | 
  •  

Question

There are two ListWidgets with drag-N-drop functionality enabled (example was taken from previous post). When a drop event occurs droppedOnA(arg) and droppedOnA(arg) methods are called. Dragging and dropping from "outside" of dialog window (from a file-browser for example) onto the list widgets works well. But dragging and dropping from-to one listWidget onto another doesn't. Because there is no way to track WHAT items were dropped since the droppedOnA(arg) and droppedOnA(arg) methods receiving no arguments (the way it happens when the dropped items are dragged from "outside" of dialog window. Before I start using a messy approach to get around it I would like to make sure there is no other way to do it. Is there?

from PyQt4 import QtGui, QtCore
import sys, os

class MyClassItem(QtGui.QListWidgetItem):
    def __init__(self, parent=None):
        super(QtGui.QListWidgetItem, self).__init__(parent)       


class ThumbListWidget(QtGui.QListWidget):
    def __init__(self, type, parent=None):
        super(ThumbListWidget, self).__init__(parent)
        self.setIconSize(QtCore.QSize(124, 124))
        self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            super(ThumbListWidget, self).dragEnterEvent(event)

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls():
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
        else:
            super(ThumbListWidget, self).dragMoveEvent(event)

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
            links = []
            for url in event.mimeData().urls():
                links.append(str(url.toLocalFile()))
            self.emit(QtCore.SIGNAL("dropped"), links)
        else:
            event.setDropAction(QtCore.Qt.MoveAction)
            super(ThumbListWidget, self).dropEvent(event)
            self.emit(QtCore.SIGNAL("dropped"))


class Dialog_01(QtGui.QMainWindow):
    def __init__(self):
        super(QtGui.QMainWindow,self).__init__()
        self.listItems={}

        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.listWidgetA = ThumbListWidget(self)
        self.listWidgetB = ThumbListWidget(self)

        for i in range(3):
            listItemAInstance=MyClassItem()
            name='A'+'%04d'%i
            listItemAInstance.setText(name)
            listItemAInstance.setBackgroundColor(QtCore.Qt.darkGray)   
            if i%2: listItemAInstance.setBackgroundColor(QtCore.Qt.gray)

            icon=self.getIcon(name)
            listItemAInstance.setIcon( icon ) 

            self.listWidgetA.addItem(listItemAInstance) 

            listItemBInstance=MyClassItem()
            name='B'+'%04d'%i
            listItemBInstance.setText(name)
            icon=self.getIcon(name)
            listItemBInstance.setIcon( icon )

            if i%2: listItemBInstance.setBackgroundColor(QtCore.Qt.lightGray)
            self.listWidgetB.addItem(listItemBInstance) 

        myBoxLayout.addWidget(self.listWidgetA)      

        myBoxLayout.addWidget(self.listWidgetB)   
        self.connect(self.listWidgetA, QtCore.SIGNAL("dropped"), self.droppedOnA)
        self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.droppedOnB)

        Button_01 = QtGui.QPushButton("Print Dropped Items")
        Button_01.clicked.connect(self.printWhatItemsWereDropped)
        myBoxLayout.addWidget(Button_01)


    def printWhatItemsWereDropped(self):
        print "List of items dropped: "


    def getThumbPath(self, name):
        thumb_dirpath=os.path.expanduser("~")+'/thumbs/' +name+'/'+name+'.jpg'
        return thumb_dirpath

    def getIcon(self, name):
        thumbpath=self.getThumbPath(name)

        if not thumbpath: return
        color='black'
        if os.path.exists( os.path.dirname( thumbpath ) ) == False: os.makedirs( os.path.dirname( thumbpath ) )

        img = QtGui.QImage(64, 64, QtGui.QImage.Format_RGB32)
        img.fill(QtGui.QColor(96,96,96))     

        painter = QtGui.QPainter(img)
        font = painter.font()
        font.setBold(True)
        font.setPointSize(48)

        filename, fileExtension = os.path.splitext( os.path.basename( thumbpath ) )  

        text=filename.upper()
        font.setPointSize(18)        

        painter.setPen(QtGui.QColor(color))
        painter.setFont(font)
        painter.drawText(img.rect(), QtCore.Qt.AlignCenter, text)
        painter.end()
        img.save(thumbpath, 'JPG')

        icon = QtGui.QIcon( thumbpath )
        pixmap = icon.pixmap(64, 64)
        icon = QtGui.QIcon(pixmap)
        return icon


    def droppedOnA(self, arg=None):
        print '\n\t droppedOnA', arg

    def droppedOnB(self, arg=None):
        print '\n\t droppedOnB', arg


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    dialog_1 = Dialog_01()
    dialog_1.show()
    dialog_1.resize(720,480)
    sys.exit(app.exec_())
Was it helpful?

Solution

I already suggested to how to do this in a comment to a previous answer. But anyway, here's a slightly crude implementation which should print a list of the source list-widget name, followed by the dropped indexes.

class ThumbListWidget(QtGui.QListWidget):
    _drag_info = []

    def __init__(self, type, name, parent=None):
        super(ThumbListWidget, self).__init__(parent)
        self.setObjectName(name)
        ...

    def startDrag(self, actions):
        self._drag_info[:] = [str(self.objectName())]
        for item in self.selectedItems():
            self._drag_info.append(self.row(item))
        super(ThumbListWidget, self).startDrag(actions)

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            ...
        elif self._drag_info:
            event.setDropAction(QtCore.Qt.MoveAction)
            super(ThumbListWidget, self).dropEvent(event)
            self.emit(QtCore.SIGNAL("dropped"), list(self._drag_info))

    ...

    self.listWidgetA = ThumbListWidget(self, 'A')
    self.listWidgetB = ThumbListWidget(self, 'B')
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top