pyjamas
pyjamas

Reputation: 5399

QTreeWidget dropped item gets deleted when using setDropAction

I am trying to make a QTreeWidget that lets the user rearrange its elements, and if the user drags and drops a tree item to another widget I don't want the item to be deleted. To get this behavior, I'm trying to use setDropAction in dropEvent.

The code below successfully rejects drops from other widgets, and allows drops to other widgets without deleting the original, but it seems to break drag-and-drop within the tree - it causes the item to disappear when dropped.

https://www.screencast.com/t/driIjyg8ekzt

import sys

from PyQt5 import QtWidgets, QtGui
from PyQt5.QtCore import Qt


class MyTree(QtWidgets.QTreeWidget):
    def __init__(self):
        super().__init__()

        self.setDragDropMode(self.DragDrop)
        self.setSelectionMode(self.ExtendedSelection)
        self.setSelectionBehavior(self.SelectRows)
        self.setDefaultDropAction(Qt.CopyAction)
        self.setAcceptDrops(True)

    def dropEvent(self, e: QtGui.QDropEvent):
        if e.source() is self:
            print("move")
            e.setDropAction(Qt.MoveAction)
            e.accept()
        super().dropEvent(e)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    my_list = QtWidgets.QListWidget()
    my_list.addItems(list('1234'))
    my_list.show()
    my_list.setDragEnabled(True)
    my_list.setAcceptDrops(True)

    my_tree = MyTree()
    for item in list('abcd'):
        QtWidgets.QTreeWidgetItem(my_tree, [item])
    my_tree.show()

    sys.exit(app.exec_())

Upvotes: 0

Views: 324

Answers (1)

musicamante
musicamante

Reputation: 48260

If you just want to prevent drop from external sources, just use:

    self.setDragDropMode(self.InternalMove)

And don't reimplement dropEvent().

Your code doesn't work properly mostly because you've set the event as accepted, and an item view ignores a drop event if it has already been accepted.

In your case, it would be better to do this:

    def dzropEvent(self, e: QtGui.QDropEvent):
        if e.source() != self:
            # ignore the drop from other sources
            return
        e.setDropAction(Qt.MoveAction)
        super().dropEvent(e)

But if you really want to ignore external drops, you should ignore the event right from the dragEnterEvent(), so that it's made also clear to the user that dropping is not allowed.

Upvotes: 1

Related Questions