Drag and Drop in PyQt

January 14, 2011 @ 10:54

So you want to be able to drag items out of a QListView? The docs suck on this. Here’s how simple it actually is:

class MyListView(QtGui.QListView):
    def __init__(self, parent=None):
        super(MyListView, self).__init__(parent)  
  
        # enable dragging
        self.setDragEnabled(True)  
   
        # I'm only interested in drag, not drop, so I disable drop
        self.setAcceptDrops(False)
        self.setDragDropMode(QtGui.QAbstractionItemView.DragOnly)  
   
        # use this to allow selecting multiple entries
        self.setSelectionMode(QtGui.QAbstractionItemView.ExtendedSelection)

    def mouseMoveEvent(self, event):
          self.dragObject()  
 
    def dragObject(self):
      if not self.selectedIndexes():
          return

      drag = QtGui.QDrag(self)  
 
      data = []
      for index in self.selectedIndexes():
          if not index.isValid(): continue

          # this assumes your model has a nodeFromIndex() method -
          # it's easy to set one up, you'll probably have a custom
          # model class anyways
          node = self.model().nodeFromIndex(index)
          data.append(str(node))

      # in this case I'm just making a newline-seperated list
      # of the data, you could do pretty much anything here
      md = Qt.QMimeData()
      md.setData('text/plain', "\n".join(data))  
 
      # this is important.  Without this, it won't do anything.
      # you can use different actions like Qt.MoveAction, which
      # would remove the item from your model, but then your model
      # has to be more complicated.  I'm only interested in copy here.
      drag.setMimeData(md)
      dropAction = drag.exec_(Qt.Qt.CopyAction)  

Yup, that’s it. There’s lots of conflicting docs, some tell you to do complicated things with mousePressEvent(), others are older than modern Qt, others just plain wrong.