next up previous contents
Next: Types of Observable Properties Up: Details of implementation Previous: An example about View   Contents


Observable Properties in details

The mechanism of the Observable Properties (OP) is fully automatic, since its management is carried out by the base class Model.

Basically the user derives from class Model (or the others listed in section 5.2). The user and adds a class variable called __properties__. This variable must be a map, whose elements' keys are names of properties, and the associated values are the initial values.

For example, suppose you want to create an OP called name initially associated to the string value ``Rob'':

 
from gtkmvc import Model

class MyModel (Model):
  __properties__ = { 'name' : 'Rob' }

  def __init__(self):
    Model.__init__(self)
    # ...
    return

  pass # end of class

By using a specific meta-class, property name will be automatically added, as well as all the code to handle it.

This means that you may use the property in this way:

 
m = MyModel()
print m.name  # prints 'Rob'
m.name = 'Roberto' # changes the property value

What's missing is now an observer, to be notified when the property changes. To create an observer, derive your class from base class gtkmvc.Observer.

 
from gtkmvc import Observer

class AnObserver (Observer):
  def __init__(self, model):
    Observer.__init__(self, model)

    # ...
    return

  def property_name_value_change(self, model, old, new):
    print ``Property name changed from '%s' to '%s''' % (old, new)
    return

  pass # end of class

The Observer constructor gets an instance of a Model, and registers the class instance itself to the given model, to become an observer of that model instance.

To receive notifications for the property name, the observer must define a method called property_name_value_change that when is automatically called will get the instance of the model containing the changed property, and the property's old and new values.

As already mentioned, when used in combination with the MVC pattern, Controllers are also Observers of their models.

Here follows an example of usage:

 
m = MyModel()
o = AnObserver(m)

print m.name  # prints 'Rob'
m.name = 'Roberto' # changes the property value, o is notified

Things so far are easy enough, but they get a bit complicated when you derive custom models from other custom models. For example, what happens to OP if you derive a new model class from the class MyModel?

In this case the behavior of the OP trusty follows the typical Object Oriented rules:

  1. Any OP in base class are inherited by derived classes.
  2. Derived class can override any OP in base classes.
  3. If multiple base classes defines the same OP, only the first OP will be accessible from the derived class.

For example:

 
from gtkmvc import Model

class Test1 (Model):
    __properties__ = {
        'prop1'  : 1
        }

    def __init__(self):
        Model.__init__(self)

        # this class is an observer of its own properties:
        self.register_observer(self) 
        return
    
    def property_prop1_value_change(self, model, old, new):
        print "prop1 changed from '%s' to '%s'" % (old, new)
        return
    pass # end of class

class Test2 (Test1):    
    __properties__ = {
        'prop2'  : 2,
        'prop1'  : 3
        }
    
    def __init__(self):
        Test1.__init__(self)
        
        # also this class is an observer of itself:
        self.register_observer(self)
        return
    
    def property_prop2_value_change(self, model, old, new):
        print "prop2 changed from '%s' to '%s'" % (old, new)
        return
    pass

# test code:
t1 = Test1()
t2 = Test2()

t2.prop2 = 20
t2.prop1 = 30
t1.prop1 = 10

When executed, this script generates this output:

 
prop2 changed from '2' to '20'
prop1 changed from '3' to '30'
prop1 changed from '1' to '10'

As you can see, t2.prop1 overrides the OP prop1 defined in Test1 (they have different initial values). Test2 could also override method property_prop1_value_change:

 
class Test2 (Test1):
  # ... copy from previous definition, and add:
   
  def property_prop1_value_change(self, model, old, new):
    print "Test2: prop1 changed from '%s' to '%s'" % (old, new)
    return   

  pass

As you expect, the output in this case would be:

 
prop2 changed from '2' to '20'
Test2: prop1 changed from '3' to '30'
prop1 changed from '1' to '10'



Subsections
next up previous contents
Next: Types of Observable Properties Up: Details of implementation Previous: An example about View   Contents
Roberto Cavada 2008-08-26