How to update TreeModel after moving subtree
I have a custom GenericTreeModel, that works just fine. Now I want the user to be able to rearrange the nodes using drag and drop, so I move a node to its new parent in the data model.
However then, the TreeModel wants to be notified using methods like row_has_child_toggled
, row_deleted
and row_inserted
.
So apparently there is no row_moved
and calling row_deleted
(for the original path) and row_inserted
(for the new path) seems not to be enough. So I thought I may have to recursively issue these changes.
Consider the following example:
* A (0,)
* B (1,)
* C (1,0)
* D (1,0,0)
Now, if I move C to A, the following things have happened:
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'
However, gtk still complains about inconsistent state of the model. Two things come to my mind:
- maybe the order of calling these functions is relevant (if so any idea how?)
- technically
child_toggle( (1,开发者_StackOverflow0) )
also happens, however the row is a) already deleted and b)row_has_child_toggled
needs atree_iter
reference, which I can't get as it doesn't exist any more.
Maybe I am following a totally wrong approach here, so what’s the best way to go about this?
Figured it out: Removing a subtree works fine by removing the subtree’s root node row (notify the model that the path is gone and conditionally toggling parent.has_child). Same goes for insertion of a new subtree, so I don't need to tell the model stuff recursively.
However the combination is critical, so
- first remove, notify model
- then insert and notify model again.
IMHO, this update should happen automatically for the treeview, if you connect the treeview correctly with its "drag_data_get" and "drag_data_received" methods AND allows it to be a source and a destination with its "enable_model_drag_dest" and "enable_model_drag_source" methods. There should be nothing more to do for the treeview.
The model must be updated in the calls to its "drag_data_received_data", but there is no "delete" to do, just the specific "insert_before" or "insert_after" as shown here :
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
This snippet comes from :
http://www.pygtk.org/pygtk2tutorial/sec-TreeViewDragAndDrop.html#DragDropReordering
where the program " treeviewdnd.py" works perfectly to show you what you need.
Hope this solves your quest !
精彩评论