2

我正在根据我的自定义模型实现拖放 QTreeView。一切正常,我的树显示数据,拖放已启用,现在最后一步摆在我面前 - 拖放和传输拖动的数据。为此,我需要在我的模型中实现 mimeTypes、mimeData 和 dropMimeData 方法。现在我的问题是:是否有任何简单的标准方法可以通过 QMimeData 传递任意 Python 对象?我只是在 QTreeView 中进行内部移动,它显示了我的 Python 类 Person 的层次结构。我想重新排序。在应用程序之外没有拖放,甚至不受控制。我只找到了一个教程:链接文本。但这是唯一的方法吗?如果不将 Python 对象编码为 ByteArray,就无法做到这一点。对于我唯一的一类人,我需要非常简单的解决方案。谢谢你。

4

2 回答 2

2

不要尝试通过重新设置底层 python 对象来实现拖放。如果阻力来自您的流程之外,这将不起作用;它也不适用于复制操作(您的节点对象可能不能存在于树中的多个位置)。

将拖放“移动”视为三个操作:

  1. 将数据序列化为某个字节串
  2. 反序列化为新索引(或新索引)
  3. (可选:如果“移动”而不是“复制”)删除旧索引

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)
于 2010-12-11T10:06:08.177 回答
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
于 2010-11-23T00:20:19.650 回答