I am trying to create a HasTraits objects which contains several other different instance of another HasTraits objects. However, I always seem to hit problems when I initialise my many HasTraits objects in the master object.
I've produced a simple example below that produces the error. Could someone explain the best way to do this? -I never know when I should use a traits.Instance(traits.Int) or just the traits.Int -How do I pass in initial values for the traits in the constructor? Whenever I do this I get errors like "type int required but found type traits.Int"
Thanks for your help
import enthought.traits.api as traits
import enthought.traits.ui.api as traitsui
class Simple(traits.HasTraits):
minimum = traits.Int()
maximum= traits.Int()
ranged = traits.Range(minimum, maximum)
traits_view = traitsui.View(traitsui.Group(
traitsui.Item('minimum'),
traitsui.Item('maximum'),
traitsui.Item('ranged')
))
class Complex(traits.HasTraits):
s1=Simple(minimum=1.0,maximum=5.0)
s2=Simple(minimum=2.0,maximum=10.0)
s3=Simple(minimum=traits.Int(1.0),maximum=traits.Int(5.0))
traits_view = traitsui.View(traitsui.Group(
traitsui.Item('s1'),
traitsui.Item('s2')
))
c= Complex()
c.configure_traits()
I've tested your code with the same results, but as I think about this, I realize that there is an issue with the means by which you are using Range. Traits of the Range type must be defined with min and max values found within trait_handlers.RangeType
which equates to (int, long, float)
. So, you'll have to define an initial range using those types, unless you want to replace traits.api.BaseRange
, which I don't think is a smart move. So, you'll have to stick with these data types, and do a little more manual work if you'd like to tie changes to Simple.minimum
and 'Simple.maximumto the bounds of your
Simple.ranged` trait.
Keeping in mind, you are not correct in stating that you're defining the Range values in the "Constructor". The definition of variables in the body of a class is not a constructor. Your ranged trait is being defined with invalid values because you're attempting to pass a Traits object and not an int, long, or float. Even if you were to convert the Int
trait to an int
value, keep in mind that you're working on the class definition at this point, and not the instance value as the class has yet to be instantiated at the point that you're defining the value of Ranged. With this in mind, I've added an _init_
method (read: Constructor) to the Simple
class.
I have adapted the use of the add_trait
method from the Traits UI Manual
from traits.api import HasTraits, Int, Range
from traitsui.api import View, Item
class Simple(HasTraits):
minimum=Int()
maximum=Int()
ranged = Range(0, 0)
traits_view = View(
Item('minimum'),
Item('maximum'),
Item('ranged'),
resizable=True,width=600,height=400)
def __init__(self, minimum=0, maximum=0, **traits):
self.maximum = maximum
self.minimum = minimum
HasTraits.__init__(self, **traits)
ranged = Range(self.minimum, self.maximum)
self.remove_trait('ranged')
self.add_trait('ranged', ranged)
def _minimum_changed(self):
self.remove_trait("ranged")
ranged = Range(self.minimum, self.maximum)
self.add_trait('ranged', ranged)
def _maximum_changed(self):
self.remove_trait("ranged")
ranged = Range(self.minimum, self.maximum)
self.add_trait('ranged', ranged)
c=Simple(minimum=1, maximum=5)
c.configure_traits()
Let me know if you have any follow up questions.
EDIT: I've learned since that this can be greatly simplified
from traits.api import HasTraits, Int, Range
class Simple(HasTraits):
minimum=Int()
maximum=Int()
ranged = Range(low='minimum', high='maximum')
using the string values for low and high causes the api to link these traits in the background, baking in all that easy flavor. This is clearly the more concise idiom to adopt for this purpose.