Search code examples
filtercomboboxgtkgtkentry

GTK how to create 3 different filter for 1 Liststore


In GTK/Python, I'm trying to build an interface with nodes.

This is photo of my interface

ChronoMap

I create one liststore and I want to filter different things. The user has to do two actions, first, he has to choose in the combobox the type of filter that he wants to use, if he wants to filter by node's type, node's beginning name or others.

Then in the text entry, he decides what information that he wants to see. Take the exemple of nodes type. There are like 3 different types of nodes, node type 1, node type 2 and node type 3. As an user I want to see only node type 1, so I write 1 in the node entry. Actually I have a problem, it is my filter does not work.

I first create 2 liststores:

    def create_liststore(self):

    if len(self.FdessinCarto.pos) != 0:
                for i,node in enumerate(self.FdessinCarto.pos):
                    self.node_liststore.append([str(node.title),self.controller.model.string_from_numdate(int(node.start_time)),self.controller.model.string_from_numdate(int(node.end_time)),str(node.node_group),str(node.description),str(node.attachment_list)])

    self.edgelist = self.controller.get_edge_list()
    if len(self.edgelist) !=0:
        for i in self.edgelist: 
            edge_prop=self.controller.edge_data(i[0],i[1])
            self.edge_liststore.append([edge_prop['label'],str(i[0].title),str(i[1].title),edge_prop['description'],edge_prop['attachment_list']])        

    #creating the treeview for Node, making it use the filter as a model, and adding the columns
    self.treeviewNode = Gtk.TreeView.new_with_model(self.node_liststore)
    for i, column_title in enumerate(["Name", "Beginning date", "End date", "Type of node", "Description of node","files"]):
        self.Noderenderer = Gtk.CellRendererText()
        self.Noderenderer.set_property("editable", True)
        column = Gtk.TreeViewColumn(column_title, self.Noderenderer, text=i)
        column.set_sort_column_id(0)
        self.treeviewNode.append_column(column)


    #creating the treeview for edge
    self.treeviewEdge = Gtk.TreeView.new_with_model(self.edge_liststore)
    for i, column_title in enumerate(["Name", "Node 1", "Node 2", "Description of edge","file"]):
        self.Edgerenderer = Gtk.CellRendererText()
        self.Edgerenderer.set_property("editable", True)
        column = Gtk.TreeViewColumn(column_title, self.Edgerenderer, text=i)
        column.set_sort_column_id(0)
        self.treeviewEdge.append_column(column)

    self.SWViewListStore.add(self.treeviewNode)
    self.SWEdgeStore.add(self.treeviewEdge)
    self.SWViewListStore.show_all()
    self.SWEdgeStore.show_all()

There are my 3 different filters:

    #creating the filtre
    self.node_beginning_date_filter = self.node_liststore.filter_new()
    self.node_end_date_filter = self.node_liststore.filter_new()
    self.node_type_filter = self.node_liststore.filter_new()


    #setting the filter function, note that we're not using the
    self.node_end_date_filter.set_visible_func(self.node_end_date_filter_func)
    self.node_beginning_date_filter.set_visible_func(self.node_beginning_date_filter_func)
    self.node_type_filter.set_visible_func(self.node_type_filter_func)

Once I change my combo-box, it would activate my function, it took the type of combofilter then also the text of combobox :

    def on_entryComboBox_changed(self,widget):
       textComboFilter = self.View.combo_filter.get_active_text()
       print("textComboFilter %s" %textComboFilter)
        if textComboFilter == "Filter by node's beginning date":
            #print("%s language selected!" % textComboFilter)
            self.View.current_filter = textComboFilter
            self.View.node_beginning_date_filter.refilter() 

        if textComboFilter == "Filter by node's end date":
            #print("%s language selected!" % textComboFilter)
            self.View.current_filter = textComboFilter
            self.View.node_end_date_filter.refilter() 

        if textComboFilter == "Filter by type of node":
            #print("%s language selected!" % textComboFilter)
            self.View.current_filter = textComboFilter
            self.View.node_type_filter.refilter() 

And it does not work.


Solution

  • Finally,

    I manage to answer it on my own.

    You should build one filter rather than three. For people who have the same problem, this is a very good example which helps me to solve my problem.

    Picture of this program

       import gi
       gi.require_version('Gtk', '3.0')
       from gi.repository import Gtk
    
       #list of tuples for each software, containing the software name, initial release, and main programming languages used
       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")]
    
       class TreeViewFilterWindow(Gtk.Window):
    
           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 positionned
               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
    
        #Creating the filter, feeding it with the liststore model
               self.language_filter = self.software_liststore.filter_new()
        #setting the filter function, note that we're not using the
               self.language_filter.set_visible_func(self.language_filter_func)
    
        #creating the treeview, making it use the filter as a model, and adding the columns
               self.treeview = Gtk.TreeView.new_with_model(self.language_filter)
               for i, column_title in enumerate(["Software", "Release Year", "Programming Language"]):
                   renderer = Gtk.CellRendererText()
                   column = Gtk.TreeViewColumn(column_title, renderer, text=i)
                   self.treeview.append_column(column)
    
        #creating buttons to filter by programming language, and setting up their events
               self.buttons = list()
               for prog_language in ["Java", "C", "C++", "Python", "None"]:
                   button = Gtk.Button(prog_language)
                   self.buttons.append(button)
                   button.connect("clicked", self.on_selection_button_clicked)
    
        #setting up the layout, putting the treeview in a scrollwindow, and the buttons in a row
               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.buttons[0], self.scrollable_treelist, Gtk.PositionType.BOTTOM, 1, 1)
               for i, button in enumerate(self.buttons[1:]):
                   self.grid.attach_next_to(button, self.buttons[i], Gtk.PositionType.RIGHT, 1, 1)
               self.scrollable_treelist.add(self.treeview)
    
               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 on_selection_button_clicked(self, widget):
        """Called on any of the button clicks"""
        #we set the current language filter to the button's label
               self.current_filter_language = widget.get_label()
               print("%s language selected!" % self.current_filter_language)
        #we update the filter, which updates in turn the view
               self.language_filter.refilter()
    
    
       win = TreeViewFilterWindow()
       win.connect("delete-event", Gtk.main_quit)
       win.show_all()
       Gtk.main()