1
.. _introduction-to-trait-editor-factories:
3
======================================
4
Introduction to Trait Editor Factories
5
======================================
7
The preceding code samples in this User Manual have been surprisingly simple
8
considering the sophistication of the interfaces that they produce. In
9
particular, no code at all has been required to produce appropriate widgets for
10
the Traits to be viewed or edited in a given window. This is one of the
11
strengths of TraitsUI: usable interfaces can be produced simply and with a
12
relatively low level of UI programming expertise.
14
An even greater strength lies in the fact that this simplicity does not have to
15
be paid for in lack of flexibility. Where a novice TraitsUI programmer can
16
ignore the question of widgets altogether, a more advanced one can select from a
17
variety of predefined interface components for displaying any given Trait.
18
Furthermore, a programmer who is comfortable both with TraitsUI and with UI
19
programming in general can harness the full power and flexibility of the
20
underlying GUI toolkit from within TraitsUI.
22
The secret behind this combination of simplicity and flexibility is a TraitsUI
23
construct called a trait :term:`editor factory`. A trait editor factory
24
encapsulates a set of display instructions for a given :term:`trait type`,
25
hiding GUI-toolkit-specific code inside an abstraction with a relatively
26
straightforward interface. Furthermore, every :term:`predefined trait type` in
27
the Traits package has a predefined trait editor factory that is automatically
28
used whenever the trait is displayed, unless you specify otherwise.
30
Consider the following script and the window it creates:
32
.. _example-12-using-default-trait-editors:
34
.. rubric:: Example 12: Using default trait editors
38
# default_trait_editors.py -- Example of using default
41
from traits.api import HasTraits, Str, Range, Bool
42
from traitsui.api import View, Item
44
class Adult(HasTraits):
48
registered_voter = Bool
51
traits_view = View(Item(name='first_name'),
52
Item(name='last_name'),
54
Item(name='registered_voter'))
56
alice = Adult(first_name='Alice',
59
registered_voter=True)
61
alice.configure_traits()
63
.. figure:: images/ui_for_ex12.jpg
64
:alt: UI showing text boxes for names, slider for Age, and checkbox for voter
66
Figure 12: User interface for Example 12
68
Notice that each trait is displayed in an appropriate widget, even though the
69
code does not explicitly specify any widgets at all. The two Str traits appear
70
in text boxes, the Range is displayed using a combination of a text box and a
71
slider, and the Bool is represented by a checkbox. Each implementation is
72
generated by the default trait editor factory (TextEditor, RangeEditor and
73
BooleanEditor respectively) associated with the trait type.
75
TraitsUI is by no means limited to these defaults. There are two ways to
76
override the default representation of a :term:`trait attribute` in a TraitsUI
79
- Explicitly specifying an alternate trait editor factory
80
- Specifying an alternate style for the editor generated by the factory
82
The remainder of this chapter examines these alternatives more closely.
84
.. _specifying-an-alternate-trait-editor-factory:
86
Specifying an Alternate Trait Editor Factory
87
--------------------------------------------
89
As of this writing the TraitsUI package includes a wide variety of predefined
90
trait editor factories, which are described in
91
:ref:`basic-trait-editor-factories` and :ref:`advanced-trait-editors`. Some
92
additional editor factories are specific to the wxWidgets toolkit and are
93
defined in one of the following packages:
97
- traitsui.wx.extra.windows (specific to Microsoft Windows)
99
These editor factories are described in :ref:`extra-trait-editor-factories`.
101
For a current complete list of editor factories, refer to the *Traits API
104
Other packages can define their own editor factories for their own traits. For
105
example, enthought.kiva.api.KivaFont uses a KivaFontEditor() and
106
enthought.enable2.traits.api.RGBAColor uses an RGBAColorEditor().
108
For most :term:`predefined trait type`\ s (see `Traits User Manual <http://github.enthought.com/traits/index.html>`_), there is
109
exactly one predefined trait editor factory suitable for displaying it: the
110
editor factory that is assigned as its default. [15]_ There are exceptions,
111
however; for example, a Str trait defaults to using a TextEditor, but can also
112
use a CodeEditor or an HTMLEditor. A List trait can be edited by means of
113
ListEditor, TableEditor (if the List elements are HasTraits objects),
114
CheckListEditor or SetEditor. Furthermore, the TraitsUI package includes tools
115
for building additional trait editors and factories for them as needed.
117
To use an alternate editor factory for a trait in a TraitsUI window, you must
118
specify it in the View for that window. This is done at the Item level, using
119
the *editor* keyword parameter. The syntax of the specification is
120
:samp:`editor = {editor_factory}()`. (Use the same syntax for specifying that
121
the default editor should be used, but with certain keyword parameters
122
explicitly specified; see :ref:`initializing-editors`).
124
For example, to display a Str trait called **my_string** using the default
125
editor factory (TextEditor()), the View might contain the following Item::
127
Item(name='my_string')
129
The resulting widget would have the following appearance:
131
.. figure:: images/default_text_editor.gif
132
:alt: Text field showing text that contains HTML markup
134
Figure 13: Default editor for a Str trait
136
To use the HTMLEditor factory instead, add the appropriate specification to the
139
Item( name='my_string', editor=HTMLEditor() )
141
The resulting widget appears as in Figure 14:
143
.. figure:: images/HTML_editor.gif
144
:alt: Same text as Figure 13, styled as HTML
146
Figure 14: Editor generated by HTMLEditor()
148
.. NOTE:: TraitsUI does not check editors for appropriateness.
150
TraitsUI does not police the *editor* argument to ensure that the specified
151
editor is appropriate for the trait being displayed. Thus there is nothing to
152
prevent you from trying to, say, display a Float trait using ColorEditor().
153
The results of such a mismatch are unlikely to be helpful, and can even crash
154
the application; it is up to the programmer to choose an editor sensibly.
155
:ref:`the-predefined-trait-editor-factories` is a useful reference for
156
selecting an appropriate editor for a given task.
158
It is possible to specify the trait editor for a trait in other ways:
160
- You can specify a trait editor when you define a trait, by passing the result
161
of a trait editor factory as the *editor* keyword parameter of the callable
162
that creates the trait. However, this approach commingles the :term:`view` of
163
a trait with its :term:`model`.
164
- You can specify the **editor** attribute of a TraitHandler object. This
165
approach commingles the :term:`view` of a trait with its :term:`controller`.
167
Use these approaches very carefully, if at all, as they muddle the :term:`MVC`
170
.. _initializing-editors:
175
Many of the TraitsUI trait editors can be used "straight from the box" as in
176
the example above. There are some editors, however, that must be initialized in
177
order to be useful. For example, a checklist editor (from CheckListEditor()) and
178
a set editor (from SetEditor()) both enable the user to edit a List attribute by
179
selecting elements from a specified set; the contents of this set must, of
180
course, be known to the editor. This sort of initialization is usually performed
181
by means of one or more keyword arguments to the editor factory, for example::
183
Item(name='my_list',editor=CheckListEditor(values=["opt1","opt2","opt3"]))
185
The descriptions of trait editor factories in
186
:ref:`the-predefined-trait-editor-factories` include a list of required and
187
optional initialization keywords for each editor.
189
.. _specifying-an-editor-style:
191
Specifying an Editor Style
192
--------------------------
194
In TraitsUI, any given trait editor can be generated in one or more of four
195
different styles: *simple*, *custom*, *text* or *readonly*. These styles, which
196
are described in general terms below, represent different "flavors" of data
197
display, so that a given trait editor can look completely different in one style
198
than in another. However, different trait editors displayed in the same style
199
(usually) have noticeable characteristics in common. This is useful because
200
editor style, unlike individual editors, can be set at the Group or View level,
201
not just at the Item level. This point is discussed further in
202
:ref:`using-editor-styles`.
204
.. _the-simple-style:
209
The *simple* editor style is designed to be as functional as possible while
210
requiring minimal space within the window. In simple style, most of the Traits
211
UI editors take up only a single line of space in the window in which they are
214
In some cases, such as the text editor and Boolean editor (see
215
:ref:`basic-trait-editor-factories`), the single line is fully sufficient. In
216
others, such as the (plain) color editor and the enumeration editor, a more
217
detailed interface is required; pop-up panels, drop-down lists, or dialog boxes
218
are often used in such cases. For example, the simple version of the enumeration
219
editor for the wxWidgets toolkit looks like this:
221
.. figure:: images/simple_enum_editor_closed.jpg
222
:alt: Closed drop-list editor
224
Figure 15: Simple style of enumeration editor
226
However, when the user clicks on the widget, a drop-down list appears:
228
.. figure:: images/simple_enum_editor_open.jpg
229
:alt: Expanded drop-list editor
231
Figure 16: Simple enumeration editor with expanded list
233
The simple editor style is most suitable for windows that must be kept small and
239
The *custom* editor style generally generates the most detailed version of any
240
given editor. It is intended to provide maximal functionality and information
241
without regard to the amount of window space used. For example, in the wxWindows
242
toolkit, the custom style the enumeration editor appears as a set of radio
243
buttons rather than a drop-down list:
245
.. figure:: images/custom_enum_editor.jpg
246
:alt: Radio buttons for a set of values
248
Figure 17: Custom style of enumeration editor
250
In general, the custom editor style can be very useful when there is no need to
251
conserve window space, as it enables the user to see as much information as
252
possible without having to interact with the widget. It also usually provides
253
the most intuitive interface of the four.
255
Note that this style is not defined explicitly for all trait editor
256
implementations. If the custom style is requested for an editor for which it is
257
not defined, the simple style is generated instead.
262
The *text* editor style is the simplest of the editor styles. When applied to a
263
given trait attribute, it generates a text representation of the trait value in
264
an editable box. Thus the enumeration editor in text style looks like the
267
.. figure:: images/text_editor.jpg
270
Figure 18: Text style of enumeration editor
272
For this type of editor, the end user must type in a valid value for the
273
attribute. If the user types an invalid value, the validation method for the
274
attribute (see `Traits User Manual <http://github.enthought.com/traits/index.html>`_) notifies the user of the error (for
275
example, by shading the background of the text box red).
277
The text representation of an attribute to be edited in a text style editor is
278
created in one of the following ways, listed in order of priority:
280
#. The function specified in the **format_func** attribute of the Item (see
281
:ref:`the-item-object`), if any, is called on the attribute value.
282
#. Otherwise, the function specified in the *format_func* parameter of the
283
trait editor factory, if any, is called on the attribute value.
284
#. Otherwise, the Python-style formatting string specified in the **format_str**
285
attribute of the Item (see :ref:`the-item-object`), if any, is used to format
287
#. The Python-style formatting string specified in the *format_str* parameter
288
of the trait editor factory, if any, is used to format the attribute value.
289
#. Otherwise, the Python str() function is called on the attribute value.
294
The *readonly* editor style is usually identical in appearance to the text
295
style, except that the value appears as static text rather than in an editable
298
.. figure:: images/read_only_editor.jpg
299
:alt: Read-only text field
301
Figure 19: Read-only style of enumeration editor
303
This editor style is used to display data values without allowing the user to
306
.. _using-editor-styles:
311
As discussed in :ref:`contents-of-a-view` and :ref:`customizing-a-view`, the
312
Item, Group and View objects of TraitsUI all have a **style** attribute. The
313
style of editor used to display the Items in a View is determined as follows:
315
#. The editor style used to display a given Item is the value of its **style**
316
attribute if specifically assigned. Otherwise the editor style of the Group
317
or View that contains the Item is used.
318
#. The editor style of a Group is the value of its **style** attribute if
319
assigned. Otherwise, it is the editor style of the Group or View that
321
#. The editor style of a View is the value of its **style** attribute if
322
specified, and 'simple' otherwise.
324
In other words, editor style can be specified at the Item, Group or View level,
325
and in case of conflicts the style of the smaller scope takes precedence. For
326
example, consider the following script:
328
.. _example-13-using-editor-styles-at-various-levels:
330
.. rubric:: Example 13: Using editor styles at various levels
334
# mixed_styles.py -- Example of using editor styles at
337
from traits.api import HasTraits, Str, Enum
338
from traitsui.api import View, Group, Item
340
class MixedStyles(HasTraits):
344
department = Enum("Business", "Research", "Admin")
345
position_type = Enum("Full-Time",
349
traits_view = View(Group(Item(name='first_name'),
350
Item(name='last_name'),
351
Group(Item(name='department'),
352
Item(name='position_type',
355
title='Mixed Styles',
358
ms = MixedStyles(first_name='Sam', last_name='Smith')
359
ms.configure_traits()
361
Notice how the editor styles are set for each attribute:
363
- **position_type** at the Item level (lines 19-20)
364
- **department** at the Group level (lines 18 and 21)
365
- **first_name** and **last_name** at the View level (lines 16, 17, and 23)
367
The resulting window demonstrates these precedence rules:
369
.. figure:: images/ui_for_ex13.jpg
370
:alt: UI showing read-only text, closed drop-list, and radio buttons
372
Figure 20: User interface for Example 13
375
.. rubric:: Footnotes
377
.. [15] Appendix II contains a table of the predefined trait types in the
378
Traits package and their default trait editor types.