Reputation: 346
How can I adapt a ListEditor to list the contents of an arbitrary collection using TraitsUI? Here is a sample code
from traits.api import HasStrictTraits, Instance, Int, List, Str
from traitsui.api import View, Item, ListEditor, InstanceEditor
from sortedcontainers import SortedListWithKey
class Person(HasStrictTraits):
name = Str
age = Int
class Office(HasStrictTraits):
# employees = Instance(SortedListWithKey,
kw={'key': lambda employee: employee.age})
employees = List
employee_view = View(
Item(name='name', show_label=False, style='readonly')
)
office_view = View(
Item(name='adults',
show_label=False,
style='readonly',
editor=ListEditor(
style='custom',
editor=InstanceEditor(view=employee_view),
),
),
resizable=True
)
employee_list = [Person(name='John', age=31), Person(name='Mike', age=31),
Person(name='Jill', age=37), Person(name='Eric', age=28)]
#office = Office()
#office.employees.update(employee_list)
office = Office(employees=employee_list)
office.configure_traits(view=office_view)
If I replace the standard list with SortedListWithKey by using the code I commented out, I get the 'AttributeError: 'Office' object has no attribute 'value'' error. How can I resolve this?
Upvotes: 0
Views: 196
Reputation: 46
Traits uses a list
subclass (TraitListObject
) for anything stored in a List
trait: this is what allows trait events to be fired on changes to items in the list as well as to the attribute. I'm guessing that the SortedListWithKey
class is from the "Sorted Containers" third-party package and so isn't a Traits list. The ListEditor
expects a TraitsListObject
(or a work-alike) for it to work properly, since it needs to know if the list items have changed.
Fixes/work-arounds that I can think of:
Using two List
traits, one unsorted (which could be a Set
) and one sorted, and have trait change handlers to synchronize the two. This sort of pattern works well if your unordered data is part of the "model" layer and the way it is sorted is part of the user-facing "view" or "presentation" layer (ie. possibly in a TraitsUI Controller
or ModelView
object).
Write a subclass of TraitListObject
that has the self-sorting behaviour of SortedListWithKey
. Use a regular List
trait but assign instances of your subclass into it, or for really slick behaviour subclass List
to do conversion to your new subclass on any set operation.
Use a regular List
trait, but a TableEditor
with columns for the name
and age
: this is a different UI from what you are intending, and may not suit what your real-world is, but the TableEditor
can be set to auto-sort on columns. For more simple examples, the ListStrEditor
may also work.
Add functionality to the TraitsUI ListEditor
so that the list items are optionally displayed in a sorted order. This is probably the most difficult option.
While it is clearly the least elegant solution, I'd probably just go with the first in most cases. You might also consider posting this question on the ETS-Users group to see if anyone else has some thoughts on it.
Upvotes: 1