我正在根据我的自定义模型实现拖放QTreeView。一切正常,我的树显示数据,拖放已启用,现在最后一步摆在我面前 - 删除和转移拖动的数据。为此,我需要在我的模型中实现mimeTypes,mimeData和dropMimeData方法。现在我的问题是:有没有简单的标准方法如何通过QMimeData传递任意Python对象?我只是在QTreeView中进行内部移动,它显示了我的Python类Person的层次结构。我想重新排序它们。在应用程序外没有拖放,甚至没有控制。我发现只有一个教程:link text。但这是唯一的方法吗?如果不将Python对象编码为ByteArray,就无法完成。我需要一个非常简单的解决方案,我只有一个班级人员谢谢。
答案 0 :(得分:2)
不要尝试通过重新创建底层python对象来实现拖放。如果拖动来自您的过程之外,这将不起作用;它也不适用于复制操作(您的节点对象可能不存在于树中的多个位置)。
将拖放“移动”想象为三个操作:
mineData()和dropMimeData()是您提供的序列化和反序列化操作。 Python提供了一些简单的方法来实现它们 - 查看pickle模块的文档。如果你很幸运,pickle.dumps()和pickle.loads()将为你开箱即用。
编辑:我无法弄清楚如何在评论中粘贴代码,所以这是我的评论所指的解决方案。这是安全的,因为如果碰巧违反规则,抛出KeyError而不是导致崩溃就会失败。
# drag: store off the data in a safe place, and serialize a cooky
# that the drop target can use to retrieve the data.
self.__tmp_storage_dct = { self.__tmp_storage_cooky: stuff }
m.setData(self.rowlistptr_mime_type, QByteArray(pickle.dumps(self.__tmp_storage_cooky)))
self.__tmp_storage_cooky += 1
# drop:
if mime.hasFormat(self.rowlistptr_mime_type):
print "got tmpstorage"
cooky = pickle.loads(mime.data(self.rowlistptr_mime_type).data())
nodes = self.__tmp_storage_dct.pop(cooky)
答案 1 :(得分:1)
好的,我想我有一个可能的解决方案。
请记住,我是这个领域的一个完全新手所以不保证他的a)有效b)是一个不错的解决方案c)不会让“真正的”程序员抛弃他们的午餐。
我所做的是将特定项目的整个祖先树转换为行列对的文本列表。 (即列出被拖动项目的行和列,其父项的行和列,其父项的父项的行和列等等......直到我们得到无效索引 - 即根目录
这看起来像这样(此示例显示拖动的项目深度为四级):
2;0,1;0,5;0,1,0
^ ^ ^ ^
| | | |
| | | great grandparent (and child of the root item)
| | |
| | grandparent
| |
| parent
|
item being dragged
稍后,在dropMimeData函数中,我反转列表(以便它从根读回到被拖动的项目)并一次构建一个索引,直到我回到最初拖动的项目。
以下是使所有工作完成的代码片段。同样,我不能保证这是一个好主意,只是它似乎工作,并不要求你将你的python对象序列化为ByteArray。
希望这有帮助。
#---------------------------------------------------------------------------
def mimeTypes(self):
"""
Only accept the internal custom drop type which is plain text
"""
types = QtCore.QStringList()
types.append('text/plain')
return types
#---------------------------------------------------------------------------
def mimeData(self, index):
"""
Wrap the index up as a list of rows and columns of each
parent/grandparent/etc
"""
rc = ""
theIndex = index[0] #<- for testing purposes we only deal with 1st item
while theIndex.isValid():
rc = rc + str(theIndex.row()) + ";" + str(theIndex.column())
theIndex = self.parent(theIndex)
if theIndex.isValid():
rc = rc + ","
mimeData = QtCore.QMimeData()
mimeData.setText(rc)
return mimeData
#---------------------------------------------------------------------------
def dropMimeData(self, data, action, row, column, parentIndex):
"""
Extract the whole ancestor list of rows and columns and rebuild the
index item that was originally dragged
"""
if action == QtCore.Qt.IgnoreAction:
return True
if data.hasText():
ancestorL = str(data.text()).split(",")
ancestorL.reverse() #<- stored from the child up, we read from ancestor down
pIndex = QtCore.QModelIndex()
for ancestor in ancestorL:
srcRow = int(ancestor.split(";")[0])
srcCol = int(ancestor.split(";")[1])
itemIndex = self.index(srcRow, srcCol, pIndex)
pIndex = itemIndex
print itemIndex.internalPointer().get_name()
return True