Bob Klahn wrote:
Bob Klahn wrote:
I like the approach Robin lays out in Listing 6.4 (pages 159-160) of "wxPython in Action" to create an application's menu bar, menus, and menu items.
But I need to be able to disable or enable specific menu items as various situations arise. Robin's approach does not create separate menu-item id's, so I'm currently at a loss as to how best to accomplish that.In addition to the handler for EVT_MENU you can (optionally) have an entry in the data structure for a handler for EVT_UPDATE_UI for each item, (or at least those that need it.) The EVT_UPDATE_UI handlers are called periodically and is an easy way to enable/disable, check/uncheck, etc. menu, toolbar and other items. The handlers just need to call a method of the event object, and wx takes care of propagating that value to the actual item.
For example, suppose you have a Foo menu item, and you want it to be enabled or disabled based on some doFoo property of the frame class. In that case the EVT_UPDATE_UI handler can be as simple as this:
def OnUpdateUI_Foo(self, evt):
evt.Enable(self.doFoo)Excellent! Not only does that work, it may also allow me to throw away several blocks of "if self.doFoo:" code!
That takes take of menu items. But I need this for entire menus too. How would I do the same kind of thing for entire menus on the menubar?
E.g., one of my menubar menus is "Grid." That entire menu should be enabled when one or more grid-containing objects are open, and disabled otherwise. What I currently have to do is this:
self.menuBar.EnableTop(2, self.have_grids)
I'd love to be able to eliminate (a) the menu-position-dependent enabling/disabling, and (b) the non-event-driven line of code itself.
BTW, when I tried binding an update handler to the menu, I got the message
AttributeError: 'Menu' object has no attribute 'GetId'If this can't be automated, then I won't be able to eliminate those "if self.doFoo:" blocks after all.
Here's hoping!
Bob
My statement "If this can't be automated, then I won't be able to eliminate those "if self.doFoo:" blocks after all" is correct in the strictest sense, but it's not an automation killer, as I can always enable/disable all the menu's menu items if I can't enable/disable the menu itself.
But I'm still hoping.
Bob
Not yet being able to automatically enable/disable menus themselves, I've now tried what I mentioned just above, i.e., enabling/disabling all a menu's menu items. My conclusion: it's ugly, and too ugly to use.
Submenus are the ugliest part, when all the menu items around them (or within them) are disabled, since they remain "enabled," i.e., not grayed out.
So to use Robin's EVT_UPDATE_UI approach, I really do need to be able to disable menus/submenus themselves in an event-driven manner, so that their labels are immediately grayed out.
I hope I'm missing something basic here.
Unfortunately I don't think it is possible the way things currently are. The menubar would have to deal with sending the update ui events in order to enable/disable whole menus, and currently only wx.Menu is doing it.
You can however approximate the same thing yourself. For example you could give the frame a handler for EVT_IDLE that checks the flag or condition that you would have checked in the EVT_UPDATE_UI handler, and if the condition has changed then call EnableTop yourself. Then you can still decouple the enabling/disabling of the menu from the rest of the app, and centralize where it is done.
ยทยทยท
At 07:38 PM 11/26/2007, Bob Klahn wrote:
At 03:12 PM 11/26/2007, Bob Klahn wrote:
At 01:01 PM 11/26/2007, Robin Dunn wrote:
--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!