next up previous
Next: Special members for Observable Up: Details of implementation Previous: View


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, 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 intial values.

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

 
from gtkmvc.model import Model

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

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

  pass # end of class

That's all. By using a specific metaclass, property name will be automatically added, as well as all the code to handle it.

This means that you can 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:

 
class AnObserver :

  def __init__(self, model):
    model.registerObserver(self)
    # ...
    return

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

  pass # end of class

The constructor gets an istance 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_change_notification 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 you can see, an Observer is not required to derive from a specific class. Anyway, in the MVC framework models and mostly controllers are use also as observers.

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 behaviour 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.model import Model

class Test1 (Model):

    __properties__ = {
        'prop1'  : 1
        }

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

	# this class is an observer of its own properties:
        self.registerObserver(self) 
        return
    
    def property_prop1_change_notification(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.registerObserver(self)
        return
    
    def property_prop2_change_notification(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 intial values). Test2 could also override method property_prop1_change_notification:

 
class Test2 (Test1):
  # ... copy from previous definition, and add:
   
  def property_prop1_change_notification(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
Next: Special members for Observable Up: Details of implementation Previous: View
Roberto Cavada 2004-11-16