ModelButton: an attempt to clean up button enabling/disabling
Don Dwiggins
ddwiggins at advpubtech.com
Fri Dec 1 10:32:36 PST 2006
I'm developing a panel with 8 buttons (hardly a record, I'm sure). Each
button should be enabled or disabled at various times while the user is
working with the panel. I've found the code to support this getting
progressively messier, with lots of "extraneous" code growing in various
event handlers.
I've just come up with a way of getting this under control, and I'm
posting it here "as is" in the hope that someone might find it useful,
or help me improve it, or point out a far better solution that I should
have used in the first place.
The core of it is a subclass of Button that I call ModelButton, as a bow
to MVC. The core of the idea is that each button is an observer of some
object, gets notified by that object when some possibly significant
event occurs, and can "ask" the object whether it should enable or
disable itself. Here's the implementation of the class:
> class ModelButton(wx.Button):
> def __init__(self):
> pre = wx.PreButton()
> self.PostCreate(pre)
>
> def SetHandlers(self, enableTester, eventHandler):
> """ Set the handlers that we'll use """
> self._enableTester = enableTester
> self._eventHandler = eventHandler
> self.Bind(wx.EVT_BUTTON, eventHandler)
>
> def notify(self):
> """ It's time to decide our enabled status """
> self.Enable( self._enableTester() )
In addition to the usual event handler, I've added a callback that the
button uses to set its enabled state.
To use this, the container class sets itself up as the observable for
its buttons by declaring the following methods:
> def setModelButton(self, button, enableTester, eventHandler):
> """ Set up the model button for operation with this class """
> button.SetHandlers(enableTester, eventHandler)
> self.observers.append(button)
>
> def notifyButtons(self):
> """ Send notification to all buttons of a state change """
> for button in self.observers:
> button.notify()
Each button is set up by something like the following:
> self.addinclbtn = xrc.XRCCTRL(self, "AddIncludeButton")
> self.setModelButton(self.addinclbtn, self.testAddInclude,
> self.includeAdZones)
Here's an "enableTester":
> def testAddInclude(self):
> # Enable if there are available AdZones selected
> return len( self.availAZlist.GetSelections() ) > 0
Then, in an event handler that changes the state of the panel, I added a
call to "self.notifyButtons()"; this separates out the issue of changing
the state from that of updating the "view" appropriately, something that
MVC was originally invented for.
This is pretty minimal and simplistic, but it's already allowed me to
prune out some crufty code and squash some bugs in the process.
--
Don Dwiggins
Advanced Publishing Technology
More information about the wxpython-users
mailing list