[kwlug-disc] Filtering on Two Columns in Gtk+ v3 and Python.
Paul Nijjar
paul_nijjar at yahoo.ca
Fri Jun 11 23:25:14 EDT 2021
Okay, I finally took a look at this.
A Gtk.TreeModelFilter wraps a TreeModel. However, it is itself an
instance of a TreeModel, so you can have one TreeModelFilter use
filter_new() to generate another one. In particular, let's look at the
following snippet from your __init__ function. Once you uncomment your
code (and regroup a little), you have something like:
---
self.current_filter_language = None
self.current_filter_year = None
# Creating the filters, feeding it with the liststore model
self.language_filter = self.software_liststore.filter_new()
self.language_filter.set_visible_func(self.language_filter_func)
self.year_filter = self.software_liststore.filter_new()
self.year_filter.set_visible_func(self.year_filter_func)
---
The line:
self.language_filter = self.software_liststore.filter_new()
says "Take the self.software_liststore TreeModel (which in your case is a ListStore, but that is fine because every ListStore is also a TreeModel) and make a TreeModelFilter that wraps that.
By "stacking" the TreeModelFilters, it means you do not start by wapping the software_liststore, but rather wrapping the existing TreeModelFilter you already made. In particular, the line
self.year_filter = self.software_liststore.filter_new()
changes to
self.year_filter = self.language_filter.filter_new()
What you have now is the original ListStore (self.software_liststore) being wrapped by your language filter (self.language_filter) wrapped by your year filter (self.year_filter).
This makes your code work, as far as I can tell.
The style seems a bit weird -- usually when you duplicate code closely as you do with the year/language filter I get worried -- but looking at the docs maybe this is not avoidable.
- Paul
On Sat, Jun 05, 2021 at 05:13:08AM -0400, John Driezen wrote:
> I am attempting to extend the demo program at
> https://python-gtk-3-tutorial.readthedocs.io/en/latest/treeview.html to
> filter on two columns and sort the resulting filtered rows. The tutorial
> suggests the following: "Instances of Gtk.TreeModelFilter|| can be stacked
> one onto another, to use multiple filters on the same model (in the same way
> you’d use “AND” clauses in a SQL request)." However the tutorial does not
> give an example of this, and my google fu is failing to find an example
> online. My attempt at filtering by two columns follows. The code works
> when filtering by programming language, or when filtering by year. I don't
> know how to filter by both programming language and year. Suggestions
> anyone?
>
> """ Sorted and Filtered TreeView Demo Program. Filters on two columns. """
> import gi
>
> gi.require_version("Gtk", "3.0")
> from gi.repository import Gtk
>
> # list of tuples for each software
> SOFTWARE_LIST = [
> ("Firefox", 2002, "C++"),
> ("Eclipse", 2004, "Java"),
> ("Pitivi", 2004, "Python"),
> ("Netbeans", 1996, "Java"),
> ("Chrome", 2008, "C++"),
> ("Filezilla", 2001, "C++"),
> ("Bazaar", 2005, "Python"),
> ("Git", 2005, "C"),
> ("Linux Kernel", 1991, "C"),
> ("GCC", 1987, "C"),
> ("Frostwire", 2004, "Java"),
> ("Homebank", 1995, "C"),
> ("Tellico", 2001, "C++"),
> ("gLabels", 2001, "C++"),
> ("Deluge", 2007, "Python"),
> ]
>
> class TreeViewFilterWindow(Gtk.Window):
> """ TreeViewFilterWindow class """
> def __init__(self):
> Gtk.Window.__init__(self, title="Treeview Filter Demo")
> self.set_border_width(10)
>
> # Setting up the self.grid in which the elements are to be
> positioned
> self.grid = Gtk.Grid()
> self.grid.set_column_homogeneous(True)
> self.grid.set_row_homogeneous(True)
> self.add(self.grid)
>
> # Creating the ListStore model
> self.software_liststore = Gtk.ListStore(str, int, str)
> for software_ref in SOFTWARE_LIST:
> self.software_liststore.append(list(software_ref))
>
> self.current_filter_language = None
> self.current_filter_year = None
>
> # Creating the filters, feeding it with the liststore model
> self.language_filter = self.software_liststore.filter_new()
> #self.year_filter = self.software_liststore.filter_new()
> # Setting the filter functions
> self.language_filter.set_visible_func(self.language_filter_func)
> #self.year_filter.set_visible_func(self.year_filter_func)
>
> # Creating the treeview, using the sorted filter as a model and
> adding the columns
> self.sortedandfilteredtree =
> Gtk.TreeModelSort(model=self.language_filter)
> #self.sortedandfilteredtree =
> Gtk.TreeModelSort(model=self.year_filter)
> self.sortedtreeview =
> Gtk.TreeView.new_with_model(self.sortedandfilteredtree)
> for i, column_title in enumerate(["Software", "Release Year",
> "Programming Language"]):
> renderer = Gtk.CellRendererText()
> column = Gtk.TreeViewColumn(column_title, renderer, text=i)
> column.set_sort_order(Gtk.SortType.ASCENDING)
> column.set_sort_column_id(i)
> self.sortedtreeview.append_column(column)
>
> # Creating buttons to filter by programming language and setting up
> their events
> self.language_buttons = list()
> for prog_language in ["Java", "C", "C++", "Python", "None"]:
> button = Gtk.Button(label=prog_language)
> self.language_buttons.append(button)
> button.connect("clicked",
> self.on_language_selection_button_clicked)
>
> # Creating buttons to filter by release year and setting up their
> events
> self.year_buttons = list()
> for year in [1987, 1991, 1995, 1996, 2001, 2002, 2004, 2005, 2007,
> 2008, "None"]:
> button = Gtk.Button(label=year)
> self.year_buttons.append(button)
> button.connect("clicked", self.on_year_selection_button_clicked)
>
> # Setting up the layout, putting the treeview in a scrollwindow, and
> the buttons in a
> # set_row_homogeneous
> self.scrollable_treelist = Gtk.ScrolledWindow()
> self.scrollable_treelist.set_vexpand(True)
> self.grid.attach(self.scrollable_treelist, 0, 0, 8, 10)
> self.grid.attach_next_to(self.language_buttons[0],
> self.scrollable_treelist,
> Gtk.PositionType.BOTTOM, 1, 1)
>
> # Layout language selection buttons
> for i, button in enumerate(self.language_buttons[1:]):
> self.grid.attach_next_to(button, self.language_buttons[i],
> Gtk.PositionType.RIGHT, 1, 1)
>
> self.grid.attach_next_to(self.year_buttons[0],
> self.language_buttons[0],
> Gtk.PositionType.BOTTOM, 1, 1)
>
> # Layout year selection buttons
> for i, button in enumerate(self.year_buttons[1:]):
> self.grid.attach_next_to(button, self.year_buttons[i],
> Gtk.PositionType.RIGHT, 1, 1)
>
> self.scrollable_treelist.add(self.sortedtreeview)
>
> self.show_all()
>
> def language_filter_func(self, model, iter, data):
> """ Tests if the language in the row is the one in the filter """
> if self.current_filter_language is None or
> self.current_filter_language == "None":
> return True
> else:
> return model[iter][2] == self.current_filter_language
>
> def year_filter_func(self, model, iter, data):
> """ Tests if the year in the row is the one in the filter. """
> if self.current_filter_year is None or self.current_filter_year ==
> "None":
> return True
> else:
> return model[iter][1] == self.current_filter_year
>
> def on_language_selection_button_clicked(self, widget):
> """ Called on any of the language button clicks """
> # Set the current language filter to the button's
> scrollable_treelist
> self.current_filter_language = widget.get_label()
> print("%s language selected!" % self.current_filter_language)
> # Update the filter, which updates the view in turn
> self.language_filter.refilter()
>
> def on_year_selection_button_clicked(self, widget):
> """ Called on any of the year selection button clicks. """
> if (widget.get_label() == "None"):
> self.current_filter_year = None
> else:
> self.current_filter_year = int(widget.get_label())
> print("year %s selected!" % self.current_filter_year)
> self.year_filter.refilter()
>
> TV_WIN = TreeViewFilterWindow()
> TV_WIN.connect("destroy", Gtk.main_quit)
> TV_WIN.show_all()
> Gtk.main()
>
> _______________________________________________
> kwlug-disc mailing list
> kwlug-disc at kwlug.org
> https://kwlug.org/mailman/listinfo/kwlug-disc_kwlug.org
--
Events: https://feeds.off-topic.kwlug.org
Blog: http://pnijjar.freeshell.org
More information about the kwlug-disc
mailing list