14.4. CellRenderers
Prev | Chapter 14. Tree View Widget | Next

## 14.4. CellRenderers

### 14.4.1. Overview

`TreeViewColumn`s and `CellRenderer`s work together to display a column of data in a `TreeView`. The `TreeViewColumn` provides the column title and a vertical space for the `CellRenderer`s to render a portion of the data from the `TreeView` data store. A `CellRenderer` handles the rendering of each row and column data within the confines of the `TreeViewColumn`. A `TreeViewColumn` can contain more than one `CellRenderer` to provide a row display similar to an `HBox`. A common use of multiple `CellRenderer`s is to combine a `CellRendererPixbuf` and a `CellRendererText` in one column.

An example illustrating the layout of two `TreeViewColumn`s: one with two`CellRenderer`s and one with one `CellRenderer` is shown in Figure 14.2, “TreeViewColumns with CellRenderers”:

Figure 14.2. TreeViewColumns with CellRenderers

The application of each `CellRenderer` is indicated with a different background color: yellow for the `CellRendererPixbuf`, cyan for one `CellRendererText`, and pink for the other `CellRendererText`. Note that the `CellRendererPixbuf` and the first `CellRendererText` are in the same column headed by the "Pixbuf and Text" header. The background color of the `CellRendererText` rendering "Print File" is the default color to show the application area in a single row.

Figure 14.2, “TreeViewColumns with CellRenderers” was created by the treeviewcolumn.py program.

### 14.4.2. CellRenderer Types

The type of `CellRenderer` needed is determined by the type of tree model data display required; PyGTK has three pre-defined `CellRenderer`s:

`CellRendererPixbuf` | renders pixbuf images either created by the program or one of the stock items.
`CellRendererText` | renders text strings, and numbers that can be converted to a string (including ints, floats, booleans).
`CellRendererToggle` | renders a boolean value as a toggle button or a radio button

### 14.4.3. CellRenderer Properties

The properties of a `CellRenderer` determine how the data will be rendered:

"mode" | Read-Write | The editable mode of the `CellRenderer`. One of: `gtk.CELL_RENDERER_MODE_INERT`, `gtk.CELL_RENDERER_MODE_ACTIVATABLE` or `gtk.CELL_RENDERER_MODE_EDITABLE`
"visible" | Read-Write | If `TRUE` the cell is displayed
"xalign" | Read-Write | The fraction of free space to the left of the cell in the range 0.0 to 1.0.
"yalign" | Read-Write | The fraction of free space above the cell in the range 0.0 to 1.0.
"xpad" | Read-Write | The amount of padding to the left and right of the cell.
"ypad" | Read-Write | The amount of padding above and below cell.
"width" | Read-Write | The fixed width of the cell.
"height" | Read-Write | The fixed height of the cell.
"is-expander" | Read-Write | If `TRUE` the row has children
"is-expanded" | Read-Write | If `TRUE` the row has children and it is expanded to show the children.
"cell-background" | Write | The background color of the cell as a string.
"cell-background-gdk" | Read-Write | The background color of the cell as a `gtk.gdk.Color`.
"cell-background-set" | Read-Write | If `TRUE` the cell background color is set by this cellrenderer

The above properties are available for all `CellRenderer` subclasses. The individual `CellRenderer` types also have their own properties.

The `CellRendererPixbuf` has these properties:

"pixbuf" | Read-Write | The pixbuf to render - overridden by "stock-id"
"pixbuf-expander-open" | Read-Write | Pixbuf for open expander.
"pixbuf-expander-closed" | Read-Write | Pixbuf for closed expander.
"stock-id" | Read-Write | The stock ID of the stock icon to render
"stock-size" | Read-Write | The size of the rendered icon
"stock-detail" | Read-Write | Render detail to pass to the theme engine

The `CellRendererText` has a large number of properties mostly dealing with style specification:

"text" | Read-Write | Text to render
"markup" | Read-Write | Marked up text to render.
"attributes" | Read-Write | A list of style attributes to apply to the text of the renderer.
"background" | Write | Background color as a string
"foreground" | Write | Foreground color as a string
"background-gdk" | Read-Write | Background color as a `gtk.gdk.Color`
"foreground-gdk" | Read-Write | Foreground color as a `gtk.gdk.Color`
"font" | Read-Write | Font description as a string
"font-desc" | Read-Write | Font description as a `pango.FontDescription`
"family" | Read-Write | Name of the font family, e.g. Sans, Helvetica, Times, Monospace
"style" | Read-Write | Font style
"variant" | Read-Write | Font variant
"weight" | Read-Write | Font weight
"stretch" | Read-Write | Font stretch
"size" | Read-Write | Font size
"size-points" | Read-Write | Font size in points
"scale" | Read-Write | Font scaling factor
"editable" | Read-Write | If `TRUE` the text can be modified by the user
"strikethrough" | Read-Write | If `TRUE` strike through the text
"underline" | Read-Write | Style of underline for this text
"rise" | Read-Write | Offset of text above the baseline (below the baseline if rise is negative)
"language" | Read-Write | The language this text is in, as an ISO code. Pango can use this as a hint when rendering the text. If you don't understand this parameter, you probably don't need it. GTK+ 2.4 and above.
"single-paragraph-mode" | Read-Write | If `TRUE`, keep all text in a single paragraph. GTK+ 2.4 and above.

"background-set" | Read-Write | If `TRUE` apply the background color
"foreground-set" | Read-Write | If `TRUE` apply the foreground color
"family-set" | Read-Write | If `TRUE` apply the font family
"style-set" | Read-Write | If `TRUE` apply the font style
"variant-set" | Read-Write | If `TRUE` apply the font variant
"weight-set" | Read-Write | If `TRUE` apply the font weight
"stretch-set" | Read-Write | If `TRUE` apply the font stretch
"size-set" | Read-Write | If `TRUE` apply the font size
"scale-set" | Read-Write | If `TRUE` scale the font
"editable-set" | Read-Write | If `TRUE` apply the text editability
"strikethrough-set" | Read-Write | If `TRUE` apply the strikethrough
"underline-set" | Read-Write | If `TRUE` apply the text underlining
"rise-set" | Read-Write | If `TRUE` apply the rise
"language-set" | Read-Write | If `TRUE` apply the language used to render the text. GTK+ 2.4 and above.

Almost every `CellRendererText` property has an associated boolean property (with the "-set" suffix) that indicates if the property is to be applied. This allows you to set a property globally and selectively enable and disable its application.

The `CellRendererToggle` has the following properties:

"activatable" | Read-Write | If `TRUE`, the toggle button can be activated
"active" | Read-Write | If `TRUE`, the button is active.
"radio" | Read-Write | If `TRUE`, draw the toggle button as a radio button
"inconsistent" | Read-Write | If `TRUE`, the button is in an inconsistent state. GTK+ 2.2 and above.

The properties can be set for all rows by using the `gobject.set_property`() method. See the treeviewcolumn.py program for an example using this method.

### 14.4.4. CellRenderer Attributes

An attribute associates a tree model column with a `CellRenderer` property; the `CellRenderer` sets the property from the row's column value before rendering the cell. This allows you to customize the cell display using tree model data. An attribute can be added to the current set by using:

      treeviewcolumn.add_attribute(cell_renderer, attribute, column)

where the property specified by `attribute` is set for the `cell_renderer` from `column`. For example:

      treeviewcolumn.add_attribute(cell, "cell-background", 1)

sets the `CellRenderer` background to the color specified by the string in the second column of the data store.

To clear all attributes and set several new attributes at once use:

      treeviewcolumn.set_attributes(cell_renderer, ...)

where the attributes of `cell_renderer` are set by key-value pairs: property=column. For example, for a `CellRendererText`:

      treeviewcolumn.set_attributes(cell, text=0, cell_background=1, xpad=3)

sets, for each row, the text from the first column, the background color from the second column and the horizontal padding from the fourth column. See the treeviewcolumn.py program for an example using these methods.

The attributes of a `CellRenderer` can be cleared using:

      treeviewcolumn.clear_attributes(cell_renderer)

### 14.4.5. Cell Data Function

If setting attributes is not sufficient for your needs you can set a function to be called for each row to set the properties for that `CellRenderer` using:

      treeviewcolumn.set_cell_data_func(cell_renderer, func, data=None)

where `func` has the signature:

      def func(column, cell_renderer, tree_model, iter, user_data)

where `column` is the `TreeViewColumn` containing `cell_renderer`, `tree_model` is the data store and `iter` is a `TreeIter` pointing at a row in `tree_model`. `user_data` is the value of `data` that was passed to `set_cell_data_func`().

In `func` you set whatever properties you want on `cell_renderer`. For example the following code fragment sets the text property to display PyGTK objects as an ID string.

      ...
      def obj_id_str(treeviewcolumn, cell_renderer, model, iter):
          pyobj = model.get_value(iter, 0)
          cell.set_property('text', str(pyobj))
          return
      ...
      treestore = gtk.TreeStore(object)
      win = gtk.Window()
      treeview = gtk.TreeView(treestore)
      win.add(treeview)
      cell = CellRendererText()
      tvcolumn = gtk TreeViewColumn('Object ID', cell)
      treeview.append_column(tvcolumn)
      iter = treestore.append(None, [win])
      iter = treestore.append(iter, [treeview])
      iter = treestore.append(iter, [tvcolumn])
      iter = treestore.append(iter, [cell])
      iter = treestore.append(None, [treestore])
      ...

The resulting display should be something like Figure 14.3, “CellRenderer Data Function”:

Figure 14.3. CellRenderer Data Function

Another use of a cell data function is to control the formatting of a numerical text display e.g. a float value. A `CellRendererText` will display and automatically convert a float to a string but with a default format "%f".

With cell data functions you can even generate the cell data for the columns from external data. For example the filelisting.py program uses a `ListStore` with just one column that holds a list of file names. The `TreeView` displays columns that include a pixbuf, the file name and the file's size, mode and time of last change. The data is generated by the following cell data functions:

        def file_pixbuf(self, column, cell, model, iter):
            filename = os.path.join(self.dirname, model.get_value(iter, 0))
            filestat = statcache.stat(filename)
            if stat.S_ISDIR(filestat.st_mode):
                pb = folderpb
            else:
                pb = filepb
            cell.set_property('pixbuf', pb)
            return

        def file_name(self, column, cell, model, iter):
            cell.set_property('text', model.get_value(iter, 0))
            return

        def file_size(self, column, cell, model, iter):
            filename = os.path.join(self.dirname, model.get_value(iter, 0))
            filestat = statcache.stat(filename)
            cell.set_property('text', filestat.st_size)
            return

        def file_mode(self, column, cell, model, iter):
            filename = os.path.join(self.dirname, model.get_value(iter, 0))
            filestat = statcache.stat(filename)
            cell.set_property('text', oct(stat.S_IMODE(filestat.st_mode)))
            return

        def file_last_changed(self, column, cell, model, iter):
            filename = os.path.join(self.dirname, model.get_value(iter, 0))
            filestat = statcache.stat(filename)
            cell.set_property('text', time.ctime(filestat.st_mtime))
            return

These cell data functions retrieve the file information using the name, extract the needed data and set the cell 'text' or 'pixbuf' property with the data. Figure 14.4, “File Listing Example Using Cell Data Functions” shows the example program in action:

Figure 14.4. File Listing Example Using Cell Data Functions

### 14.4.6. CellRendererText Markup

A `CellRendererText` can use Pango markup (by setting the "markup" property) instead of a plain text string to encode various text attributes and provide a rich text display with multiple font style changes. See the Pango Markup reference in the PyGTK Reference Manual for details on the Pango markup language.

The following code fragment illustrates the use of the "markup" property:

      ...
      liststore = gtk.ListStore(str)
      cell = gtk.CellRendererText()
      tvcolumn = gtk.TreeViewColumn('Pango Markup', cell, markup=0)
      ...
      liststore.append(['<span foreground="blue"><b>Pango</b></span> markup can'
    ' change\n<i>style</i> <big>size</big>, <u>underline,'
     <s>strikethrough</s></u>,\n'
    'and <span font_family="URW Chancery L"><big>font family '
    'e.g. URW Chancery L</big></span>\n<span foreground="red">red'
    ' foreground and <span background="cyan">cyan background</span></span>'])
      ...

produces a display similar to Figure 14.5, “CellRendererText Markup”:

Figure 14.5. CellRendererText Markup

If you create pango markup on the fly you have to be careful to replace the characters that are special to the markup language: "<", ">", "&". The Python library function `cgi.escape`() can do these basic conversions.

### 14.4.7. Editable Text Cells

`CellRendererText` cells can be made editable to allow a user to edit the contents of the cell that is selected by clicking it or pressing one of the Return, Enter, Space or Shift+Space keys. A `CellRendererText` is made editable for all rows by setting its "editable" property to `TRUE` as follows:

      cellrenderertext.set_property('editable', True)

Individual cells can be set editable by adding an attribute to the `TreeViewColumn` using the `CellRendererText` similar to:

      treeviewcolumn.add_attribute(cellrenderertext, "editable", 2)

which sets the "editable" property to the value contained in the third column of the data store.

Once the cell editing completes, your application should handle the "edited" signal to retrieve the new text and set the associated data store value. Otherwise the cell value reverts to its original value. The signature of the "edited" signal handler is:

      def edited_cb(cell, path, new_text, user_data)

where `cell` is the `CellRendererText`, `path` is the tree path (as a string) to the row containing the edited cell, `new_text` is the edited text and `user_data` is context data. Since the `TreeModel` is needed to use `path` to set `new_text` in the data store you probably want to pass the `TreeModel` as `user_data` in the `connect`() method:

      cellrenderertext.connect('edited', edited_cb, model)

If you have two or more editable cells in a row, you could pass the `TreeModel` column number as part of `user_data` as well as the `TreeModel`:

      cellrenderertext.connect('edited', edited_cb, (model, col_num))

Then you can set the new text in the "edited" handler similar to this example using a `ListStore`:

      def edited_cb(cell, path, new_text, user_data):
          liststore, column = user_data
          liststore[path][column] = new_text
          return

### 14.4.8. Activatable Toggle Cells

`CellRendererToggle` buttons can be made activatable by setting the "activatable" property to `TRUE`. Similar to editable `CellRendererText` cells the "activatable" property can be set for the entire `CellRendererToggle` set of cells using the `set_property`() method or for individual cells by adding an attribute to the `TreeViewColumn` containing the `CellRendererToggle`.

      cellrenderertoggle.set_property('activatable', True)

      treeviewcolumn.add_attribute(cellrenderertoggle, "activatable", 1)

The setting of the individual toggle buttons can be derived from the values in a `TreeModel` column by adding an attribute, for example:

      treeviewcolumn.add_attribute(cellrenderertoggle, "active", 2)

You should connect to the "toggled" signal to get notification of user clicks on the toggle buttons so that your application can change the value in the data store. For example:

      cellrenderertoggle.connect("toggled", toggled_cb, (model, column))

The callback has the signature:

      def toggled_cb(cellrenderertoggle, path, user_data)

where `path` is the tree path, as a string, pointing to the row containing the toggle that was clicked. You should pass the `TreeModel` and possibly the column index as part of `user_data` to provide the necessary context for setting the data store values. For example, your application can toggle the data store value as follows:

      def toggled_cb(cell, path, user_data):
          model, column = user_data
          model[path][column] = not model[path][column]
          return

If your application wants to display the toggle buttons as radio buttons and have only one be set, it will have to scan the data store to deactivate the active radio button and then set the toggled button. For example:

      def toggled_cb(cell, path, user_data):
          model, column = user_data
          for row in model:
              row[column] = False
          model[path][column] = True
          return

takes the lazy approach of setting all data store values to `FALSE` before setting the value to `TRUE` for the row specified by `path`.

### 14.4.9. Editable and Activatable Cell Example Program

The cellrenderer.py program illustrates the application of editable `CellRendererText` and activatable `CellRendererToggle` cells in a `TreeStore`.

        1   #!/usr/bin/env python
        2   # vim: ts=4:sw=4:tw=78:nowrap
        3   """ Demonstration using editable and activatable CellRenderers """
        4   import pygtk
        5   pygtk.require("2.0")
        6   import gtk, gobject
        7
        8   tasks =  {
        9       "Buy groceries": "Go to Asda after work",
       10       "Do some programming": "Remember to update your software",
       11       "Power up systems": "Turn on the client but leave the server",
       12       "Watch some tv": "Remember to catch ER"
       13       }
       14
       15   class GUI_Controller:
       16       """ The GUI class is the controller for our application """
       17       def __init__(self):
       18           # setup the main window
       19           self.root = gtk.Window(type=gtk.WINDOW_TOPLEVEL)
       20           self.root.set_title("CellRenderer Example")
       21           self.root.connect("destroy", self.destroy_cb)
       22           # Get the model and attach it to the view
       23           self.mdl = Store.get_model()
       24           self.view = Display.make_view( self.mdl )
       25           # Add our view into the main window
       26           self.root.add(self.view)
       27           self.root.show_all()
       28           return
       29       def destroy_cb(self, *kw):
       30           """ Destroy callback to shutdown the app """
       31           gtk.main_quit()
       32           return
       33       def run(self):
       34           """ run is called to set off the GTK mainloop """
       35           gtk.main()
       36           return
       37
       38   class InfoModel:
       39       """ The model class holds the information we want to display """
       40       def __init__(self):
       41           """ Sets up and populates our gtk.TreeStore """
       42           self.tree_store = gtk.TreeStore( gobject.TYPE_STRING,
       43                                            gobject.TYPE_BOOLEAN )
       44           # places the global people data into the list
       45           # we form a simple tree.
       46           for item in tasks.keys():
       47               parent = self.tree_store.append( None, (item, None) )
       48               self.tree_store.append( parent, (tasks[item],None) )
       49           return
       50       def get_model(self):
       51           """ Returns the model """
       52           if self.tree_store:
       53               return self.tree_store
       54           else:
       55               return None
       56
       57   class DisplayModel:
       58       """ Displays the Info_Model model in a view """
       59       def make_view( self, model ):
       60           """ Form a view for the Tree Model """
       61           self.view = gtk.TreeView( model )
       62           # setup the text cell renderer and allows these
       63           # cells to be edited.
       64           self.renderer = gtk.CellRendererText()
       65           self.renderer.set_property( 'editable', True )
       66           self.renderer.connect( 'edited', self.col0_edited_cb, model )
       67
       68           # The toggle cellrenderer is setup and we allow it to be
       69           # changed (toggled) by the user.
       70           self.renderer1 = gtk.CellRendererToggle()
       71           self.renderer1.set_property('activatable', True)
       72           self.renderer1.connect( 'toggled', self.col1_toggled_cb, model )   73
       74           # Connect column0 of the display with column 0 in our list model   75           # The renderer will then display whatever is in column 0 of
       76           # our model .
       77           self.column0 = gtk.TreeViewColumn("Name", self.renderer, text=0)   78
       79           # The columns active state is attached to the second column
       80           # in the model.  So when the model says True then the button
       81           # will show as active e.g on.
       82           self.column1 = gtk.TreeViewColumn("Complete", self.renderer1 )
       83           self.column1.add_attribute( self.renderer1, "active", 1)
       84           self.view.append_column( self.column0 )
       85           self.view.append_column( self.column1 )
       86           return self.view
       87       def col0_edited_cb( self, cell, path, new_text, model ):
       88           """
       89           Called when a text cell is edited.  It puts the new text
       90           in the model so that it is displayed properly.
       91           """
       92           print "Change '%s' to '%s'" % (model[path][0], new_text)
       93           model[path][0] = new_text
       94           return
       95       def col1_toggled_cb( self, cell, path, model ):
       96           """
       97           Sets the toggled state on the toggle button to true or false.
       98           """
       99           model[path][1] = not model[path][1]
      100           print "Toggle '%s' to: %s" % (model[path][0], model[path][1],)
      101           return
      102
      103   if __name__ == '__main__':
      104       Store = InfoModel()
      105       Display = DisplayModel()
      106       myGUI = GUI_Controller()
      107       myGUI.run()

The program provides editable cells in the first column and activatable cells in the second column. Lines 64-66 create an editable `CellRendererText` and connect the "edited" signal to the `col0_edited_cb`() callback (lines 87-94) that changes the appropriate row column value in the `TreeStore`. Likewise lines 70-72 create an activatable `CellRendererToggle` and connect the "toggled" signal to the `col1_toggled_cb`() callback (lines 95-101) to change the appropriate row value. When an editable or activatable cell is changed, a message is printed to indicate what the change was.

Figure 14.6, “Editable and Activatable Cells” illustrates the cellrenderer.py program in operation.

Figure 14.6. Editable and Activatable Cells

Prev | Up | Next
14.3. TreeViews | Home | 14.5. TreeViewColumns