使用 setDropAction 时 QTreeWidget 丢弃的项目被删除

QTreeWidget dropped item gets deleted when using setDropAction

我正在尝试制作一个 QTreeWidget 让用户重新排列其元素,如果用户将树项目拖放到另一个小部件,我不希望该项目被删除。为了获得这种行为,我试图在 dropEvent.

中使用 setDropAction

下面的代码成功地拒绝了其他小部件的放置,并允许在不删除原始小部件的情况下放置到其他小部件,但它似乎破坏了树内的拖放 - 它导致项目在放置时消失。

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_())

如果你只是想防止从外部源掉落,只需使用:

    self.setDragDropMode(self.InternalMove)

并且不要重新实现 dropEvent()

您的代码无法正常工作主要是因为您已将事件设置为已接受,并且项目视图会忽略已接受的放置事件。

在你的情况下,最好这样做:

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

但是如果你真的想忽略外部掉落,你应该直接从 dragEnterEvent() 忽略事件,这样也让用户清楚不允许掉落。