As a beginner in programming, and especially in Python, I have found it quite easy to create new types by simply writing new classes. One could, of course, take a lower-level approach and extend Python using the C/C++ API, but that would miss the point of programming in Python: to write readable, clean code and fast. The Traits package is something that makes the former approach more palatable. It does so by adding a number of characteristics to Python class attributes, like initializing default values for attributes, restricting attributes by their respective properties, notifying the user about changes in attributes, etc. These advantages make Traits particularly effective for GUI design - users might want to interactively modify attributes, visualize the return values of different methods, etc. The visualization of traits is supported by the TraitsUI package.
To demonstrate the graphical and interactive modification of traits, consider the following snippet:
from traits.api import HasTraits, CInt, Enum
class Camera(HasTraits):
gain = Enum(1,2,3, desc = 'The gain index of the camera',
label = 'Gain')
exposure = CInt(10, desc = 'Exposure in ms',
label = 'Exposure')
def capture(self):
print "capturing an image at %i ms exposure, gain: %i" %
(self.exposure, self.gain )
Camera().configure_traits()
Let's consider the trait attributes in the Camera class. The HasTraits class can be subclassed to create the most commonly used traits required in UI applications. The gain of a camera can be (virtually) any real number, but in this case we wish to assign the gain trait a predefined set of integers. For this we use the Enum trait, which is used to assign a predefined set of values to a trait, and they do not have to be of the same type. The default value of an Enum trait is the first value passed to it - in this case, 1. The next trait, CInt, is called a casting trait. Casting traits can be used to cast the type of the value to the type that is required by the trait. When the class is instantiated and the configure_traits() method is called on it, it automatically creates the widgets required by the UI. The user does not have to worry about the layers between writing algorithms and rendering widgets.
A great variety of traits are available in the package, most of them with characteristic visual properties.
Interactive GUIs with Traits
A major advantage of using traits is its notification property. This is indispensable in making interactive GUIs. There are many ways of making a Python programme react to changes in variables. Trait notifications are particularly effective in accomplishing this graphically. Consider the following code snippet:
from traits.api import HasTraits
class EchoBox(HasTraits):
input = Str
output = Str
def _input_changed(self):
output = self.input
EchoBox().configure_traits()
For any trait foo, a notification for it's change can be created by writing a method _foo_changed(). If we use a Button object in a UI, then the notification is made by writing a _bar_fired() method in the class (where bar is the name of the Button object). This is illustrated in the following snippet:
from traits.api import HasTraits, Button, Int
from traitsui.api import View, Item
class ButtonClick(HasTraits):
value = Int()
add_one = Button()
def _add_one_fired(self):
self.value += 1
view = View('value', Item('add_one', show_label = False))
ButtonClick().configure_traits()
The View and Item classes from the traitsui.api module are used to add different panels to one TraitsUI window.More with Traits
I have taken a very minimal approach to Traits so far. In the next post I will write about embedding 2-D plots in TraitsUI, for which I will use ETS Chaco. Chaco is a very convenient package for adding 2-D plotting functionality to a TraitsUI, as it is fully integrated with Traits. Even standalone Chaco plot widgets require Traits to be rendered. I have omitted a few parts of the original tutorial - especially the parts on executing event loops via threads and ensuring safety of these threads. I will rewrite the tutorial when I have played around with Traits a bit.



