如何在移动子树后更新TreeModel

3 投票
2 回答
517 浏览
提问于 2025-04-17 01:33

我有一个自定义的通用树模型,它运行得很好。现在我想让用户能够通过拖放的方式来重新排列节点,所以我把一个节点移动到它的新父节点下。

但是,这样一来,树模型就需要通过一些方法来通知,比如 row_has_child_toggledrow_deletedrow_inserted

显然没有 row_moved 这个方法,而调用 row_deleted(针对原来的位置)和 row_inserted(针对新位置)似乎不够。因此,我想我可能需要递归地发出这些更改。

考虑以下示例:

* A (0,)
* B (1,)
  * C (1,0)
    * D (1,0,0)

现在,如果我把 C 移动到 A,发生了以下事情:

row_delete( (1,0) ) # C
row_delete( (1,0,0) ) # D
row_inserted( (0,0) ) # C'
row_inserted( (0,0,0) ) # D'
child_toggle( (0,) ) # A
child_toggle( (1,) ) # B
child_toggle( (0,1) ) # C'

然而,gtk 仍然抱怨模型的状态不一致。我想到两件事:

  • 也许调用这些函数的顺序很重要(如果是这样,有什么想法吗?)
  • 从技术上讲,child_toggle( (1,0) ) 也会发生,但这个行 a) 已经被删除,b) row_has_child_toggled 需要一个 tree_iter 的引用,而我无法获取,因为它已经不存在了。

也许我在这里走错了方向,那么处理这个问题的最佳方法是什么呢?

2 个回答

1

在我看来,这个更新应该是自动进行的,只要你正确地把树形视图(treeview)和它的“drag_data_get”和“drag_data_received”方法连接起来,并且允许它作为拖拽的源和目标,使用“enable_model_drag_dest”和“enable_model_drag_source”这两个方法就可以了。

对于树形视图来说,应该没有其他需要做的事情。

模型在调用“drag_data_received_data”时必须更新,但不需要“删除”任何东西,只需要根据具体情况使用“insert_before”或“insert_after”,就像这里展示的那样:

   def drag_data_received_data(self, treeview, context, x, y, selection,
                               info, etime):
       model = treeview.get_model()
       data = selection.data
       drop_info = treeview.get_dest_row_at_pos(x, y)
       if drop_info:
           path, position = drop_info
           iter = model.get_iter(path)
           if (position == gtk.TREE_VIEW_DROP_BEFORE
               or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
               model.insert_before(iter, [data])
           else:
               model.insert_after(iter, [data])
       else:
           model.append([data])
       if context.action == gtk.gdk.ACTION_MOVE:
           context.finish(True, True, etime)
       return

这段代码来自于:

http://www.pygtk.org/pygtk2tutorial/sec-TreeViewDragAndDrop.html#DragDropReordering

在这个地方,程序“treeviewdnd.py”可以完美地展示你需要的内容。

希望这能解决你的问题!

2

我搞明白了:要删除一个子树,只需要删除这个子树的根节点(告诉模型这个路径已经不存在了,并根据情况切换父节点的has_child状态)。插入一个新的子树也是一样,所以我不需要递归地告诉模型一些事情。

不过,这两个操作的顺序很重要,所以要记住:

  1. 先删除,然后通知模型
  2. 再插入,并再次通知模型。

撰写回答