Model View Presenter GUI pattern?

Chris Liechti cliechti at gmx.net
Thu Dec 13 18:42:57 EST 2001


[posted and mailed]

george young <gry at ll.mit.edu> wrote in
news:20011213172833.0bfac3c7.gry at ll.mit.edu: 

> Is anyone using the Model View Presenter GUI framework/pattern in
> python? I've been reading bits about it, and it sounds quite
> attractive.  
> 
> I've started trying to write a simple MVP module as a basis for an
> application. The hardest part is dealing with the overall structure: 
> my app deals with a big structured data object and it's hard to picture
> how the parallel trees of models, views, and presenters all get
> instantiated and linked.   
> 
> Below I include my baby mvp.py file (using pygtk) for
> comment/discussion.  Any comments of design/implementation/style etc.
> are very welcome. 
> 
>    A few mvp references for the curious:
> http://www.object-arts.com/Lib/EducationCentre4/htm/modelviewpresenter.h
> tm 
> http://www.object-arts.com/EducationCentre/Overviews/ModelViewPresenter.
> htm http://www-106.ibm.com/developerworks/library/mvp.html
> 
> 
> import gtk
> class Topw(gtk.GtkWindow):
>     def __init__(self):
>         gtk.GtkWindow.__init__(self, gtk.WINDOW_TOPLEVEL)
>         self.connect("destroy", gtk.mainquit)
>         self.connect("delete_event", gtk.mainquit)
> 
> 
> class Observable:
>     def __init__(self):
>         self.observers = []
>     def register(self, o):
>         self.observers.append(o)
>     def un_register(self, o):
>         self.observers.remove(o)
>     def notify(self):
>         for o in self.observers:
>             o.update(self)

i prefer "notify(self, *args, **kargs)" and o.update(self, *args, **kargs)
then you can give along detailed information on changes e.g. when your 
model is a table you can pass the row and column of the changed cell.

 
> class Observer:
>     '''Just for clarity, not really needed.'''
>     def update(self): pass

i would throw an exception here, so that you see when you forgot to 
override update somewhere.

> class Model(Observable):
>     def __init__(self, value=None):
>         Observable.__init__(self)
>         self.set(value)
>     def get(self):
>         return self._value
>     def set(self, v):
>         self._value = v

shouldn't notify() be called here?

>     def str(self):
>         return `self.get()`
> 
> 
> class IntegerModel(Model):
>     def __init__(self, i):
>         Model.__init__(self, i)
>     def set(self, i):
>         self._value = int(i)

notify()...
             
> 
> class IntegerView(gtk.GtkEntry, Observer):
>     def __init__(self):
>         gtk.GtkEntry.__init__(self)
>         
>     def set(self, x):
>         self.set_text(`x`)
>         
>     def clear(self):
>         self.delete_text(0, -1)
> 
>     def update(self, mod):
>         self.set(mod.get())
>         
> 
> class IntegerPresenter:
>     def __init__(self, i=None):
>         self.view = IntegerView()
>         self.model = IntegerModel(i)
>         self.model.register(self.view)
>         self.view.connect('changed', self.changed)
> 
>     def changed(self, v):
>         try:
>             self.model.set(int(v.get_text()))
>         except ValueError:
>             gtk.gdk_beep()
> 
> 
> if __name__ == '__main__':
>     pres = IntegerPresenter(33)
>     topw = Topw()
>     topw.add(pres.view)
>     topw.show_all()
>     gtk.mainloop()
> 

there yould also be an diffrent solution using a proxy pattern. the proxy 
class implements __getattr__ and __setattr__, gets its data from the 
wrapped class, but also notifies all registred observers on a __setattr__ 
call.

chris

-- 
Chris <cliechti at gmx.net>




More information about the Python-list mailing list