traits: how to set property for list trait

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

traits: how to set property for list trait

Gregor Thalhammer
Hi all,

I experience difficulties with list traits.
Here my (simplified) goal: I want to define two traits that describe a value in different units. Both traits should be synchronized with each other, if I change on, the other should be update properly.
With a property with get and set methods this works nicely for a float trait (see example below), but the same approach fails for a list trait: in the example below, edits of the value of the property list items are ignored.
Is there a (simple) way to achieve proper custom synchronization of list traits?

Any help is very much appreciated
Gregor


from traits.api import *
from traitsui.api import *

class A(HasTraits):
    a = Float(1)

    a10 = Property(Float, depends_on='a')

    def _get_a10(self):
        return self.a*10

    def _set_a10(self, value):
        self.a = value/10

class B(HasTraits):
    b = List(Float)
    b10 = Property(List(Float), depends_on='b')

    def _get_b10(self):
        return [b*10 for b in self.b]

    def _set_b10(self, value):
        self.b = [b10/10 for b10 in value]
       
a_trait = A()
b_trait = B()

a_trait.configure_traits()
b_trait.configure_traits()
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: traits: how to set property for list trait

Robert Kern
On Thu, Jan 16, 2014 at 11:52 PM, Gregor Thalhammer <[hidden email]> wrote:
>
> Hi all,
>
> I experience difficulties with list traits.
> Here my (simplified) goal: I want to define two traits that describe a value in different units. Both traits should be synchronized with each other, if I change on, the other should be update properly.
> With a property with get and set methods this works nicely for a float trait (see example below), but the same approach fails for a list trait: in the example below, edits of the value of the property list items are ignored.
> Is there a (simple) way to achieve proper custom synchronization of list traits?
>
> Any help is very much appreciated
> Gregor
>
>
> from traits.api import *
> from traitsui.api import *
>
> class A(HasTraits):
>     a = Float(1)
>
>     a10 = Property(Float, depends_on='a')
>
>     def _get_a10(self):
>         return self.a*10
>
>     def _set_a10(self, value):
>         self.a = value/10
>
> class B(HasTraits):
>     b = List(Float)
>     b10 = Property(List(Float), depends_on='b')

depends_on=['b', 'b_items']

The implicit event trait `b_items` gets fired when `b` is modified in-place, e.g. with `.append()` or `.remove()`, etc. That will tell anyone listening to `b10` or `b10_items` (like the Traits UI Item that is displaying `b10`) that they have to retrieve the value from `b10` again to get the latest value.

--
Robert Kern
Enthought

_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: traits: how to set property for list trait

Gregor Thalhammer

Am 17.01.2014 um 10:57 schrieb Robert Kern <[hidden email]>:

On Thu, Jan 16, 2014 at 11:52 PM, Gregor Thalhammer <[hidden email]> wrote:
>
> Hi all,
>
> I experience difficulties with list traits.
> Here my (simplified) goal: I want to define two traits that describe a value in different units. Both traits should be synchronized with each other, if I change on, the other should be update properly.
> With a property with get and set methods this works nicely for a float trait (see example below), but the same approach fails for a list trait: in the example below, edits of the value of the property list items are ignored.
> Is there a (simple) way to achieve proper custom synchronization of list traits?
>
> Any help is very much appreciated
> Gregor
>
>
> from traits.api import *
> from traitsui.api import *
>
> class A(HasTraits):
>     a = Float(1)
>
>     a10 = Property(Float, depends_on='a')
>
>     def _get_a10(self):
>         return self.a*10
>
>     def _set_a10(self, value):
>         self.a = value/10
>
> class B(HasTraits):
>     b = List(Float)
>     b10 = Property(List(Float), depends_on='b')

depends_on=['b', 'b_items']

The implicit event trait `b_items` gets fired when `b` is modified in-place, e.g. with `.append()` or `.remove()`, etc. That will tell anyone listening to `b10` or `b10_items` (like the Traits UI Item that is displaying `b10`) that they have to retrieve the value from `b10` again to get the latest value.

Dear Robert,

thanks for the response, I tried your proposal, but I didn't succeed. Still the problem remains, when setting an item of b10, this is not reflected by the value of b, i.e., _set_b10 is not called. The other way round, modifying an item of b works as expected and b10 is always up to date (even only with depends_on='b').

I also tried other variations of your proposal, such as decorating a method with @on_trait_change('b10_items') or 'b10[]' to get notification when the items of the b10 property are modified, but without success. 

When I instead use two normal traits b and b10 (not a Property), updating each other on modification, I get infinite recursions. I would need a method to selectively suppress notification only for a certain listener to break the notification cycle. I had a look at the source of sync_trait, which seems to implement such a method, but this was too complicated for me, I didn't understand how it works :-(

Thanks for your help
Gregor


class B(HasTraits):
    b = List(Float,[1.])
    b10 = Property(List(Float), depends_on=['b', 'b_items'])

    def _get_b10(self):
        return [b*10 for b in self.b]

    def _set_b10(self, value):
        self.b = [b10/10 for b10 in value]


--
Robert Kern
Enthought
_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev


_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev