我正在尝试向QTreeWidget拖放功能添加约束,以防止分支进入另一个根中的另一个分支 .
这是一个让事情更清晰的例子:
我有4个物体 . 让我们称他们为苹果,香蕉,胡萝卜,榴莲 .
树看起来像这样:
isDelicious (Root)
|-- BackgroundObjects (Branch)
|-- Durian
|-- ForgroundObjects (Branch)
|-- Apple
|-- Banana
|-- Carrot
isSmelly (Root)
|-- BackgroundObjects (Branch)
|-- Apple
|-- Carrot
|-- ForgroundObjects (Branch)
|-- Banana
|-- Durian
因此,允许将对象从BackgroundObjects拖放到ForgroundObjects,反之亦然,但是不允许将它们拖放到不同根目录上的分支上 .
我已经尝试重新实现和子类化dragMoveEvent,dragEnterEvent和dropEvent,如果我在dragEnterEvent中对事件调用accept,它将调用dragMoveEvent(我期望) . 但是,只有当我退出QTreeWidget时才会调用dropEvent .
我想要做的是在移动之前检查所选对象的祖父母,以及建议的新祖父母以查看它们是否相同 . 如果是,那么接受此举 . 否则忽略此举 .
我已经搜索过是否有任何答案,到目前为止我还没有尝试过 . 可能最接近的是来自Stack Overflow的这两个问题:
https://stackoverflow.com/questions/17134289/managing-drag-and-drop-within-qtreewidgets-in-pyside
qt: QTreeView - limit drag and drop to only happen within a particlar grandparent (ancestor)
2 回答
Qt似乎没有让这种事情变得非常容易 .
我能想到的最好的方法是在拖动输入和拖动移动事件期间暂时重置项目标志 . 下面的示例动态计算当前顶级项目以禁止拖放 . 但也可以通过使用
setData()
为每个项目添加标识符来完成 .这是我的解决方案(最后的完整代码),子类化
QTreeWidget
. 我尝试过一些非常通用的东西,应该适用于很多情况 . 拖动时视觉提示仍然存在一个问题 . 以前的版本在Windows上不起作用,我希望这个版本能够 . 它在Linux上运行得非常好 .Defining categories
树中的每个项目都有一个类别(一个字符串),我存储在
QtCore.Qt.ToolTipRole
中 . 您还可以将QTreeWidgetItem
子类化为具有特定属性category
.我们在字典
settings
中定义所有类别,包括可以放入的类别列表和要设置的标志 . 例如:类别“family”的每个项目都可以获得拖动,并且只能放入“root”(隐藏的根项) . “儿童”类别中的每一项都只能归入“家庭” .
Adding items to the tree
方法
addItem(strings,category,parent=None)
使用工具提示"category"和setting
中的匹配标志创建QTreeWidgetItem(strings,parent)
. 它返回该项目 . 例:Reimplementation of Drag and Drop
被拖动的项目由
self.currentItem()
确定(不处理多项选择) . 可以删除此项目的类别列表是okList=self.settings[itemBeingDragged.data(0,role)][0]
.鼠标下的项目,即"drop target",是
self.itemAt(event.pos())
. 如果鼠标位于空白处,则将放置目标设置为根项目 .dragMoveEvent
(视觉提示是否接受/忽略掉落)如果放置目标在
okList
中,我们称之为常规dragMoveEvent
. 如果没有,我们必须检查"next to drop target" . 在下面的图像中,鼠标下的项目是Robertsons,但真正的下降目标是根项目(参见下面的Robertsons线?) . 为了解决这个问题,我们检查项目是否可以拖放到放置目标的父级 . 如果没有,我们称之为event.ignore()
.唯一剩下的问题是当鼠标实际上在“Robertsons”上时:接受拖动事件 . 视觉线索表示,当不是时,它将被接受 .
dropEvent
而不是接受或忽略掉落,这是因为"next to drop target"非常棘手,我们总是接受掉落,然后修复错误 .
如果新父级与旧父级相同,或者它位于
okList
中,则我们不执行任何操作 . 否则,我们将拖动的项目放回旧父项中 .有时被删除的项目将被折叠,但这可以很容易地修复
itemBeingDragged.setExpanded()
最后,完整代码有两个例子: