|| [[http://wiki.wxpython.org/index.cgi/WxGladeStatusbar|Prev]] || [[http://wiki.wxpython.org/index.cgi/WxGladeTutorial|Up]] || [[http://wiki.wxpython.org/index.cgi/WxGladeToolbar|Next]] || = wxGlade tutorial - Menu = (Contributed by Chris Lale, chrislale AT users DOT berlios DOT de) '''Table of Contents:''' <> == Create the application in wxglade == Run wxglade. Open the simple project simple-glade.wxg that you created in "first steps" (WxGladeFirstSteps). The project consists of one empty frame. Set the title to "menu-glade" and save it as menu-glade.wxg. In the main (toolbox) window * Properties - -> Widget -> Title: menu-glade * File -> Save -> /path/to/your/project/menu-glade.wxg The Tree shows that the application contains one frame (window)and a sizer to added automatically by wxGlade. * `Application` * `frame_1 (MyFrame)` * `sizer_1` == About the wx.Menu class == A menu is a popup (or pull down) list of items, one of which may be selected before the menu goes away (clicking elsewhere dismisses the menu). Menus may be used to construct either menu bars or popup menus. Look for wxWindow's methods in * wxWidgets manual -> Alphabetical class reference -> wxMenu -> Members and * wxPython API -> Classes -> Menu -> Methods summary == Construct a menubar object == Look up wx.Menu's `__init__()` method, or constructor. You should find that `__init__()` has two string parameters: * title - A title for the popup menu: the empty string denotes no title. * style - If set to wxMENU_TEAROFF, the menu will be detachable (wxGTK only). In the wxGlade Tree window, double-click on `frame_1(MyFrame)`. This opens the Design window and the Properties window for `frame_1`. The wx.Menu `__init__()` method is set by the `Has MenuBar` option in the Widget tab of the Properties window: * Properties - -> Widget -> `Has MenuBar`: (tick) This adds these lines to `MyFrame`'s `__init()__` method: {{{ #!python # Menu Bar self.frame_1_menubar = wx.MenuBar() self.SetMenuBar(self.frame_1_menubar) # Menu Bar end }}} The code constructs a new `wx.Menu` menubar object (`frame_1_menubar`), and tells the frame to show the menubar with the `wx.Frame` method `SetMenuBar()`. == Add menu items to the menubar == The menubar is just a container widget - there is nothing to see until you have added some menu items. First, add "File", "Edit" and "Help" items: * Properties - -> Common -> Edit menus... This brings up the Menu editor. Add the items and give them labels: * Menu editor -> Add -> Label: &File * Menu editor -> Add -> Label: &Edit * Menu editor -> Add -> Label: &Help * Menu editor -> OK Check the result: * Properties - -> Common -> Preview == Add menu items to the File menu == Now add some items to the File menu: * Properties - -> Common -> Edit menus... * Menu editor -> Add -> Label: &Open Use the "Down" button to move the item directly below "&File". Use the ">" button to demote the item one level. In the same way, add items for "&Save" and "&Quit: * Menu editor -> Add -> Label: &Save * Menu editor -> Add -> Label: &Quit Now highlight "&Save" and insert a separator above "&Quit" * Menu editor -> Add separator * Menu editor -> OK Check the result: * Properties - -> Common -> Preview Generate the Python code. In the Tree window, select Application. In the Properties window, enter a new filename for the python file. * `Output path: /path/to/your/project/simple2-glade.py` Click on * `Generate code` Look at the code in a text editor or Idle: {{{ #!python # Menu Bar self.frame_1_menubar = wx.MenuBar() self.SetMenuBar(self.frame_1_menubar) wxglade_tmp_menu = wx.Menu() wxglade_tmp_menu.Append(wx.NewId(), "&Open", "", wx.ITEM_NORMAL) wxglade_tmp_menu.Append(wx.NewId(), "&Save", "", wx.ITEM_NORMAL) wxglade_tmp_menu.AppendSeparator() wxglade_tmp_menu.Append(wx.NewId(), "&Quit", "", wx.ITEM_NORMAL) self.frame_1_menubar.Append(wxglade_tmp_menu, "&File") wxglade_tmp_menu = wx.Menu() self.frame_1_menubar.Append(wxglade_tmp_menu, "&Edit") wxglade_tmp_menu = wx.Menu() self.frame_1_menubar.Append(wxglade_tmp_menu, "&Help") # Menu Bar end }}} == Add a keyboard accelerator to the Quit menu item == The item string for the normal menu items (not submenus or separators) may include the accelerator which can be used to activate the menu item from keyboard. The accelerator string follows the item label and is separated from it by a TAB character ('\t'). Its general syntax is any combination of "CTRL", "ALT" and "SHIFT" strings (case doesn't matter) separated by either '-' or '+' characters and followed by the accelerator key itself. Use the menu editor to add the key combination ctrl-q to the Quit menu item: * Menu editor -> Add -> Label: &Quit\tCtrl+Q == Make the Quit menu item close the application == Use wxGlade to create an event handler that reponds to "Quit" being selected. In wxGlade, edit the entry for "&Quit" and add an event handler called `OnQuit`: * Properties - -> Common -> Edit menus... * Menu editor -> &Quit\tCtrl+Q -> Event Handler: `OnQuit` Generate the Python code. Look at the code in a text editor or Idle. wxGlade has added a new `OnQuit` method to the `MyFrame` class: {{{ #!python def OnQuit(self, event): # wxGlade: MyFrame. print "Event handler `OnQuit` not implemented" event.Skip() }}} Also, a new method is added to `MyFrame`'s `__init__()` method to bind the "Quit" menu item to the `OnQuit()` method: {{{ #!python self.Bind(wx.EVT_MENU, self.OnQuit, self.quit) }}} If you run `menu-glade.py` from a terminal window and click on * File -> Quit "Event handler `OnQuit` not implemented" is printed to standard output (the terminal window).Replace {{{ #!python print "Event handler `OnQuit` not implemented" }}} with {{{ #!python self.Close() }}} Save the file and run it. Now, clicking on * File -> Quit invokes the `Close()` method which is inherited by `MyFrame` from `wx.Window`. == Add an icon to the Quit item == Make sure that `stock_quit.png` exists in the working directory. In Linux systems with Gtk, you can find it somewhere like `/usr/share/icons/hicolor/16x16/stock/generic/stock_exit.png`. You must add the `SetBitmap()` method to the code manually. To do this, you must first create the "File" menu as a named `wx.Menu` object, and the "Quit" menu item as a named `wx.MenuItem` object. In wxGlade, edit the entry for "&File" and add the Name file: * Properties - -> Common -> Edit menus... * Menu editor -> &File -> Name: file Do the same for "&quit": * Menu editor -> &Quit -> Name: quit Generate the Python code. Look at the code in a text editor or Idle: {{{ #!python # Menu Bar self.frame_1_menubar = wx.MenuBar() self.SetMenuBar(self.frame_1_menubar) self.file = wx.Menu() self.file.Append(wx.NewId(), "&Open", "", wx.ITEM_NORMAL) self.file.Append(wx.NewId(), "&Save", "", wx.ITEM_NORMAL) self.file.AppendSeparator() self.quit = wx.MenuItem(self.file, wx.NewId(), "&Quit\tCtrl+Q", "", wx.ITEM_NORMAL) self.file.AppendItem(self.quit) self.frame_1_menubar.Append(self.file, "&File") wxglade_tmp_menu = wx.Menu() self.frame_1_menubar.Append(wxglade_tmp_menu, "&Edit") wxglade_tmp_menu = wx.Menu() self.frame_1_menubar.Append(wxglade_tmp_menu, "&Help") # Menu Bar end }}} Notice how {{{ #!python wxglade_tmp_menu = wx.Menu() ... self.frame_1_menubar.Append(wxglade_tmp_menu, "&File") }}} has become {{{ #!python self.file = wx.Menu() ... self.frame_1_menubar.Append(self.file, "&File") }}} and {{{ #!python wxglade_tmp_menu.Append(wx.NewId(), "&Quit\tCtrl+Q", "", wx.ITEM_NORMAL) }}} has become {{{ #!python self.quit = wx.MenuItem(self.file, wx.NewId(), "&Quit\tCtrl+Q", "", wx.ITEM_NORMAL) self.file.AppendItem(self.quit) }}} Now add the `stock_exit.png` image using the `SetBitMap()` method. wxPython can only put bitmaps into menus. You must convert the .png file to a bitmap using `ConvertToBitmap()`. Insert this line just after the line that creates the "quit" menuitem object: {{{ #!python self.quit.SetBitmap(wx.Image('stock_exit.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()) }}} The Menu Bar section now looks like this. {{{ #!python # Menu Bar self.frame_1_menubar = wx.MenuBar() self.SetMenuBar(self.frame_1_menubar) self.file = wx.Menu() self.file.Append(wx.NewId(), "&Open", "", wx.ITEM_NORMAL) self.file.Append(wx.NewId(), "&Save", "", wx.ITEM_NORMAL) self.file.AppendSeparator() self.quit = wx.MenuItem(self.file, wx.NewId(), "&Quit\tCtrl+Q", "", wx.ITEM_NORMAL) self.quit.SetBitmap(wx.Image('stock_exit.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.file.AppendItem(self.quit) self.frame_1_menubar.Append(self.file, "&File") wxglade_tmp_menu = wx.Menu() self.frame_1_menubar.Append(wxglade_tmp_menu, "&Edit") wxglade_tmp_menu = wx.Menu() self.frame_1_menubar.Append(wxglade_tmp_menu, "&Help") # Menu Bar end }}} Save `menu-glade.py` and run it. Check that you can see the icon in the "Quit" menu item. You may find that the `SetBitmap()` line is deleted next time you regenerate menu-glade.py from wxGlade. For this reason, add icons to menus only after you have finished building the complete GUI. ---- . Comment... Or write your '''manual statements after the end-comment'''. Only lines within ''# XXX'' and ''# XXX end'' are replaced. = Appendix: The complete code = {{{ #!python #!/usr/bin/env python # -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4.1 on Tue Mar 28 19:05:38 2006 import wx class MyFrame(wx.Frame): def __init__(self, *args, **kwds): # begin wxGlade: MyFrame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) # Menu Bar self.frame_1_menubar = wx.MenuBar() self.SetMenuBar(self.frame_1_menubar) self.file = wx.Menu() self.file.Append(wx.NewId(), "&Open", "", wx.ITEM_NORMAL) self.file.Append(wx.NewId(), "&Save", "", wx.ITEM_NORMAL) self.file.AppendSeparator() self.quit = wx.MenuItem(self.file, wx.NewId(), "&Quit\tCtrl+Q", "", wx.ITEM_NORMAL) self.quit.SetBitmap(wx.Image('stock_exit.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()) self.file.AppendItem(self.quit) self.frame_1_menubar.Append(self.file, "&File") wxglade_tmp_menu = wx.Menu() self.frame_1_menubar.Append(wxglade_tmp_menu, "&Edit") wxglade_tmp_menu = wx.Menu() self.frame_1_menubar.Append(wxglade_tmp_menu, "&Help") # Menu Bar end self.__set_properties() self.__do_layout() self.Bind(wx.EVT_MENU, self.OnQuit, self.quit) # end wxGlade def __set_properties(self): # begin wxGlade: MyFrame.__set_properties self.SetTitle("menu-glade") self.SetSize((343, 510)) # end wxGlade def __do_layout(self): # begin wxGlade: MyFrame.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) self.SetAutoLayout(True) self.SetSizer(sizer_1) self.Layout() # end wxGlade def OnQuit(self, event): # wxGlade: MyFrame. self.Close() event.Skip() # end of class MyFrame class MyApp(wx.App): def OnInit(self): wx.InitAllImageHandlers() frame_1 = MyFrame(None, -1, "") self.SetTopWindow(frame_1) frame_1.Show() return 1 # end of class MyApp if __name__ == "__main__": app = MyApp(0) app.MainLoop() }}}