2

We're trying to assess the feasibility of this idea:

We have a pretty deep stack of HasTraits objects in a modeling program. For example, if we are modeling two materials, we could access various attributes on these with:

Layer.Material1.Shell.index_of_refraction
Layer.Material5.Medium.index_of_refraction

We've used this code for simulations, where we merely increment the values of a trait. For example, we could run a simulation were the index_of_refraction of one of these materials varies from 1.3 to 1.6 over 10 iterations. It actually is working quite nicely.

The problem is in selecting the desired traits for the simulation. Users aren't going to know all of these trait variable names, so we wanted to present a heirarchal/tree view of the entire trait structure of the program. For the above two traits, it might look like:

Layer
 - Material1
    - Shell
        - index_of_refraction
 - Material2
    - Medium
        - index_of_refraction

Etc...

I know that traitsui supports TreeEditors, but are there any examples of building a TreeEditor based on the inspection of a HasTraits stack like this? What is the most straightforward way to get the Stack of traits from an object? Essentially, is this idea feasible or should I go back to the drawing board?

Thanks

Adam Hughes
  • 14,601
  • 12
  • 83
  • 122

2 Answers2

2

The ValueEditor does this. You can take a look at how it configures the TreeEditor to do this here:

https://github.com/enthought/traitsui/blob/master/traitsui/value_tree.py

Robert Kern
  • 13,118
  • 3
  • 35
  • 32
  • Thank you. I never realized this worked this way, despite it being fairly well-documented: http://code.enthought.com/projects/traits/docs/html/TUIUG/factories_basic.html#valueeditor Appreciate it. – Adam Hughes Jan 14 '15 at 22:53
  • Robert, Offhand, do you have a suggestion for how parse the final traits that are displayed to users? I want to hide some traits that I know apriori shouldn't be in the view, and some of the more private ones. In the screenshot in my answer below, this would include the "modeltree" trait and the __listener_traits__. Also, my editor doesn't have the fancy colors and layout of the one in the link you provided. Do you think this is because I'm using the QT backend instead of WX, or is the screenshot online no longer current? – Adam Hughes Jan 14 '15 at 23:15
  • 1
    You can look at the implementation of `ValueEditor` to see how it builds the underlying `TreeEditor`. All of the guts are in `TraitsNode` in that `value_tree.py` module. You can subclass `TraitsNode` to replace `tno_get_children()` to customize which traits are considered children. – Robert Kern Jan 15 '15 at 00:51
  • We really tried hard to get this to work, but at the end of the day, it's not obvious to me how to change tno_get_children() on an editor. This is because ValueEditor is returned by a Factory, and so we couldn't figure out how to change this node behavior and have the _ValueEditor, SimpleEditor, ValueEditor, Editor and all the interrelated objects know about it. I ended up monkey patching TraitsNode at runtime. – Adam Hughes Jan 27 '15 at 23:06
  • 1
    Don't use `ValueEditor`; just look at its implementation to see how to configure a `TreeEditor` that does most of what you need to do. Instead of configuring it with `TraitsNode`, instead pass your customized subclass of `TraitsNode`. – Robert Kern Jan 28 '15 at 10:52
  • Thanks. I have been trying this, can you look at my modified answer below for problem I'm having. – Adam Hughes Jan 28 '15 at 17:33
  • You need to configure `TreeEditor`. You can't just put it there unconfigured. Specifically, you need to provide the `nodes=` list. Look at how `ValueEditor` constructs the `TreeEditor`: https://github.com/enthought/traitsui/blob/master/traitsui/editors/value_editor.py#L70-L75 – Robert Kern Jan 29 '15 at 15:54
  • I'm constructing the TreeEditor in an identical way: ` Item(name='stack', editor=TreeEditor(auto_open=2, hide_root=False, editable=True, nodes=value_tree_nodes) ), ` But get error: `TraitError: The 'adapter' trait of an ITreeNodeAdapterBridge instance must be an implementor of, or can be adapted to implement, ITreeNode or None,` – Adam Hughes Jan 29 '15 at 16:45
  • It's ok though, we'll just implement a workaround I don't want to waste your time on it. Thank you for trying to help us, we are probably just dense. – Adam Hughes Jan 29 '15 at 16:49
1

enter image description here

Here is an image from Robert's solution.

Followup Discussion

Robert, imagine I had a custom TreeEditor. It doesn't seem to let me use it directly:

Item('myitem', editor=TreeEditor())

I get:

traits.trait_errors.TraitError: The 'adapter' trait of an ITreeNodeAdapterBridge instance must be an implementor of, or can be adapted to implement, ITreeNode or None, but a value of [<pame.gensim.LayerSimulation object at 0x7fb623bf0830>] <class 'traits.trait_handlers.TraitListObject'> was specified.

I've tried this with _ValueTree, ValueTree, value_tree_editor, value_tree_editor_with_root, _ValueEditor and ValueEditor.

The only one that works is ValueEditor, therefore, even though I can understand how to subclass TraitsNode, it doesn't seem like it's going to work unless I hook everything up through an EditorFactory. IE the behavior we want to customize is all the way down in TreeEditor, and that's buried under _ValueEditor, ValueEditor, EditorFactory etc...

Does this make any sense?

Adam Hughes
  • 14,601
  • 12
  • 83
  • 122