How do I include a submenu or checked menu

In this section, we'll present two common menu tricks, the submenu and the checked or radio menu. A submenu is a menu which is accessible inside one of the top menus. A checkbox or radio menu is a group of menu items that behaves like a group of checkboxes or radio buttons. Figure 6.3 displays a menubar, including a submenu with radio menu items.

To create a submenu, build itjust as you would any other menu, and append it to the parent menu using wx.Menu.AppendMenu() .

Figure 6.3 A menu that uses a submenu with radio menu items

Menu items with checkbox or radio button decorations can be created either by using the wx.Menu methods AppendCheckItem() and AppendRadioItem(), or by passing the kind attribute to the creator for wx.MenuItem one of the following values: wx.ITEM_N0RMAL, wx.ITEM_CHECKB0X, or wx.ITEM_RADI0. A checkbox menu item displays a check that automatically toggles on and off as the item is selected; you do not have to manually manage that process. The start value of a checked menu item is off. Radio menu items are implicitly grouped. Consecutive radio items are considered to be part of the same group (a menu separator will break up the group). By default, the topmost member of the group is checked, after which selecting any member of the group automatically transfers the check to that item. To programmatically check a menu item, use the wx.Menu method Check(id, bool), where id is the wxPython ID of the item to be changed, and the Boolean specifies the checked state of the item.

Listing 6.4 adds menu support to the sketch application frame. The menu functionality here is an evolutionary descendent of the refactored utility code displayed in listing 5.5. In this case, the data format is tweaked to provide submenus, and the creation code recursively creates a submenu when necessary. Support is also added for radio and checkbox menus.

Listing 6.4 Menu support for the sketch application import wx from examplel import SketchWindow class SketchFrame(wx.Frame):

wx.Frame._init_(self, parent, -1, "Sketch Frame", size=(800,600)) self.sketch = SketchWindow(self, -1)

self.sketch.Bind(wx.EVT_M0TI0N, self.OnSketchMotion)

self_initStatusBar() Note slight self_createMenuBar() Q refactoring def initStatusBar(self):

self.statusbar = self.CreateStatusBar() self.statusbar.SetFieldsCount(3) self.statusbar.SetStatusWidths([-1, -2, -3])

def 0nSketchMotion(self, event):

self.statusbar.SetStatusText("Pos: %s" % str(event.GetPositionTuple()), 0) self.statusbar.SetStatusText("Current Pts: %s" %

len(self.sketch.curLine), 1) self.statusbar.SetStatusText("Line Count: %s" %

len(self.sketch.lines), 2) event.Skip()

def menuData(self):

"New Sketch file", self.OnNew), "Open sketch file", self.OnOpen), "Save sketch file", self.OnSave),

("&Black", "", self.OnColor, wx.ITEM_RADIO), ("&Red", "", self.OnColor, wx.ITEM_RADIO), ("&Green", "", self.OnColor, wx.ITEM_RADIO), ("&Blue", "", self.OnColor, wx.ITEM_RADIO))), ("", "", ""), ("&Quit", "Quit", self.OnCloseWindow)))]

Identifying menu data def createMenuBar(self): menuBar = wx.MenuBar() for eachMenuData in self.menuData(): menuLabel = eachMenuData[0] menuItems = eachMenuData[1]

menuBar.Append(self.createMenu(menuItems), menuLabel) self.SetMenuBar(menuBar)

def createMenu(self, menuData): menu = wx.Menu() for eachItem in menuData: if len(eachItem) == 2: label = eachItem[0]

subMenu = self.createMenu(eachItem[1]) menu.AppendMenu(wx.NewId(), label, subMenu) else:

self.createMenuItem(menu, *eachItem) return menu

Creating submenus def createMenuItem(self, menu, label, status, handler, kind=wx.ITEM_NORMAL):

if not label:

menu.AppendSeparator() return menuItem = menu.Append(-1, label, status, kind) self.Bind(wx.EVT_MENU, handler, menuItem)

def OnNew(self, event): pass def OnOpen(self, event): pass def OnSave(self, event): pass

Creating menu items

Q with kind

A Handling color change def OnCloseWindow(self, event): self.Destroy()

app = wx.PySimpleApp() frame = SketchFrame(None) frame.Show(True) app.MainLoop()

def OnColor(self, event):

menubar = self.GetMenuBar()

itemId = event.GetId()

item = menubar.FindltemByld(itemld)

color = item.GetLabel()

self.sketch.SetColor(color)

O Now that the_init__method contains more functionality, we've encapsulated the status bar stuff into its own method. © The format of the menu data is now (label, (items)), where each item is either a list (label, status text, handler, optional kind) or a menu with a label and items. To determine whether a subitem of data is a menu or a menu item, remember, menus are length 2, and items are length 3 or 4. In a production system, where the data is more complex, I recommend using XML or some other external format. d If the data piece is of length 2, it's meant to be a submenu, so break it up the same way the top-level was broken up, and recursively call createMenu and append it. Q Given the implementation of the menus here, it was easier to add the kind parameter to the wx.Menultem constructor than to use the special methods of wx.Menu. f The OnColor method is set up to handle the color changes of all the menu items, rather than setting up separate handlers for each item. In this case, the code gets the item id from the event, and uses the FindltemByld() method to get the appropriate menu item (notice that this does not require us to maintain a separate hash table of item ids—we're using the menubar as that data structure). This method assumes that the label of the menu item is a wxPython color name, and passes that label to the sketch window, which updates its pen.

Was this article helpful?

0 -1

Post a comment