[wxPython] MVC example?

Brian Kelley bkelley at wi.mit.edu
Wed Apr 14 13:07:27 EDT 2004


Nobody wrote:

> I'm trying to wrap my mind around MVC.  Does anyone have a _simple_ example
> of using the MVC pattern with wxPython?  Maybe just a simple window with a
> dialog box that allows one to update some data.
> 
All right, here you go.  Some points to mention...

The model knows nothing about the view or the controller.
The view knows nothing about the controller or the model.
The controller understands both the model and the view.

The model uses observables, essentially when important data is changed, 
any interested listener gets notified through a callback mechanism.

The following opens up two windows, one that reports how much money you 
have, and one that has two buttons, one to add money and one to remove 
money.

The important thing is that the controller is set up to monitor changes 
in the model.  In this case the controller notices that you clicked a 
button and modifies the money in the model which then sends out a 
message that it has changed.  The controller notices this and updates 
the widgets.

The cool thing is that anything modifying the model will notify the 
model.  In this case it is the controller modifying the model, but it 
could be anything else, even another controller off in the distance 
looking at something else.

The main idea is that you give a controller the model and view that it 
needs, but the model's can be shared between controllers so that when 
the model is updated, all associated views are updated.

I sure hope that made sense, anyway, here is the code, enjoy.

import wx

# an observable calls callback functions when the data has
# changed
#o = Observable()
#def func(data):
#    print "hello", data
#o.addCallback(func)
#o.set(1)
# --> "hello", 1

class Observable:
     def __init__(self, initialValue=None):
         self.data = initialValue
         self.callbacks = {}

     def addCallback(self, func):
         self.callbacks[func] = 1

     def delCallback(self, func):
         del self.callback[func]

     def _docallbacks(self):
         for func in self.callbacks:
             func(self.data)

     def set(self, data):
         self.data = data
         self._docallbacks()

     def get(self):
         return self.data

     def unset(self):
         self.data = None

class Model:
     def __init__(self):
         self.myMoney = Observable(0)

     def addMoney(self, value):
         self.myMoney.set(self.myMoney.get() + value)

     def removeMoney(self, value):
         self.myMoney.set(self.myMoney.get() - value)


class View(wx.Frame):
     def __init__(self, parent):
         wx.Frame.__init__(self, parent, -1, "Main View")
         sizer = wx.BoxSizer(wx.VERTICAL)
         text = wx.StaticText(self, -1, "My Money")
         ctrl = wx.TextCtrl(self, -1, "")
         sizer.Add(text, 0, wx.EXPAND|wx.ALL)
         sizer.Add(ctrl, 0, wx.EXPAND|wx.ALL)
         self.moneyCtrl = ctrl
         ctrl.SetEditable(False)
         self.SetSizer(sizer)
         self.moneyCtrl = ctrl

     def SetMoney(self, money):
         self.moneyCtrl.SetValue(str(money))

class ChangerWidget(wx.Frame):
     def __init__(self, parent):
         wx.Frame.__init__(self, parent, -1, "Main View")
         sizer = wx.BoxSizer(wx.VERTICAL)
         self.add = wx.Button(self, -1, "Add Money")
         self.remove = wx.Button(self, -1, "Remove Money")
         sizer.Add(self.add, 0, wx.EXPAND|wx.ALL)
         sizer.Add(self.remove, 0, wx.EXPAND|wx.ALL)
         self.SetSizer(sizer)

class Controller:
     def __init__(self, app):
         self.model = Model()
         self.view1 = View(None)
         self.view2 = ChangerWidget(self.view1)
         self.MoneyChanged(self.model.myMoney.get())
         self.view2.add.Bind(wx.EVT_BUTTON, self.AddMoney)
         self.view2.remove.Bind(wx.EVT_BUTTON, self.RemoveMoney)

         self.model.myMoney.addCallback(self.MoneyChanged)
         self.view1.Show()
         self.view2.Show()

     def AddMoney(self, evt):
         self.model.addMoney(10)

     def RemoveMoney(self, evt):
         self.model.removeMoney(10)

     def MoneyChanged(self, money):
         self.view1.SetMoney(money)


app = wx.PySimpleApp()
Controller(app)
app.MainLoop()




More information about the Python-list mailing list