Re: [pygtk] Filtered Sortable
On 17-02-11 21:08, Adam Tauno Williams wrote: I'm confused trying to make a filtered sorted treeview. Filtering works... data is correctly displayed. But sorting does not work. self.todo_model = gtk.ListStore(gobject.TYPE_PYOBJECT) # Create a TreeModelFilter to control row visibility self.todo_filter = self.todo_model.filter_new() self.todo_filter.set_visible_func(self.todo_visible_filter) # Create a TreeModelSort to wrap the TreeModelFilter self.todo_sort = gtk.TreeModelSort(self.todo_filter) # Set a sort function self.todo_sort.set_default_sort_func(TaskList.sort, None) # Set the model in the view to the TreeModelSort self.todo_task_view.set_model(self.todo_sort) TaskList.sort --- @staticmethod def sort(model, iter1, iter2, user_data): print 'SORT', model, iter1, iter2 sort_by = model.get_sort_column_id() This fails because model is a TreeModelFilter... which does not have a method get_sort_column_id why isn't this the TreeModelSort object? NOTE: Using a sorted filter can be very confusing in the beginning. I recently implemented this in my app too. As far as I know, it is the lowest model, the liststore. Your setup looks good, it is the sort function that is not good. The docs [1] say that the function should return -1, 0 or 1. Here is the method I use: def _sort_func(self, model, iter1, iter2): data1 = model.get_value(iter1, 3) data2 = model.get_value(iter2, 3) if data1 == data2: data1 = model.get_value(iter1, 2) data2 = model.get_value(iter2, 2) return cmp(data1, data2) This will sort column 2 if the values in column 3 are equal. The key part here is the built-in cmp() function that will return -1, 0 or 1, which is what we need. Cheers, Timo [1] http://library.gnome.org/devel/pygtk/stable/class-gtktreesortable.html#method-gtktreesortable--set-sort-func [that is the model directly owned by the view. Does anyone have a working example of a filtered sortable list? ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://faq.pygtk.org/ ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://faq.pygtk.org/
Re: [pygtk] Filtered Sortable
On Fri, 2011-02-18 at 10:13 +0100, Timo wrote: On 17-02-11 21:08, Adam Tauno Williams wrote: I'm confused trying to make a filtered sorted treeview. Filtering works... data is correctly displayed. But sorting does not work. self.todo_model = gtk.ListStore(gobject.TYPE_PYOBJECT) # Create a TreeModelFilter to control row visibility self.todo_filter = self.todo_model.filter_new() self.todo_filter.set_visible_func(self.todo_visible_filter) # Create a TreeModelSort to wrap the TreeModelFilter self.todo_sort = gtk.TreeModelSort(self.todo_filter) # Set a sort function self.todo_sort.set_default_sort_func(TaskList.sort, None) # Set the model in the view to the TreeModelSort self.todo_task_view.set_model(self.todo_sort) TaskList.sort --- @staticmethod def sort(model, iter1, iter2, user_data): print 'SORT', model, iter1, iter2 sort_by = model.get_sort_column_id() This fails because model is a TreeModelFilter... which does not have a method get_sort_column_id why isn't this the TreeModelSort object? NOTE: Using a sorted filter can be very confusing in the beginning. Yep. As far as I know, it is the lowest model, the liststore. ? I'm sorry, but I don't follow. What is it [is the lowest model]? Your setup looks good, it is the sort function that is not good. The docs [1] say that the function should return -1, 0 or 1. Which my function does; I just didn't include beyond the call to get_sort_column_id because the method call *fails* at that point because the model is a TreeModelFilter which does *not* have a get_sort_column_id method. If I just don't call get_sort_column_id and assume a static sort column then I do get some sorting behavior [although not correct, at least something happens if I click on the header of the first column]. If I build a hack and drive down to the lowest model (the actual ListStore) - initmodel = model basemodel = None while basemodel is None: if (isinstance(model, gtk.TreeModelFilter)): model = model.get_model() elif (isinstance(model, gtk.TreeModelSort)): model = model.get_model() else: basemodel = model sort_by = basemodel.get_sort_column_id() Then sort_by ends up being (None, None). IMO, this is a bit beyond confusing. Searching archives I've found several posts about this issue... and never an answer. Clicking on the header of a column other than the first column just results in an error of - GtkWarning: gtk_tree_model_sort_set_sort_column_id: assertion `header != NULL' failed Here is the method I use: def _sort_func(self, model, iter1, iter2): data1 = model.get_value(iter1, 3) data2 = model.get_value(iter2, 3) if data1 == data2: data1 = model.get_value(iter1, 2) data2 = model.get_value(iter2, 2) return cmp(data1, data2) This will sort column 2 if the values in column 3 are equal. The key part here is the built-in cmp() function that will return -1, 0 or 1, which is what we need. ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://faq.pygtk.org/
Re: [pygtk] Filtered Sortable
On Fri, 2011-02-18 at 06:27 -0500, Adam Tauno Williams wrote: On Fri, 2011-02-18 at 10:13 +0100, Timo wrote: On 17-02-11 21:08, Adam Tauno Williams wrote: I'm confused trying to make a filtered sorted treeview. Filtering works... data is correctly displayed. But sorting does not work. self.todo_model = gtk.ListStore(gobject.TYPE_PYOBJECT) # Create a TreeModelFilter to control row visibility self.todo_filter = self.todo_model.filter_new() self.todo_filter.set_visible_func(self.todo_visible_filter) # Create a TreeModelSort to wrap the TreeModelFilter self.todo_sort = gtk.TreeModelSort(self.todo_filter) # Set a sort function self.todo_sort.set_default_sort_func(TaskList.sort, None) # Set the model in the view to the TreeModelSort self.todo_task_view.set_model(self.todo_sort) Clicking on the header of a column other than the first column just results in an error of - GtkWarning: gtk_tree_model_sort_set_sort_column_id: assertion `header != NULL' failed Perhaps it is doing the same stupid thing as the sort call and trying to set the column sort id on the TreeModelFilter? ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://faq.pygtk.org/
Re: [pygtk] Filtered Sortable [SUCCESS!]
On Fri, 2011-02-18 at 06:27 -0500, Adam Tauno Williams wrote: On Fri, 2011-02-18 at 10:13 +0100, Timo wrote: On 17-02-11 21:08, Adam Tauno Williams wrote: I'm confused trying to make a filtered sorted treeview. Filtering works... data is correctly displayed. But sorting does not work. self.todo_model = gtk.ListStore(gobject.TYPE_PYOBJECT) # Create a TreeModelFilter to control row visibility self.todo_filter = self.todo_model.filter_new() self.todo_filter.set_visible_func(self.todo_visible_filter) # Create a TreeModelSort to wrap the TreeModelFilter self.todo_sort = gtk.TreeModelSort(self.todo_filter) # Set a sort function self.todo_sort.set_default_sort_func(TaskList.sort, None) # Set the model in the view to the TreeModelSort self.todo_task_view.set_model(self.todo_sort) Okay, I figured it out. The call to set_default_sort_func(TaskList.sort, None) is *wrong*. [It makes sense, and is obvious, but wrong]. Setting a sort function and retrieving the sort column in the sort method just isn't how Gtk works. You have to see a sort function for each sortable column and pass the column id either implicitly [a different sort function for every column] or explicitly [by using the user_data] field. So, something like... class TaskList(object) ... @staticmethod def sort_model(model): sortable = gtk.TreeModelSort(model) sortable.set_sort_func(TaskList.COLUMN_TASK_ID, TaskList.sort, TaskList.COLUMN_TASK_ID) sortable.set_sort_func(TaskList.COLUMN_TASK_NAME, TaskList.sort, TaskList.COLUMN_TASK_NAME) sortable.set_sort_func(TaskList.COLUMN_TASK_END, TaskList.sort, TaskList.COLUMN_TASK_END) sortable.set_sort_column_id(TaskList.COLUMN_TASK_ID, gtk.SORT_ASCENDING) return sortable - then in the sort function - @staticmethod def sort(model, iter1, iter2, user_data): sort_by = user_data value1 = model[iter1][0][TaskList.COLUMN_KEYS[sort_by]] value2 = model[iter2][0][TaskList.COLUMN_KEYS[sort_by]] return cmp(value1, value2) I know have a sortable filtered TreeView. I believe setting a set_default_sort_func might supress the stray - Warning: unable to set property `text' of type `gchararray' from value of type `PyObject' - seen when the application starts. But I haven't tried that. ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://faq.pygtk.org/
[pygtk] Filtered Sortable
I'm confused trying to make a filtered sorted treeview. Filtering works... data is correctly displayed. But sorting does not work. self.todo_model = gtk.ListStore(gobject.TYPE_PYOBJECT) # Create a TreeModelFilter to control row visibility self.todo_filter = self.todo_model.filter_new() self.todo_filter.set_visible_func(self.todo_visible_filter) # Create a TreeModelSort to wrap the TreeModelFilter self.todo_sort = gtk.TreeModelSort(self.todo_filter) # Set a sort function self.todo_sort.set_default_sort_func(TaskList.sort, None) # Set the model in the view to the TreeModelSort self.todo_task_view.set_model(self.todo_sort) TaskList.sort --- @staticmethod def sort(model, iter1, iter2, user_data): print 'SORT', model, iter1, iter2 sort_by = model.get_sort_column_id() This fails because model is a TreeModelFilter... which does not have a method get_sort_column_id why isn't this the TreeModelSort object? [that is the model directly owned by the view. Does anyone have a working example of a filtered sortable list? ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://faq.pygtk.org/