3
votes

I have two QListWidgets. I want to be able to move items from widget 1 onto widget 2 and vice versa by dragging and dropping. It must work with MultiSelection mode. It must be a MoveAction NOT a copy action. A simple way to achieve this is to use:

self.listWidget_2.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
self.listWidget_2.setDefaultDropAction(QtCore.Qt.MoveAction)
self.listWidget_2.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
self.listWidget_2.setObjectName("listWidget_2")
self.listWidget_2.acceptDrops()

This achieves all the desired requirements with one caveat. Dragging and dropping the item onto the widget where it currently resides removes it from the widget. A definite no go. I Then tried to write my own QListWidget class to achieve my desired results to no avail, this is the class:

class dragLeaveList(QtWidgets.QListWidget):

def __init__(self, type, parent=None):
    super(dragLeaveList, self).__init__(parent)
    self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
    self.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
    self.setAlternatingRowColors(True)
    self.setAcceptDrops(True)


def dragEnterEvent(self, event):
    if event.mimeData().hasText():
        event.accept()
        print("Drag Enter Event: IF CLAUSE")
    else:
        super(dragLeaveList, self).dragEnterEvent(event)
        print("Drag Enter Event: ELSE CLAUSE")

def dragMoveEvent(self, event):
    if event.mimeData().hasText():
        event.setDropAction(QtCore.Qt.MoveAction)
        event.accept()
    else:
        event.ignore()
        super(dragLeaveList, self).dragMoveEvent(event)


def dropEvent(self, event):
    print("Drop Event ", event)
    if event.mimeData().hasText():
        event.setDropAction(QtCore.Qt.MoveAction)
        event.accept()
        print("Drop Event - 1 ", event)

def startDrag(self, event):
    print("In Start Drag")
    item = self.currentItem()
    itemText = self.currentItem().text()
    itemData = QtCore.QByteArray()
    dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.WriteOnly)
    print(item, itemText)
    mimeData = QtCore.QMimeData()
    mimeData.setData(itemText, itemData)


    drag = QtGui.QDrag(self)
    drag.setMimeData(mimeData)

    if drag.exec_(QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction:
        if self.currentItem() is not None:
            self.takeItem(self.row(item))

I've read every tutorial online and all the related documentation on sourceforge and i just can't seem to make this work. I rarely end up not being able to figure something out but the documentation for this just seems to be pretty darn bad. I'm really looking for explanations along with the code. However, as i said I've read all the related documentation multiple times so I'm not completely ignorant. Seems to me in the above class that i have a lot more then what i need and it may have the right components just not the right implementation. Please give me some clarity on this subject, thanks a bunch.

Main things to clarify in answer code

  1. The bare minimum/most effective DragDrop(the built in methods i.e. dragEnterEvent, dragMoveEvent et cetera) methods.
  2. Is mimeData() absolutely required? Assume yes from the Docs.
  3. Formatting the mimeData() into a QListWidgetItem.
  4. Does the item have to be manually removed from the widget or is this built in with the QtCore.Qt.MoveAction?
  5. Actually making the QtCore.Qt.MoveAction move the list item.
1

1 Answers

0
votes

So i have figured out one solution to get everything in working order. Keep in mind that this answer does not teach me what i wanted to know. However, this may be helpful to others wishing to do something the same or similar. I'm am still looking for a method the touches on the topics listed in " Main things to clarify code" list.

class QListDragAndDrop(QtWidgets.QListWidget):
   def __init__(self):
       super(QListDragAndDrop, self).__init__()
       self.setFrameShape(QtWidgets.QFrame.WinPanel)
       self.setFrameShadow(QtWidgets.QFrame.Raised)
       self.setDragEnabled(True)
       self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
       self.setDefaultDropAction(QtCore.Qt.MoveAction)
       self.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
       self.setMovement(QtWidgets.QListView.Snap)
       self.setProperty("isWrapping", True)
       self.setWordWrap(True)
       self.setSortingEnabled(True)
       self.setAcceptDrops(True)

Just make this QListWidget class with these parameters set and import to wherever you need it works like a charm but does not really teach you much. Hopefully, this helps certain people get by until someone answers the question properly.