title: How to Drag and Drop from One QListWidget to Another
body: <p>There are two QListWIdgets sitting in a same dialog window. The DragDrop functionality has been enabled for both. If I drag and drop a file to any of two ListWidges the program recognizes it and prints out the list of the files dropped. But aside from drag and dropping files I would like to be able to drag and drop the List widget Items from one to another. If I drag the ListItems the drag and drop event is triggered. But it is not able to recognize what Items were dropped onto the widget. The example code is below. The goal is to drag-drop the list items from one ListWidget to another.</p>
  
  <pre><code>import sys, os
  from PyQt4 import QtCore, QtGui   
  class ThumbListWidget(QtGui.QListWidget):
      def __init__(self, type, parent=None):
          super(ThumbListWidget, self).__init__(parent)
          self.setAcceptDrops(True)
          self.setIconSize(QtCore.QSize(124, 124))
  
      def dragEnterEvent(self, event):
          if event.mimeData().hasUrls:
              event.accept()
          else:
              event.ignore()
  
      def dragMoveEvent(self, event):
          if event.mimeData().hasUrls:
              event.setDropAction(QtCore.Qt.CopyAction)
              event.accept()
          else:
              event.ignore()
  
      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.ignore()
  
  
  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)
          for i in range(12): 
              QtGui.QListWidgetItem( 'Item '+str(i), self.listWidgetA )
          myBoxLayout.addWidget(self.listWidgetA)
  
          self.listWidgetB = ThumbListWidget(self)
          myBoxLayout.addWidget(self.listWidgetB)   
  
          self.listWidgetA.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
          self.listWidgetA.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
          self.connect(self.listWidgetA, QtCore.SIGNAL("dropped"), self.items_dropped)
          self.listWidgetA.currentItemChanged.connect(self.item_clicked)
  
          self.listWidgetB.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
          self.listWidgetB.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
          self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.items_dropped)
          self.listWidgetB.currentItemChanged.connect(self.item_clicked)
  
      def items_dropped(self, arg):
          print arg
  
      def item_clicked(self, arg):
          print arg
  
  if __name__ == '__main__':
      app = QtGui.QApplication(sys.argv)
      dialog_1 = Dialog_01()
      dialog_1.show()
      dialog_1.resize(480,320)
      sys.exit(app.exec_())
  </code></pre>
  
  <h1>EDIT # 2</h1>
  
  <p>Here is the code that does it all. But there is no way to track down what object was dropped. The droppedOnA() and droppedOnB() methods are still not working.</p>
  
  <hr>
  
  <pre><code>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):
          print 'dropEvent', 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)
  
  
  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(7):
              listItemAInstance=MyClassItem()
              listItemAInstance.setText('A'+'%04d'%i)
              listItemAInstance.setBackgroundColor(QtCore.Qt.darkGray)   
              if i%2: listItemAInstance.setBackgroundColor(QtCore.Qt.gray)
              self.listWidgetA.addItem(listItemAInstance) 
  
              listItemBInstance=MyClassItem()
              listItemBInstance.setText('B'+'%04d'%i)
  
              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)
  
  
      def droppedOnA(self, arg):
          print '\n\t droppedOnA', arg.text
  
      def droppedOnB(self, arg):
          print '\n\t droppedOnB', arg.text
  
  
  if __name__ == '__main__':
      app = QtGui.QApplication(sys.argv)
      dialog_1 = Dialog_01()
      dialog_1.show()
      dialog_1.resize(480,320)
      sys.exit(app.exec_())
  </code></pre>
  
  <h1>EDIT # 3</h1>
  
  <p>Here is another attempt this time using MIME to pass dropped Item's objects to ListWidget. Unfortunately cPickle refuses to accept binary objects throwing a </p>
  
  <blockquote>
    <p>TypeError: the sip.wrapper type cannot be instantiated or sub-classed</p>
  </blockquote>
  
  <p>To get around it I convert each object names to string and use it with self.listItems={} dictionary as its key to retrieve list Item's binary objects. Which seems to be working well. But at the end when I almost though it as all done, a ListWidget with no visible errors doesn't add the dropped list Item to itself... It's strange. </p>
  
  <blockquote>
    <p>self.listWidgetB.addItem(droppedItemInstance)</p>
  </blockquote>
  
  <p>.</p>
  
  <hr>
  
  <pre><code>from PyQt4 import QtGui, QtCore
  import sys, os
  import cPickle 
  
  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()))
  
          else:
              event.setDropAction(QtCore.Qt.MoveAction)
              super(ThumbListWidget, self).dropEvent(event)
  
  
      def mimeTypes(self):
          return ['bstream', 'text/xml']
  
      def mimeData(self, droppedItems):
          mimedata = QtCore.QMimeData()
  
          droppedItemsAsStrings=[]
          for each in droppedItems:            
              droppedItemsAsStrings.append( str(each) )
  
          bstream = cPickle.dumps(droppedItemsAsStrings)
          mimedata.setData('bstream', bstream)        
          return mimedata
  
  
      def dropMimeData(self, action, mimedata, row):
  
          if action == QtCore.Qt.IgnoreAction: return True  
  
          dropped=cPickle.loads(str(mimedata.data('bstream')))
  
          self.emit(QtCore.SIGNAL("dropped"), dropped)  
  
          return True
  
  
  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(7):
              listItemAInstance=MyClassItem()
              listItemAInstance.setText('A'+'%04d'%i)
              listItemAInstance.setBackgroundColor(QtCore.Qt.darkGray)   
              if i%2: listItemAInstance.setBackgroundColor(QtCore.Qt.gray)
              self.listWidgetA.addItem(listItemAInstance) 
  
              listItemBInstance=MyClassItem()
              listItemBInstance.setText('B'+'%04d'%i)
  
              if i%2: listItemBInstance.setBackgroundColor(QtCore.Qt.lightGray)
              self.listWidgetB.addItem(listItemBInstance) 
  
              self.listItems[str(listItemAInstance)]=listItemAInstance
              self.listItems[str(listItemBInstance)]=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)
  
  
      def droppedOnA(self, droppedItemsAsStrings):
          print '\n\t droppedOnA()'
          for each in droppedItemsAsStrings:
              if each in self.listItems.keys():
                  droppedItemInstance = self.listItems[each]
                  print 'adding', droppedItemInstance.text()
                  self.listWidgetA.addItem(droppedItemInstance) 
  
  
      def droppedOnB(self, droppedItemsAsStrings):
          print '\n\t droppedOnB()'
          for each in droppedItemsAsStrings:
              if each in self.listItems.keys():
                  droppedItemInstance = self.listItems[each]
                  self.listWidgetB.addItem(droppedItemInstance) 
                  print 'adding', droppedItemInstance.text()
  
  
  if __name__ == '__main__':
      app = QtGui.QApplication(sys.argv)
      dialog_1 = Dialog_01()
      dialog_1.show()
      dialog_1.resize(480,320)
      sys.exit(app.exec_())
  </code></pre>