Note that there are some explanatory texts on larger screens.

plurals
  1. POPython duck-typing for MVC event handling in pygame
    primarykey
    data
    text
    <p>A friend and I have been playing around with pygame some and came across <a href="http://ezide.com/games/writing-games.html" rel="nofollow">this tutorial for building games</a> using pygame. We really liked how it broke out the game into a model-view-controller system with events as a go-between, but the code makes <em>heavy</em> use of <code>isinstance</code> checks for the event system.</p> <p>Example:</p> <pre><code>class CPUSpinnerController: ... def Notify(self, event): if isinstance( event, QuitEvent ): self.keepGoing = 0 </code></pre> <p>This results in some extremely unpythonic code. Does anyone have any suggestions on how this could be improved? Or an alternative methodology for implementing MVC?</p> <hr> <p>This is a bit of code I wrote based on @Mark-Hildreth answer (how do I link users?) Does anyone else have any good suggestions? I'm going to leave this open for another day or so before picking a solution.</p> <pre><code>class EventManager: def __init__(self): from weakref import WeakKeyDictionary self.listeners = WeakKeyDictionary() def add(self, listener): self.listeners[ listener ] = 1 def remove(self, listener): del self.listeners[ listener ] def post(self, event): print "post event %s" % event.name for listener in self.listeners.keys(): listener.notify(event) class Listener: def __init__(self, event_mgr=None): if event_mgr is not None: event_mgr.add(self) def notify(self, event): event(self) class Event: def __init__(self, name="Generic Event"): self.name = name def __call__(self, controller): pass class QuitEvent(Event): def __init__(self): Event.__init__(self, "Quit") def __call__(self, listener): listener.exit(self) class RunController(Listener): def __init__(self, event_mgr): Listener.__init__(self, event_mgr) self.running = True self.event_mgr = event_mgr def exit(self, event): print "exit called" self.running = False def run(self): print "run called" while self.running: event = QuitEvent() self.event_mgr.post(event) em = EventManager() run = RunController(em) run.run() </code></pre> <p>This is another build using the examples from @Paul - impressively simple!</p> <pre><code>class WeakBoundMethod: def __init__(self, meth): import weakref self._self = weakref.ref(meth.__self__) self._func = meth.__func__ def __call__(self, *args, **kwargs): self._func(self._self(), *args, **kwargs) class EventManager: def __init__(self): # does this actually do anything? self._listeners = { None : [ None ] } def add(self, eventClass, listener): print "add %s" % eventClass.__name__ key = eventClass.__name__ if (hasattr(listener, '__self__') and hasattr(listener, '__func__')): listener = WeakBoundMethod(listener) try: self._listeners[key].append(listener) except KeyError: # why did you not need this in your code? self._listeners[key] = [listener] print "add count %s" % len(self._listeners[key]) def remove(self, eventClass, listener): key = eventClass.__name__ self._listeners[key].remove(listener) def post(self, event): eventClass = event.__class__ key = eventClass.__name__ print "post event %s (keys %s)" % ( key, len(self._listeners[key])) for listener in self._listeners[key]: listener(event) class Event: pass class QuitEvent(Event): pass class RunController: def __init__(self, event_mgr): event_mgr.add(QuitEvent, self.exit) self.running = True self.event_mgr = event_mgr def exit(self, event): print "exit called" self.running = False def run(self): print "run called" while self.running: event = QuitEvent() self.event_mgr.post(event) em = EventManager() run = RunController(em) run.run() </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload