PyGTK + Threads + Treewiew + TreeModelFilter + TreeModelSort

Since some days ago, I’ve been dealing with an issue in a personal project at my work, before to detail the issue I would to start with a simple suggestion when dealing with issues:

“Always try to write a separated Test Case to isolate the problem, try to reproduce the issue, maybe you can find your own solution before to get some help from others…”

Some tips when mixing pygtk, threads, treemodelfilter, treemodelsort, treeview…etc

If you want to have a treeview with a model filter and a sort capability, do it on this order

model = gtk.ListStore()
filter = model.filter_new()
sorter = gtk.TreeModelSort(filter)
treeview = gtk.TreeView()
treeview.set_model(sorter)

remember to set the visible_func for the filter.

You want to populate your treeview but while you get your data your UI freeze

No big deal here, your solution? just use threads!, oh!, but wait… what about if you want the following behavior: click on a button, launch a thread, thread get data from somewhere, emit a signal with the data , catch the signal in the main thread and populate the treeview ?. The big problem with this will be the signal which is not emited in the main thread and working with a treeview you can get some intermitent problem like this:

There is a disparity between the internal view of the GtkTreeView,
and the GtkTreeModel.  This generally means that the model has changed
without letting the view know.  Any display from now on is likely to
be incorrect.

This is a very weird problem, is hard to find documentation, but if you are following be above schema, you should do somethink like:

  • Write a gobject subclass like this:

    class _IdleObject(gobject.GObject):
    “””
    Override gobject.GObject to always emit signals in the main thread
    by emmitting on an idle handler
    “””
    def __init__(self):
    gobject.GObject.__init__(self)

    def emit(self, *args):
    gobject.idle_add(gobject.GObject.emit,self,*args)

  • Build a subclass of threading.Thread, put the code that get the data under the run method
  • Build a _IdleObejct subclass which will be called by the run method of the threaded class

On that way your signal will be emited in the main thread avoiding disparity issues on the main treeview, if you want to take a look to a working example go here:

http://edsiper.linuxchile.cl/tv-filter-sort.py

  • godlike

    Your example is fine for when the thread in GTK’s main_loop (as called by the ‘emit’ function of _IdleObject) does not need to return any data to the previously spawned thread. That was not my case, as I was not populating a ListStore, but a TreeStore, and needed to have the returning iter in order to properly insert the child items.

    However, your example was of great value, and I fixed my issue by using multiprocess.Pipe. Thanks!

  • http://edsiper.linuxchile.cl Eduardo Silva

    i am glad to hear that after 4 years is still helpful :)