在QTreeView中拖放,removeRows没有被调用
Posted
技术标签:
【中文标题】在QTreeView中拖放,removeRows没有被调用【英文标题】:Drag and drop in QTreeView, removeRows not called 【发布时间】:2014-06-16 19:18:49 【问题描述】:我在QTreeView
中的拖放有一些问题:
我将标志设置为Qt::MoveAction
并在我的模型中重新实现removeRows()
、dropMimeData()
等。模型继承QAbstractItemModel
。
当我拖放时,mimeData()
、dropMimeData()
会被自动调用,
还有dropMimeData()
自动调用insertRows()
。但是removeRows()
没有被调用,所以被拖拽的item还活着。我用谷歌搜索,但他们说他们的removeRows()
是自动调用的。
removeRows()
不在dropMimeData()
之后调用?
我应该在dropMimeData()
中手动调用removeRows()
吗?
如果是这样,我怎么知道前一个拖动开始的QModelIndex
?
当开始拖动时,在mimeData()
,我可以将索引保存在私有成员中,但看起来不太好。
任何建议将不胜感激。
【问题讨论】:
【参考方案1】:简答
如果一切配置正确,则目标不应移除源项,如果执行Qt::MoveAction
,则拖动的发起者应移除源项。
视图配置
QAbstractItemView
(是QTreeView
、QListView
、QTableView
、...的基类)实现QDrag
操作在startDrag
中的发起和结束:
if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction) d->clearOrRemove();
因此,当请求的删除操作(由QDrag::exec
返回)是Qt::MoveAction
时,该项目将自动删除(或由setDragDropOverwriteMode
指定清除)。
视图的重要配置选项有:
setDragDropMode
:指定视图是否应该接受来自外部或仅内部项目的拖放项目。该函数相应地调用setDragEnabled
和setAcceptDrops
。
setDragEnabled
: 开启内置拖拽机制
setAcceptDrops
: 启用内置 drop 机制
setDragDropOverwriteMode
:指定是否应删除源项(通常在树视图中)或清除(通常在表视图中)
setDefaultDropAction
:启动QDrag
操作时指定的默认放置动作。
模型配置
除了视图的配置,你应该正确配置你的模型。
您应该实现模型的编辑界面,即removeRows
、insertRows
、moveRows
和setData
。尽管根据您的具体情况可能没有必要实现所有这些,但对于可编辑模型来说,无论如何实现它们都是一种好方法。
supportedDropActions
:重新实现此函数以返回支持删除操作(默认为Qt::CopyAction
)。请注意,用户可以通过按一些键在不同的支持操作之间切换。 (shift
代表 Qt::MoveAction
和 control
代表 Qt::CopyAction
)
supportedDragActions
:如果支持的拖动操作与支持的拖放操作不同,请重新实现此功能。
示例
很好的例子是 Qt 本身的源代码。对应的Q*Widget
类(例如QTreeWidget
用于QTreeView
)提供了视图和对应模型的具体实现。
【讨论】:
我遇到的另一件事:视图的selectionBehavior
必须设置为QAbstractItemView::SelectRows
(并且not 设置为QAbstractItemView::SelectItems
)。【参考方案2】:
我的自定义模型也有同样的问题。为视图设置 dragDropOverwriteMode=false
解决了我的问题。
【讨论】:
dragDropOverwriteMode 的默认值为 false,如在 QListView 和 QTreeView 子类中。另一方面,在 QTableView 子类中,该属性已设置为 true【参考方案3】:我认为是的,如果Qt::DropAction
是Qt::MoveAction
,则您必须从dropMimeData()
调用removeRows()
,即您将树节点从一个地方完全移动到另一个地方。
写下您的第二个问题,您可以在QAbstractItemModel::mimeData()
中创建您的自定义 mime 数据,并在那里对您拖动的节点的初始信息进行编码。所以,在dropMimeData()
函数中你可以解码并使用它。
【讨论】:
感谢您的快速回复。我知道对自定义 mime 数据进行编码/解码,但我无法对拖动节点的索引进行编码。如何将模型索引编码为 QDataStream? @user18640,例如,可以存储行号和列号,或者树项路径或者其他可以唯一标识模型索引的信息。 我明白了,我将对行、列和模型索引内部 ID 进行编码,以在 dropMimeData() 中使用 QAbstractItemModel::createIndex()。谢谢。 如果拖放在两个不同模型之间执行会怎样? 'removeRows' 实际上应该在源模型上调用。文档说,当“dropMimeData”返回 true 时,“removeRows”将被自动调用。 这是错误的,当你从dropMimeData()
返回true
时,Qt会自动为你调用removeRows
以上是关于在QTreeView中拖放,removeRows没有被调用的主要内容,如果未能解决你的问题,请参考以下文章