Search code examples
pythontreeviewgtk

Python Gtk TreeView Column Data Display


I have been using the code found here:

How to limit number of decimal places to be displayed in Gtk CellRendererText

successfully for several years to format Treeview number columns. But when I insert columns using a loop, the columns display the data from the first column, rather than the data I would expect to get from the ListStore. Why is this? I've struggled with this for sometime and it probably is a really simple solution, but I am rather clueless!! Thank you very much. Here's a working example that shows my problem:

from gi.repository import Gtk, Gdk
class myClass:
    def __init__(self):
    # Setup
        self.iListstore = Gtk.ListStore(str, float, float, float, float)
        self.iListstore.append(['abc',209.8967,568.56432, 1, 2])
        self.iListstore.append(['def',2409.846,559.534, 3, 4])
        self.window = Gtk.Window()
        self.iTreeView = Gtk.TreeView(self.iListstore)
    # Column 0
        lblr= Gtk.CellRendererText()
        lcol = Gtk.TreeViewColumn('Row Label')
        self.iTreeView.append_column(lcol)
        lcol.pack_start(lblr, True)
        lcol.add_attribute(lblr, 'text',0)
    # Column 1
        cr = Gtk.CellRendererText(xalign=1)
        myCol = Gtk.TreeViewColumn('Col1')
        myCol.set_sort_column_id(1)
        self.iTreeView.append_column(myCol)
        myCol.pack_start(cr, True)
        myCol.add_attribute(cr, 'text',1)
        myCol.set_cell_data_func(cr,lambda column, cell, model, iter, unused:cell.set_property("text","{0:.2f}".format(round(model.get(iter,1)[0],2))))
    # Column 2
        myCol = Gtk.TreeViewColumn('Col2')
        myCol.set_sort_column_id(2)
        self.iTreeView.append_column(myCol)
        myCol.pack_start(cr, True)
        myCol.add_attribute(cr, 'text',2)
        myCol.set_cell_data_func(cr,lambda column, cell, model, iter, unused:cell.set_property("text","{0:.2f}".format(round(model.get(iter,2)[0],2))))
# The above works but the following does not. Col3 has the same value as Col4. Can someone tell me the reason a loop can not be used with the code?
        colNames=['Col3','Col4']
        for i in range(3,5):
            myCol = Gtk.TreeViewColumn(colNames[i-3]) # I realize this is a bit of a fudge 
            myCol.set_sort_column_id(i)
            self.iTreeView.append_column(myCol)
            myCol.pack_start(cr, True)
            myCol.add_attribute(cr, 'text',i)
            myCol.set_cell_data_func(cr,lambda column, cell, model, iter, unused:cell.set_property("text","{0:.2f}".format(round(model.get(iter,i)[0],2))))
    # Window
            self.window.add(self.iTreeView)
            self.window.show_all()

    def main(self):
        Gtk.main()

    p=myClass()
    p.main()

Solution

  • Just indeed the set_cell_data_func is a pivotal point for formatting text in a treeviewcolumn cell. I simplified the above answer, all is done in one go via a for loop. For the real formatting you can use the new f-string feature.

    import gi
    gi.require_version("Gtk", "3.0")
    from gi.repository import Gtk, Gdk
    
    class myClass:
        def __init__(self):
        # Setup
            self.window = Gtk.Window()
            iListstore = Gtk.ListStore(str, float, float, float, float)
            iListstore.append(['abc',209.8967,568.56432, 1, 2])
            iListstore.append(['def',2409.846,559.534, 3, 4])
            self.iTreeView = Gtk.TreeView(model=iListstore)
            self.window.add(self.iTreeView)
            treeview_columns = ['Row Label', 'Col1', 'Col2', 'Col3', 'Col4']
            for col_num, name in enumerate(treeview_columns):
                # align text in column cells of row (0.0 left, 0.5 center, 1.0 right)
                rendererText = Gtk.CellRendererText(xalign=1.0, editable=False)
                column = Gtk.TreeViewColumn(name ,rendererText, text=col_num)
                column.set_cell_data_func(rendererText, self.celldatafunction, func_data=col_num)
                # center the column titles in first row
                column.set_alignment(0.5)
                # make all the column reorderable, resizable and sortable
                column.set_sort_column_id(col_num)
                column.set_reorderable(True)
                column.set_resizable(True)
                self.iTreeView.append_column(column)
        # Window
            self.window.connect("destroy", Gtk.main_quit)
            self.window.show_all()
    
        def celldatafunction(self, col, cell, mdl, itr, i):
        # col = Columnn, cell = Cell, mdl = model, itr = iter, i = column number
        # column is provided by the function, but not used
            value = mdl.get(itr,i)[0]
            if type(value) is not str:
                cell.set_property('text',f'{value+0.005:.2f}')
            path = mdl.get_path(itr)
            row = path[0]
            colors = ['white', 'lightskyblue']
        # set alternating backgrounds
            cell.set_property('cell-background', colors[row % 2])
    
        def main(self):
            Gtk.main()
    
    p = myClass()
    p.main()