1
# Copyright (c) 2007, Enthought, Inc.
4
#--(Extended Traits UI Item and Editor References)------------------------------
6
Extended Traits UI Item and Editor References
7
=============================================
9
In Traits 3.0, the Traits UI **Item** class and various *editor* classes
10
have been extended to use the new extended trait name support provided by the
11
*on_trait_change* method.
13
In previous Traits versions, for example, **Item** objects could only refer to
14
traits defined directly on a UI context object. For example::
19
Item( 'handler.status' )
22
In Traits 3.0 this restriction has been lifted, and now **Items** can reference
23
(i.e. edit) any trait reachable from a UI context object::
26
Item( 'object.mother.name' ),
27
Item( 'object.axel.chassis.serial_number', style = 'readonly' )
30
Similarly, any Traits UI *editor* classes that previously accepted a trait name
31
now accept an extended trait name::
35
Item( 'state', editor = EnumEditor( name = 'handler.country.states' )
38
Because **Items** and *editors* only refer to a single trait, you should not use
39
extended trait references that refer to multiple traits, such as
40
*'foo.[bar,baz]'* or *'foo.+editable'*, since the behavior of such references
43
Look at the code tabs for this lesson for a complete example of a Traits UI
44
using extended **Item** and editor references. In particular, the
45
**LeagueModelView Class** tab contains a **View** definition containing
48
Code Incompatibilities
49
----------------------
51
Note that the editor enhancement may cause some incompatibities with editors
52
that previously supported both an *object* and *name* trait, with the *object*
53
trait containing the context object name, and the *name* trait containing the
54
name of the trait on the specified context object. Using the new extended trait
55
references, these have been combined into a single *name* trait.
57
If you encounter such an occurrence in existing code, simply combine the
58
context object name and trait name into a single extended name of the form::
60
context_object_name.trait_name
65
Avoid extended **Item** references that contain intermediate links that could
66
be *None*. For example, in the following code::
70
Item( 'object.team.players', ... )
74
an exception will be raised if *object.team* is *None*, or is set to *None*,
75
while the view is active, since there is no obvious way to obtain a valid value
76
for *object.team.players* for the associated **Item** *editor* to display.
78
Note that the above example is borrowed from this lesson's demo code, which has
79
additional code written to ensure that *object.team* is not *None*. See the
80
*_model_changed* method in the **LeagueModelView Class** tab, which makes sure
81
that the *team* trait is intialized to a valid value when a new **League**
85
#--<Imports>--------------------------------------------------------------------
93
from traitsui.table_column \
96
#--[Player Class]---------------------------------------------------------------
98
# Define a baseball player:
99
class Player ( HasTraits ):
101
# The name of the player:
102
name = Str( '<new player>' )
104
# The number of hits the player made this season:
107
#--[Team Class]-----------------------------------------------------------------
109
# Define a baseball team:
110
class Team ( HasTraits ):
112
# The name of the team:
113
name = Str( '<new team>' )
115
# The players on the team:
116
players = List( Player )
118
# The number of players on the team:
119
num_players = Property( depends_on = 'players' )
121
def _get_num_players ( self ):
122
""" Implementation of the 'num_players' property.
124
return len( self.players )
126
#--[League Class]---------------------------------------------------------------
128
# Define a baseball league model:
129
class League ( HasTraits ):
131
# The name of the league:
132
name = Str( '<new league>' )
134
# The teams in the league:
137
#--[LeagueModelView Class]-----------------------------------------------------
139
# Define a ModelView for a League model:
140
class LeagueModelView ( ModelView ):
142
# The currently selected team:
143
team = Instance( Team )
145
# The currently selected player:
146
player = Instance( Player )
148
# Button to add a hit to the current player:
149
got_hit = Button( 'Got a Hit' )
151
# The total number of hits
152
total_hits = Property( depends_on = 'model.teams.players.hits' )
155
def _get_total_hits ( self ):
156
""" Returns the total number of hits across all teams and players.
159
return reduce( add, [ reduce( add, [ p.hits for p in t.players ], 0 )
160
for t in self.model.teams ], 0 )
165
Item( 'total_hits', style = 'readonly' ),
166
label = 'League Statistics',
172
editor = TableEditor(
173
columns = [ ObjectColumn( name = 'name',
175
ObjectColumn( name = 'num_players',
179
selected = 'object.team',
182
configurable = False,
185
label = 'League Teams',
189
Item( 'object.team.players', # <-- Extended Item name
191
editor = TableEditor(
192
columns = [ ObjectColumn( name = 'name',
194
ObjectColumn( name = 'hits',
197
selected = 'object.player',
199
row_factory = Player,
200
configurable = False,
207
enabled_when = 'player is not None'
210
label = 'Team Players',
218
def _model_changed ( self, model ):
219
""" Handles the 'league' model being initialized.
221
if len( model.teams ) > 0:
222
self.team = model.teams[0]
224
def _got_hit_changed ( self ):
225
""" Handles the currently selected player making a hit.
227
self.player.hits += 1
229
def _team_changed ( self, team ):
230
""" Handles a new team being selected.
232
if len( team.players ) > 0:
233
self.player = team.players[0]
237
# Function to add two numbers (used with 'reduce'):
238
add = lambda a, b: a + b
240
#--[Example*]-------------------------------------------------------------------
242
# Define some sample teams and players:
243
blue_birds = Team( name = 'Blue Birds', players = [
244
Player( name = 'Mike Scott', hits = 25 ),
245
Player( name = 'Willy Shofield', hits = 37 ),
246
Player( name = 'Tony Barucci', hits = 19 ) ] )
248
chicken_hawks = Team( name = 'Chicken Hawks', players = [
249
Player( name = 'Jimmy Domore', hits = 34 ),
250
Player( name = 'Bill Janks', hits = 16 ),
251
Player( name = 'Tim Saunders', hits = 27 ) ] )
253
eagles = Team( name = 'Eagles', players = [
254
Player( name = 'Joe Peppers', hits = 33 ),
255
Player( name = 'Sam Alone', hits = 12 ),
256
Player( name = 'Roger Clemson', hits = 23 ) ] )
258
# Create a league and its corresponding model view:
259
demo = LeagueModelView(
260
League( name = 'National Baseball Conference',
261
teams = [ blue_birds, chicken_hawks, eagles ] )