如何阻止QTreeWidget在拖放时创建重复项

0 投票
1 回答
1891 浏览
提问于 2025-04-18 16:41

下面的代码创建了一个包含五个项目的 QTreeWidget
这里的 self.setDragDropMode(self.InternalMove) 这个设置确保了当你把一个项目拖到另一个项目上时,不会生成它的副本(这样项目的数量始终保持不变)。

enter image description here

如果我们把这行代码换成 self.setDragDropMode(self.DragDrop),那么每次拖动/放下一个项目时,都会生成一个新的副本。

enter image description here

因为我不想在每次拖放事件中生成项目的副本,所以我希望使用 InternalMove 这个设置,但它又阻止了 QTreeWidget 接受来自其他地方的拖放(如果设置了 InternalMoveQTreeWidget 就不允许从其他 QTreeWidget、QListView 或文件浏览器中拖放)。
有没有办法设置一个覆盖,使得 QTreeWidget 不会创建拖动项目的副本,同时又能接受来自外部窗口的拖放呢?

from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])

class Tree(QtGui.QTreeWidget):
    def __init__(self, *args, **kwargs):
        super(Tree, self).__init__()
        self.setDragEnabled(True)
        self.setDropIndicatorShown(True)
        self.setDragDropMode(self.InternalMove)
        items=[QtGui.QTreeWidgetItem([name]) for name in ['Item_1','Item_2','Item_3','Item_4','Item_5']]
        self.addTopLevelItems(items)
        self.resize(360,240)
        self.show()

tree=Tree()
sys.exit(app.exec_())

1 个回答

1

解决这个问题的关键在于,你需要在对象移动到下一个 QListsWidget 时进行处理,并检查数据是否重复。也就是说,要把数据从源位置移到目标位置,具体做法是先从源位置删除数据,然后再把这些数据添加到目标 QListsWidget 中。

你需要使用两个方法,分别是 dragEnterEventdropEvent,来处理这些操作;

  1. dragEnterEvent 方法中,检查要移动的对象是否在同一个 QListsWidget 中。

  2. dropEvent 方法中,检查数据是否重复,并将数据从源位置移动到目标位置。

示例:

import sys
from PyQt4 import QtCore, QtGui

class QCustomTreeWidget (QtGui.QTreeWidget):
    def __init__(self, parent = None):
        super(QCustomTreeWidget, self).__init__(parent)
        self.setDragEnabled(True)
        self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
        self.resize(360,240)

    def dragEnterEvent (self, eventQDragEnterEvent):
        sourceQCustomTreeWidget = eventQDragEnterEvent.source()
        if isinstance(sourceQCustomTreeWidget, QCustomTreeWidget):
            if self != sourceQCustomTreeWidget:
                sourceQCustomTreeWidget.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
                eventQDragEnterEvent.accept()
            else:
                sourceQCustomTreeWidget.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
                QtGui.QTreeWidget.dragEnterEvent(self, eventQDragEnterEvent)
        else:
            QtGui.QTreeWidget.dragEnterEvent(self, eventQDragEnterEvent)

    def dropEvent (self, eventQDropEvent):
        sourceQCustomTreeWidget = eventQDropEvent.source()
        if isinstance(sourceQCustomTreeWidget, QCustomTreeWidget):
            if self != sourceQCustomTreeWidget:
                sourceQCustomTreeWidget.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
                sourceQTreeWidgetItem = sourceQCustomTreeWidget.currentItem()
                isFound = False
                for column in range(0, self.columnCount()):
                    sourceQString = sourceQTreeWidgetItem.text(column)
                    listsFoundQTreeWidgetItem = self.findItems(sourceQString, QtCore.Qt.MatchExactly, column)
                    if listsFoundQTreeWidgetItem:
                        isFound = True
                        break
                if not isFound:
                    (sourceQTreeWidgetItem.parent() or sourceQCustomTreeWidget.invisibleRootItem()).removeChild(sourceQTreeWidgetItem)
                    self.invisibleRootItem().addChild(sourceQTreeWidgetItem)
            else:
                sourceQCustomTreeWidget.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
                QtGui.QTreeWidget.dropEvent(self, eventQDropEvent)
        else:
            QtGui.QTreeWidget.dropEvent(self, eventQDropEvent)

class QCustomQWidget (QtGui.QWidget):
    def __init__ (self, parent = None):
        super(QCustomQWidget, self).__init__(parent)
        self.my1QCustomTreeWidget = QCustomTreeWidget(self)
        self.my2QCustomTreeWidget = QCustomTreeWidget(self)
        items = [QtGui.QTreeWidgetItem([name]) for name in ['Item_1', 'Item_2', 'Item_3', 'Item_4', 'Item_5']]
        self.my1QCustomTreeWidget.addTopLevelItems(items)
        self.allQHBoxLayout = QtGui.QHBoxLayout()
        self.allQHBoxLayout.addWidget(self.my1QCustomTreeWidget)
        self.allQHBoxLayout.addWidget(self.my2QCustomTreeWidget)
        self.setLayout(self.allQHBoxLayout)

app = QtGui.QApplication([])
myQCustomQWidget = QCustomQWidget()
myQCustomQWidget.show()
sys.exit(app.exec_())

关于事件处理的有用参考

撰写回答