> On Behalf Of Kevin Walzer > What's the best way to do this? Can anyone point me in the > right direction? How could, for instance, the top snippet be > rewritten to separate the Tkinter parts from the generic stuff?
I like to use the broadcaster/broker recipe at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81983 I added a few features (such as decorators for listener functions -- see below sig). There are other recipes out there, such as PyDispatcher. Basically, I have GUI events translated into broadcaster events (by passing lambdas that call broadcaster.Broadcast() to the event binders), which are received by controller functions/classes. Feedback (status/progress) is also communicated via broadcaster events. Something I tried on my current project, which is going fairly well, is first writing a command-line version, then writing a GUI version, with the same controller back-end used in each case, and the controller communicating progress/results via the same interface. This approach has made me keep presentation and logic very loosely coupled. So for instance, the view class would send request for processing, which the controller gets. The controller performs the requested action, sending broadcasts of progress (note that the controller can start a worker thread for the processing, but the broadcasts should be made on the GUI thread...) broadcaster.Broadcast( "progress", "start", (100, "Doing your bidding now..." ) ) # number of items we will process # ... broadcaster.Broadcast( "progress", "progress", (i, "Working on item %i" % i ) ) # current item # ... broadcaster.Broadcast( "progress", "end", (100, "Done!") ) Depending on who is showing the progress, this might go onto a status bar, progress dialog, the console, a log file, and so on, or some combination thereof -- the controller doesn't know or care. When the controller is finished, it asks the broker for a view, and calls show results on the view view = broker.Request( "view" ) view.ShowResults( results ) That could have been done equally with the broadcaster, but for some reason I like the broker here (it makes the view "dumber"). Regards, Ryan -- Ryan Ginstrom ================== # listener decorators def BrokerRequestHandler( title ): """A decorator for broker listeners @param title: the title to provide The decorated function must take no arguments (it can retrieve them using CurrentData()) """ def decorator(func): broker.Register( title, func ) return func return decorator def BroadcasterEventHandler( source, title ): """A decorator for broadcaster event handlers @param source: the broadcast source @param title: the title of the broadcast The decorated function must take no arguments (it can retrieve them using CurrentData()) """ def decorator(func): broadcaster.Register( func, source, title ) return func return decorator # example ... @BrokerRequestHandler( "meaning of life" ) def getMeaningOfLife(): return 42 ## A little more complicated for class methods. I stole this technique from WCK # Lifted shamelessly from WCK (effbot)'s wckTkinter.bind def EventHandler( source, title ): """Dectorator for event-handling methods""" def decorator(func): func.BroadcasterEvent = (source, title) return func return decorator class FrameController: """Controller for the main frame window""" def __init__( self ): for key in dir(self): method = getattr(self, key) if hasattr(method, "BroadcasterEvent") and callable(method): source, title = method.BroadcasterEvent broadcaster.Register( method, source=source, title=title ) @EventHandler( "event", "onExport" ) def onExport( self ): """Handles the onExport broadcast by exporting the database to the requested format""" format = broadcaster.CurrentData() # Perform export... -- http://mail.python.org/mailman/listinfo/python-list