16.2. ComboBox and ComboBoxEntry Widgets

16.2.1. ComboBox Widgets

The ComboBox replaces the OptionMenu with a powerful widget that uses a TreeModel (usually a ListStore) to provide the list items to display. The ComboBox implements the CellLayout interface that provides a number of methods for managing the display of the list items. One or more CellRenderers can be packed into a ComboBox to customize the list item display.

16.2.1.1. Basic ComboBox Use

The easy way to create and populate a ComboBox is to use the convenience function:

  combobox = gtk.combo_box_new_text()

This function creates a ComboBox and its associated ListStore and packs it with a CellRendererText. The following convenience methods are used to populate or remove the contents of the ComboBox and its ListStore:

  combobox.append_text(text)
  combobox.prepend_text(text)
  combobox.insert_text(position, text)
  combobox.remove_text(position)

where text is the string to be added to the ComboBox and position is the index where text is to be inserted or removed. In most cases the convenience function and methods are all you need.

The example program comboboxbasic.py demonstrates the use of the above function and methods. Figure 16.5, “Basic ComboBox” illustrates the program in operation:

Figure 16.5. Basic ComboBox

Basic ComboBox

Unfortunately, the GTK+ developers did not provide a convenience method to retrieve the active text. That would seem to be a useful method. You'll have to create your own similar to:

  def get_active_text(combobox):
      model = combobox.get_model()
      active = combobox.get_active()
      if active < 0:
          return None
      return model[active][0]

The index of the active item is retrieved using the method:

  active = combobox.get_active()

The active item can be set using the method:

  combobox.set_active(index)

where index is an integer larger than -2. If index is -1 there is no active item and the ComboBox display will be blank. If index is less than -1, the call will be ignored. If index is greater than -1 the list item with that index value will be displayed.

You can connect to the "changed" signal of a ComboBox to be notified when the active item has been changed. The signature of the "changed" handler is:

  def changed_cb(combobox, ...):

where ... represents the zero or more arguments passed to the GObject.connect() method.

16.2.1.2. Advanced ComboBox Use

Creating a ComboBox using the gtk.combo_box_new_text() function is roughly equivalent to the following code:

  liststore = gtk.ListStore(str)
  combobox = gtk.ComboBox(liststore)
  cell = gtk.CellRendererText()
  combobox.pack_start(cell, True)
  combobox.add_attribute(cell, 'text', 0)  

To make use of the power of the various TreeModel and CellRenderer objects you need to construct a ComboBox using the constructor:

  combobox = gtk.ComboBox(model=None)

where model is a TreeModel. If you create a ComboBox without associating a TreeModel, you can add one later using the method:

  combobox.set_model(model)

The associated TreeModel can be retrieved using the method:

  model = combobox.get_model()

Some of the things you can do with a ComboBox are:

  • Share the same TreeModel with other ComboBoxes and TreeViews.
  • Display images and text in the ComboBox list items.
  • Use an existing TreeStore or ListStore as the model for the ComboBox list items.
  • Use a TreeModelSort to provide a sorted ComboBox list.
  • Use a TreeModelFilter to use a subtree of a TreeStore as the source for a ComboBox list items.
  • Use a TreeModelFilter to use a subset of the rows in a TreeStore or ListStore as the ComboBox list items.
  • Use a cell data function to modify or synthesize the display for list items.

The use of the TreeModel and CellRenderer objects is detailed in Chapter 14, Tree View Widget.

The ComboBox list items can be displayed in a grid if you have a large number of items to display. Otherwise the list will have scroll arrows if the entire list cannot be displayed. The following method is used to set the number of columns to display:

  combobox.set_wrap_width(width)

where width is the number of columns of the grid displaying the list items. For example, the comboboxwrap.py program displays a list of 50 items in 5 columns. Figure 16.6, “ComboBox with Wrapped Layout” illustrates the program in operation:

Figure 16.6. ComboBox with Wrapped Layout

ComboBox with Wrapped Layout

With a large number of items, say more than 50, the use of the set_wrap_width() method will have poor performance because of the computation for the grid layout. To get a feel for the affect modify the comboboxwrap.py program line 18 to display 150 items.

        for n in range(150):

Run the program and get a time estimate for startup. Then modify it by commenting out line 17:

        #combobox.set_wrap_width(5)

Run and time it again. It should start up significantly faster. My experience is about 20 times faster.

In addition to the get_active() method described above, you can retrieve a TreeIter pointing at the active row by using the method:

  iter = combobox.get_active_iter()

You can also set the active list item using a TreeIter with the method:

  combobox.set_active_iter(iter)

The set_row_span_column() and set_column_span_column() methods are supposed to allow the specification of a TreeModel column number that contains the number of rows or columns that the list item is supposed to span in a grid layout. Unfortunately, in GTK+ 2.4 these methods are broken.

Since the ComboBox implements the CellLayout interface which has similar capabilities as the TreeViewColumn (see Section 14.5, “TreeViewColumns” for more information). Briefly, the interface provides:

  combobox.pack_start(cell, expand=True)
  combobox.pack_end(cell, expand=True)
  combobox.clear()

The first two methods pack a CellRenderer into the ComboBox and the clear() method clears all attributes from all CellRenderers.

The following methods:

  comboboxentry.add_attribute(cell, attribute, column)

  comboboxentry.set_attributes(cell, ...)

set attributes for the CellRenderer specified by cell. The add_attribute() method takes a string attribute name (e.g. 'text') and an integer column number of the column in the TreeModel to use to set attribute. The additional arguments to the set_attributes() method are attribute=column pairs (e.g text=1).

16.2.2. ComboBoxEntry Widgets

The ComboBoxEntry widget replaces the Combo widget. It is subclassed from the ComboBox widget and contains a child Entry widget that has its contents set by selecting an item in the dropdown list or by direct text entry either from the keyboard or by pasting from a Clipboard or a selection.

16.2.2.1. Basic ComboBoxEntry Use

Like the ComboBox, the ComboBoxEntry can be created using the convenience function:

  comboboxentry = gtk.combo_box_entry_new_text()

The ComboBoxEntry should be populated using the ComboBox convenience methods described in Section 16.2.1.1, “Basic ComboBox Use”.

Since a ComboBoxEntry widget is a Bin widget its child Entry widget is available using the "child" attribute or the get_child() method:

  entry = comboboxentry.child
  entry = comboboxentry.get_child()

You can retrieve the Entry text using its get_text() method.

Like the ComboBox, you can track changes in the active list item by connecting to the "changed" signal. Unfortunately, this doesn't help track changes to the text in the Entry child that are direct entry. When a direct entry is made to the child Entry widget the "changed" signal will be emitted but the index returned by the get_active() method will be -1. To track all changes to the Entry text, you'll have to use the Entry "changed" signal. For example:

  def changed_cb(entry):
      print entry.get_text()

  comboboxentry.child.connect('changed', changed_cb)

will print out the text after every change in the child Entry widget. For example, the comboboxentrybasic.py program demonstrates the use of the convenience API. Figure 16.7, “Basic ComboBoxEntry” illustrates the program in operation:

Figure 16.7. Basic ComboBoxEntry

Basic ComboBoxEntry

Note that when the Entry text is changed due to the selection of a dropdown list item the "changed" handler is called twice: once when the text is cleared; and, once when the text is set with the selected list item text.

16.2.2.2. Advanced ComboBoxEntry Use

The constructor for a ComboBoxEntry is:

  comboboxentry = gtk.ComboBoxEntry(model=None, column=-1)

where model is a TreeModel and column is the number of the column in model to use for setting the list items. If column is not specified the default value is -1 which means the text column is unset.

Creating a ComboBoxEntry using the convenience function gtk.combo_box_entry_new_text() is equivalent to the following:

  liststore = gtk.ListStore(str)
  comboboxentry = gtk.ComboBoxEntry(liststore, 0)

The ComboBoxEntry adds a couple of methods that are used to set and retrieve the TreeModel column number to use for setting the list item strings:

  comboboxentry.set_text_column(text_column)
  text_column = comboboxentry.get_text_column()

The text column can also be retrieved and set using the "text-column" property. See Section 16.2.1.2, “Advanced ComboBox Use” for more information on the advanced use of the ComboBoxEntry.

Note

Your application must set the text column for the ComboBoxEntry to set the Entry contents from the dropdown list. The text column can only be set once, either by using the constructor or by using the set_text_column() method.

When a ComboBoxEntry is created it is packed with a new CellRendererText which is not accessible. The 'text' attribute for the CellRendererText has to be set as a side effect of setting the text column using the set_text_column() method. You can pack additional CellRenderers into a ComboBoxEntry for display in the dropdown list. See Section 16.2.1.2, “Advanced ComboBox Use” for more information.