### 2.9.6 Widget support in Proxies

The Proxies provide a quite complex mechanism to handle updates in most of the widgets normally used in "forms". There is a reason for supporting these widgets: they are easily mapped to model attributes. This doesn't mean that you can't use other widgets in your Proxy interface, but there is no automatic update mechanism for it, and you will have to use your own handlers for them.

This is a reasonable property - it would be difficult to map what exactly the state of a gtk.Curve means to the model, for instance - and the Proxy can be extended in the future to support other widgets (write me if you are interested in contributing). What follows is a list of widget types supported, details on the use of them, and details about setting custom handlers if you need them.

- gtk.Entry: the single-line entry box in gtk. Updates the model on insertion or deletion of every character, which means you should make sure your accessors take this into account, if you use accessors (as opposed to `setattr()`). For instance, if you type in "Foobar" into the box, the accessor for that model attribute will be called 6 times.

  Custom handlers: The best signal for hooking a user handler to a gtk.Entry is "changed", preferably by using `after_entryname__changed()`; it will be called immediately after the entry has text inserted or deleted. You can use the individual "insert_text" or "delete_text" signals if you want to capture one of those specific events.

- gtk.Label: a read-only widget that displays text. It is useful for displaying model attributes, but it doesn't generate signals my itself. Use `update()` in other widget's custom handlers to notify the Proxy a calculated label's value has changed.

  Custom handlers: The gtk.Label doesn't generate signals.

- gtk.OptionMenu (OM): the menuitem or listbox widget, containing a list of items. The GTK+ OM has a very evil API by default, but using the Proxy makes it much simpler; basically, the OM's choice reflects directly in the model, without extra effort. The OM items can be created in Glade or straight PyGTK commands; in this case the model attribute will be set to the text in the label selected. To select an item, set the model value to the string of text. The model is updated each time an item is selected in the OM.

  However, this is a very limited way of using the OM, and the recommended way to build your menu is to use Kiwi's `OptionMenu.prefill()` call, which allows you to specify a data value for each item, along with an extra callback to be called when the an item in the OM is selected. This way, the model's attribute can be set to any value per item; for instance, an integer value, or an instance associated with one particular menuitem.

  If you use `OM.prefill()`, each item is associated to a data value, and this value is sent to the model when the item is selected. To select an item from the model, just set the attribute to the data value, and the optionmenu updates itself automatically. Set the model attribute to the data value, and the interface updates automatically. Check the API for OM for more details.

  Custom handlers: as stated above, use `prefill()`'s `callback` parameter to specify a handler for the OptionMenu. There is no signal you can connect to directly in GTK+ 1.2.

- gtk.RadioButton: Handling the radiobutton is slightly more complicated, because there are in reality groups of radiobuttons that bind to a single attribute. In other words, the multiple radiobutton widgets are connected to a single attribute, which assumes a different value depending on which button is toggled.

  To perform this grouping8 the Proxy offers a special method called `group_radiobuttons()`. This method accepts `name` and set of tuples as a parameter, each tuple being in the format `(widget_name, widget_value)`. `name` indicates the model attribute it is to be bound to, `widget_name` is a string strings with the name (like used in the widgets list) of the individual radiobutton to be grouped. Once grouped, these radiobuttons are treated by the Proxy as a single widget attached to the model attribute, and the model attribute or accessor will receive the `widget_value` associated with the button selected. Setting the model value follows the same rule as for OM.

  Custom handlers: use the "clicked" signal, connecting after it (see gtk.Entry above for an `after_*()` example), and check the state of the widget if you need to check if it was selected or de-selected (use `widget['active']` to check the state in your callback).

- gtk.CheckButton and gtk.ToggleButton: the two-state button widgets allow values to be set to True and False. The value is updated every time the button's state changes.

  Custom handlers: use the "clicked" signal, in the same manner as for gtk.RadioButton.

- gtk.SpinButton, gtk.ComboBox and gtk.TextView: similarly to the gtk.Entry, these widgets are updated every time a single character is changed in the editable space (yes, the SpinButton contains an entry). There is no signal that can easily catch when a gtk.ComboBox list item was selected, which is why we have to handle things this was for it. In practice, it should work as expected unless you rely on your accessor being called a specific number of times for each change, which you shouldn't.

  Custom handlers: gtk.SpinButton and gtk.Text are good candidates for the "changed" signal; use the same rules as for gtk.Entry. For gtk.Combo, things are not so easy, because there is no signal it offers you can catch9, and the fact that it holds two subobjects, a gtk.Entry and a gtk.Button, means that you are forced to use `connect()` on either of these to get the effect you desire. In practice, the following works for me (taking into account the fact that the handler will be called multiple times):

          widget = [":combo", ...]
          def __init__(self, *args):
              # [... in constructor ...]
              entry = combo.entry
              entry.connect("changed", on_combo_entry__changed)

          def on_combo_entry__changed(self, entry, *args):
              # [...]

The code in tests/test_Proxy.py offers a sample of using all the supported widgets in the same interface, and is highly recommended for study; it is however a bit too long to include in this text.

#### Footnotes

... grouping8
  Alas, we can't use radiobutton's `group()` method to discover groups automatically because it is yet to be wrapped in PyGTK.
... catch9
  A lively discussion could ensue about gtk.Combo and the lack of a signal that indicates an option was selected in its list, but I deliberately choose to avoid it!