Search code examples
pythonpygtkgtk2gtktreeview

Toggle TreeView row selection individually with each click


I'm using PyGTK 2.0's TreeView backed by a ListStore to create a table of selectable items. I need to select and deselect individual rows by single clicking anywhere on the row. Clicking a row should toggle the highlight and the value of a checkbox only for that row.

I've created the TreeView with multiple selection and a column for the checkboxes, but I can't toggle the selection on an individual row without holding Control. I tried to connect a select function to the view so that it would at least toggle the checkboxes, but the function does not work as described in the tutorial:

    self.dataview = gtk.TreeView(store)
    self.dataview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
    self.dataview.get_selection().set_select_function(self.on_row_selected, None)

def on_row_selected(self, selection, model, path, is_selected, data):
    print selection
    print model
    print path
    print is_selected
    print data
    model.set_value(path, 0, is_selected)

Triggering the select function produces an error:

TypeError: on_row_selected() takes exactly 6 arguments (3 given)

Replacing the function arguments with *args shows that only path and data are provided.

Besides the behavior of set_select_function, what's the best approach to toggling row selection with single clicks, and how do I sync that with a column in my data model?


Solution

  • This isn't exactly what I asked for but I finally got the interaction I wanted using gtk.TreeViewColumn.set_cell_data_func. This allows me to specify a function that will be called whenever a cell is to be rendered. I used it to apply a custom style across the whole row based on its data, and then used single-selection clicks just to toggle the value.

        self.view = gtk.TreeView(store)
        self.view.get_selection().set_mode(gtk.SELECTION_SINGLE)
        self.view.get_selection().set_select_function(self.on_row_selected)
        ...
        renderer = gtk.CellRendererText()
        for idx, heading in enumerate(heading_list):
            col = gtk.TreeViewColumn(None, renderer, text=idx)
            col.set_cell_data_func(renderer, self.cell_data_func)
    
    ...
    
    def cell_data_func(self, column, cell, model, it):
        if model.get(it, self.select_index)[0]:
            # apply selected style
        else:
            # apply normal style
    
    def on_row_selected(self, data):
        path = data[0]
        iter = self.model.get_iter(path)
        val = self.model.get_value(iter, self.select_index)
        self.model.set_value(iter, self.select_index, not val)