# mini_mvc3_py.txt # Source : http://tkinter.unpythonic.net/wiki/ToyMVC ## 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 ## controller. 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. -Brian Kelley ## ## following is a Tkinter approximation of the original example. import tkinter as tk 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(tk.Toplevel): def __init__(self, master): tk.Toplevel.__init__(self, master) self.protocol('WM_DELETE_WINDOW', self.master.destroy) tk.Label(self, text='My Money').pack(side='left') self.moneyCtrl = tk.Entry(self, width=8) self.moneyCtrl.pack(side='left') def SetMoney(self, money): self.moneyCtrl.delete(0,'end') self.moneyCtrl.insert('end', str(money)) class Controller: def __init__(self, root): self.model = Model() self.model.myMoney.addCallback(self.MoneyChanged) self.view1 = View(root) self.view2 = ChangerWidget(self.view1) self.view2.addButton.config(command=self.AddMoney) self.view2.removeButton.config(command=self.RemoveMoney) self.MoneyChanged(self.model.myMoney.get()) def AddMoney(self): self.model.addMoney(10) def RemoveMoney(self): self.model.removeMoney(10) def MoneyChanged(self, money): self.view1.SetMoney(money) 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 ChangerWidget(tk.Toplevel): def __init__(self, master): tk.Toplevel.__init__(self, master) self.addButton = tk.Button(self, text='Add', width=8) self.addButton.pack(side='left') self.removeButton = tk.Button(self, text='Remove', width=8) self.removeButton.pack(side='left') if __name__ == '__main__': root = tk.Tk() root.withdraw() app = Controller(root) root.mainloop()