7

在将多行插入 GTK 树视图(使用 PyGTK)或修改多行时,我遇到了性能问题。问题是模型似乎在每次更改(插入/修改)后都会重新使用。这会导致 GUI 挂起几秒钟。通过注释掉模型不排序可以model.set_sort_column_id(SOME_ROW_INDEX, gtk.SORT_ASCENDING)消除这些问题。

因此,我想在插入或修改模型时禁用排序,然后重新启用它。不幸的是,排序不能用model.set_sort_column_id(-1, gtk.SORT_ASCENDING). 使用冻结/解冻功能也不起作用:

treeview.freeze_child_notify()

try:
    for row in model:
        # ... change something in row ...
finally:
    treeview.thaw_child_notify()

那么,如何禁用排序?还是有更好的批量插入/修改方法?


解决方案

感谢他在回答中提供的信息和链接 bobince,我检查了一些替代方案:

1) 虚拟排序

 tv.freeze_child_notify()
 sortSettings = model.get_sort_column_id()
 model.set_default_sort_func(lambda *unused: 0) # <-- can also use None but that is slower!
 # model.set_default_sort_func(lambda *unused: 1) <-- slow
 # model.set_default_sort_func(lambda *unused: -1) <-- crash (access violation in gtk_tree_store_move_after?!)
 model.set_sort_column_id(-1, gtk.SORT_ASCENDING)
 # change rows
 model.set_sort_column_id(*sortSettings)
 tv.thaw_child_notify()

这使时间从大约 11 秒减少到 2 秒。哇!但可能会更好,这仅适用于 1000 行。

2) 更新时删除模型

tv.set_model(None)
# change rows
tv.set_model(model)

没有明显差异,11 秒。

3) PyGTK FAQ中的虚拟排序和酷生成器技巧

 def gen():
      tv.freeze_child_notify()
      sortSettings = model.get_sort_column_id()
      model.set_default_sort_func(lambda *unused: 0)
      model.set_sort_column_id(-1, gtk.SORT_ASCENDING)

      i = 0
      for row in rowsToChange:
           i += 1
           # change something
           if i % 200 == 0:
                # freeze/thaw not really  necessary here as sorting is wrong because of the
                # default sort function
                yield True

      model.set_sort_column_id(*sortSettings)
      tv.thaw_child_notify()
      yield False

 g = gen()
 if g.next(): # run once now, remaining iterations when idle
     gobject.idle_add(g.next)

结果:与解决方案 1) 中估计的 2 秒相同,但 GUI 在此期间做出反应。我更喜欢这种方法。如果需要,可以调整模 200 以使 GUI 或多或少具有反应性。

也许甚至可以进行子类化gtk.TreeStore以获得更好的结果?还没有尝试过,但选项 3) 现在已经足够好了。

4

1 回答 1

2

Sounds like you're nearly there. See the FAQ for further notes. In particular, you should also set the default_sort_order (you can now use None as well as the dummy compare lambda in that example, for better performance) to ensure there is no sorting, and remove the model from the treeview for the duration of the operations.

If it's a lot of changes you may be better off creating and setting a complete new model.

于 2010-08-24T11:54:15.093 回答