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

Posted

技术标签:

【中文标题】如何阻止 QTreeWidget 在拖放时创建重复项【英文标题】:How to stop QTreeWidget from creating the item duplicates on Drag and Drop 【发布时间】:2014-08-09 20:47:36 【问题描述】:

下面的代码创建了包含五个项目的QTreeWidgetself.setDragDropMode(self.InternalMove) 标志确保当项目被拖到 另一个将不会复制它(因此项目的数量始终保持不变)。

如果我们用self.setDragDropMode(self.DragDrop) 替换这一行,那么每次拖放一个项目时都会创建一个新副本。

由于我不希望在每个 dragAndDrop 事件上创建项目的副本,如果 InternalMove 标志不会阻止 QTreeWidget 接受来自其自身视图之外的拖放,我会很高兴(如果设置了InternalMove 标志QTreeWidget 不允许从另一个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】:

解决这个问题的关键是你必须在对象移动到下一个QListsWidget时执行,并检查数据是否重复。通过删除源并将此数据添加到目标QListsWidget,将数据从源带到目标。

使用dragEnterEventdropEvent这两种方法来处理它们;

    实现dragEnterEvent检查要移动的对象是否相同QListsWidget

    已实现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_())

Useful reference for event handle

【讨论】:

以上是关于如何阻止 QTreeWidget 在拖放时创建重复项的主要内容,如果未能解决你的问题,请参考以下文章

如何在拖放时克隆 div 而不是在拖动开始时克隆

android在拖放时滚动

C#在拖放时在ListView中实现自动滚动

如何使可拖动元素在拖放时保持在新位置(HTML5 不是 jQuery)?

C#在拖放时实现ListView中的自动滚动

Jquery ui div在拖放时不可拖动