File: dynamic_form_using_instances.py

package info (click to toggle)
python-traitsui 4.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 13,292 kB
  • sloc: python: 39,867; makefile: 120; sh: 5
file content (139 lines) | stat: -rw-r--r-- 4,531 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""
Dynamic restructuring a user interface using Instance editor and Handler

How to dynamically change the *structure* of a user interface (not merely which
components are visible), depending on the value of another trait.

This code sample shows a simple implementation of the dynamic
restructuring of a View on the basis of some trait attribute's
assigned value.

The demo class "Person" has attributes that apply to all instances
('first_name', 'last_name', 'age') and a single attribute 'misc'
referring to another object whose traits are specific to age
group (AdultSpec for adults 18 and over, ChildSpec for children
under 18).  The 'misc' attribute is re-assigned to a new instance
of the appropriate type when a change to 'age' crosses the range
boundary.

The multi-attribute instance assigned to 'misc' is edited by means
of a single InstanceEditor, which is displayed in the 'custom' style
so that the dynamic portion of the interface is displayed in a panel
rather than a separate window.

It is necessary to use a Handler because otherwise when the instance is
updated dynamically, Traits UI will not detect the change and the UI will not
be reconfigured. This is due to architectural limitations of the current
version of Traits UI.

Compare this to the simpler, but less powerful demo of *enabled_when*.
"""

from traits.api import HasTraits, Str, Range, Enum, Bool, Instance

from traitsui.api import Item, Group, View, Handler, Label


class Spec ( HasTraits ):
    """ An empty class from which all age-specific trait list classes are
        derived.
    """
    pass


class ChildSpec ( Spec ):
    """ Trait list for children (assigned to 'misc' for a Person when age < 18).
    """
    legal_guardian = Str
    school         = Str
    grade          = Range( 1, 12 )

    traits_view = View( 'legal_guardian',
                        'school',
                        'grade' )


class AdultSpec ( Spec ):
    """ Trait list for adults (assigned to 'misc' for a Person when age >= 18).
    """

    marital_status   = Enum( 'single', 'married', 'divorced', 'widowed' )
    registered_voter = Bool
    military_service = Bool

    traits_view = View( 'marital_status',
                        'registered_voter',
                        'military_service' )


class PersonHandler ( Handler ):
    """ Handler class to perform restructuring action when conditions are met.
    The restructuring consists of replacing a ChildSpec instance by an
    AdultSpec instance, or vice-versa. We would not need a handler to listen
    for a change in age, but we do need a Handler so that Traits UI will
    respond immediately to changes in the viewed Person, which require
    immediate restructuring of the UI.
    """

    def object_age_changed ( self, info ):
        if ((info.object.age >= 18) and
            (not isinstance( info.object.misc, AdultSpec ))):
            info.object.misc = AdultSpec()
        elif ((info.object.age < 18) and
              (not isinstance( info.object.misc, ChildSpec ))):
            info.object.misc = ChildSpec()


class Person ( HasTraits ):
    """ Demo class for demonstrating dynamic interface restructuring.
    """
    first_name = Str
    last_name  = Str
    age        = Range( 0, 120 )
    misc       = Instance( Spec )

    # Interface for attributes that are always visible in interface:
    gen_group = Group(
        Item( name = 'first_name' ),
        Item( name = 'last_name' ),
        Item( name = 'age'),
        label       = 'General Info',
        show_border = True
    )

    # Interface for attributes that depend on the value of 'age':
    spec_group = Group(
        Group(
            Item( name = 'misc', style = 'custom' ),
            show_labels = False
        ),
        label       = 'Additional Info',
        show_border = True
    )

    # A simple View is enough as long as the right handler is specified:
    view = View(
        Group( 
            gen_group, 
            '10',
            Label("Using Instances and a Handler:"),
            '10',
            spec_group 
            ),
        title     = 'Personal Information',
        buttons   = [ 'OK' ],
        resizable = True,
        width = 300,
        handler   = PersonHandler()
    )

# Create the demo:
demo = Person( first_name = "Samuel",
               last_name  = "Johnson",
               age        = 18,
               misc       = AdultSpec() )

# Run the demo (if invoked from the command line):
if __name__ == '__main__':
    demo.configure_traits()