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/Coo...n/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.Bro adcast() 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.Bro adcast( "progress", "start", (100, "Doing your
bidding now..." ) ) # number of items we will process
# ...
broadcaster.Bro adcast( "progress", "progress", (i, "Working on
item %i" % i ) ) # current item
# ...
broadcaster.Bro adcast( "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.ShowResult s( 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 BrokerRequestHa ndler( 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 BroadcasterEven tHandler( 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.Reg ister( func, source, title )
return func
return decorator
# example ...
@BrokerRequestH andler( "meaning of life" )
def getMeaningOfLif e():
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 ):
"""Dectorat or for event-handling methods"""
def decorator(func) :
func.Broadcaste rEvent = (source, title)
return func
return decorator
class FrameController :
"""Controll er for the main frame window"""
def __init__( self ):
for key in dir(self):
method = getattr(self, key)
if hasattr(method, "BroadcasterEve nt") and
callable(method ):
source, title = method.Broadcas terEvent
broadcaster.Reg ister( 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.Cur rentData()
# Perform export...