= Gtk Menus = Menus are lists of commands, accessed from a drop-down or pull-down list. Menus are typically found within a menubar, which displays the title of each menu. [[Image(menus.png)]] == Creating the Menu Bar == The menu bar itself is created as an instance of '!MenuBar'. The menubar is a regular Gtk widget and can be located anywhere you choose, but for the classic menu-at-the-top, place the menubar at the top of a non-expandable 'VBox' before adding it to the window. The following 'createMenu' definition shows how to construct and add the menubar to a window class. (A complete example is given at the bottom of this page.) {{{ #!cobra def createMenu # create the main menubar mainMenu = MenuBar () # -- the menu construction code goes here -- # Add the menubar to the top of the window box = VBox(false, 0) # make this 'false' so menubar stays compact box.packStart(mainMenu, false, false, 0) .add(box) }}} == Adding Menus to the Menu Bar == The menubar displays instances of '!MenuItems'. To make the headings for menus such as 'File', 'Edit', 'Help' we would write: {{{ #!cobra menuItem = MenuItem("_File") mainMenu.append(menuItem) menuItem = MenuItem("_Edit") # (it is convenient to reuse the 'menuItem' variable) mainMenu.append(menuItem) menuItem = MenuItem("_Help") mainMenu.append(menuItem) }}} Notice the underscore in the title - this gets converted into a mnemonic for accessing the menu, and is shown as an underlined letter in the menu. To get an actual ''menu'' under each heading, we first create an instance of 'Menu' and attach it as the submenu for the respective menuitem: {{{ #!cobra menuItem = MenuItem("_File") mainMenu.append(menuItem) fileMenu = Menu() menuItem.submenu = fileMenu menuItem = MenuItem("_Edit") mainMenu.append(menuItem) editMenu = Menu() menuItem.submenu = editMenu menuItem = MenuItem("_Help") mainMenu.append(menuItem) helpMenu = Menu() menuItem.submenu = helpMenu }}} If you include the above code in the 'createWidgets' method of our example program, you will see a menubar on the window with nothing in the menus. == Adding Items to Menus == For our menus to be useful, we need to include items to launch commands or store information. There are several categories of items we can include, but here we look at: ''simple items'' (rather like buttons), ''check boxes'', and ''radio buttons''. === Simple Items === A simple menu item shows as a text label. The following code shows the three steps of creating a menu item, attaching a method to call when activated, and adding it to a menu: {{{ #!cobra # create a menu item for 'show values' menuItem = MenuItem("Show values") # attach method to call when menu item is selected listen menuItem.activated, ref .showValues # add the menu item to the editMenu editMenu.append(menuItem) }}} === Check Boxes === Check boxes can be placed onto a menu, using the '!CheckMenuItem' class. We need to store a reference to the checkbox to later retrieve its state, by accessing its 'active' attribute (see the method 'showValues' at the bottom of this page). {{{ #!cobra # create a check box item and add to the edit menu _checkbox = CheckMenuItem("Select me") editMenu.append(_checkbox) }}} === Radio Buttons === Radio buttons on menus are similar to regular radio buttons: the user is allowed to pick one option out of a pre-defined set. To store the state of radio buttons we can use a variable to hold the currently selected option, and provide some methods to change that variable as different options are selected. For example, to select a language from three options: {{{ #!cobra var _language as String def selectCobra(obj, e) _language = "cobra" def selectJava(obj, e) _language = "java" def selectPython(obj, e) _language = "python" }}} The radio buttons can then be set up to call the respective 'selectN' method when toggled: {{{ #!cobra # create some radio buttons _language = "cobra" # set initial option radioItem1 = RadioMenuItem("Cobra") # this one selected by default editMenu.append(radioItem1) listen radioItem1.toggled, ref .selectCobra radioItem2 = RadioMenuItem(radioItem1, "Java") editMenu.append(radioItem2) listen radioItem2.toggled, ref .selectJava radioItem3 = RadioMenuItem(radioItem1, "Python") editMenu.append(radioItem3) listen radioItem3.toggled, ref .selectPython }}} As with standard radio buttons, radio buttons are placed into groups by including the first member of the group in the constructor of subsequent members. === Stock Items and Accelerator Groups === There are several standard menu items that you find in many applications: these are listed in Gtk as a set of [http://developer.gnome.org/gtk/2.24/gtk-Stock-Items.html Stock] items. Stock items can be used on menus by creating an instance of an '!ImageMenuItem'. Because these standard items are also usually linked with keyboard shortcuts (such as CTRL-Q to quit the application), the menu items must also be linked to an ''accelerator group''. The following code creates an accelerator group, and then adds 'new', 'open', 'save' and 'quit' items to the file menu: {{{ #!cobra # create an accelerator group acceleratorGroup = AccelGroup() .addAccelGroup(acceleratorGroup) # -- new item menuItem = ImageMenuItem(Stock.new, acceleratorGroup) listen menuItem.activated, ref .newAction fileMenu.append(menuItem) # -- open item menuItem = ImageMenuItem(Stock.open, acceleratorGroup) listen menuItem.activated, ref .openAction fileMenu.append(menuItem) # -- save item menuItem = ImageMenuItem(Stock.save, acceleratorGroup) listen menuItem.activated, ref .saveAction fileMenu.append(menuItem) # -- separator fileMenu.append(SeparatorMenuItem()) # -- quit item menuItem = ImageMenuItem(Stock.quit, acceleratorGroup) listen menuItem.activated, ref .quit fileMenu.append(menuItem) }}} == Submenus == A submenu is a menu contained within another menu; a submenu is shown on the screenshot at the top of this page. Submenus are simply menus added to an existing menu instance rather than the menubar. We can create a submenu for the language selector as follows: {{{ #!cobra languageMenu = Menu() # instance of menu on which to build submenu radioItem1 = RadioMenuItem("Cobra") languageMenu.append(radioItem1) # attach the radio items to the submenu listen radioItem1.toggled, ref .selectCobra radioItem2 = RadioMenuItem(radioItem1, "Java") languageMenu.append(radioItem2) listen radioItem2.toggled, ref .selectJava radioItem3 = RadioMenuItem(radioItem1, "Python") languageMenu.append(radioItem3) listen radioItem3.toggled, ref .selectPython languageMenuItem = MenuItem("Language") # create a menuitem labelled 'Language' languageMenuItem.submenu = languageMenu # and attach the languageMenu to it as a submenu editMenu.append(languageMenuItem) # before adding to the edit menu }}} == Complete Example == {{{ #!cobra # @args -pkg:gtk-sharp-2.0 # remove initial '#' use Gtk class ExampleWindow inherits Window cue init base.init("Menus Example") .setDefaultSize(300,200) listen .deleteEvent, ref .quit .createMenu def quit(obj, e) Application.quit def newAction(obj, e) print "Clicked new" def openAction(obj, e) print "Clicked open" def saveAction(obj, e) print "Clicked save" def aboutAction(obj, e) print "Clicked about" var _checkbox as CheckMenuItem var _language as String def selectCobra(obj, e) _language = "cobra" def selectJava(obj, e) _language = "java" def selectPython(obj, e) _language = "python" def showValues(obj, e) print "Show values: [_checkbox.active] and language [_language]" def createMenu # create the main menubar mainMenu = MenuBar () # create an accelerator group acceleratorGroup = AccelGroup() .addAccelGroup(acceleratorGroup) # -- menu 1: file menu, with three stock buttons and a separator menuItem = MenuItem("_File") mainMenu.append(menuItem) fileMenu = Menu() menuItem.submenu = fileMenu # create an accelerator group acceleratorGroup = AccelGroup() .addAccelGroup(acceleratorGroup) # -- new item menuItem = ImageMenuItem(Stock.new, acceleratorGroup) listen menuItem.activated, ref .newAction fileMenu.append(menuItem) # -- open item menuItem = ImageMenuItem(Stock.open, acceleratorGroup) listen menuItem.activated, ref .openAction fileMenu.append(menuItem) # -- save item menuItem = ImageMenuItem(Stock.save, acceleratorGroup) listen menuItem.activated, ref .saveAction fileMenu.append(menuItem) # -- separator fileMenu.append(SeparatorMenuItem()) # -- quit item menuItem = ImageMenuItem(Stock.quit, acceleratorGroup) listen menuItem.activated, ref .quit fileMenu.append(menuItem) # -- menu 2: edit menu, with menu item, check item, and submenu menuItem = MenuItem("_Edit") mainMenu.append(menuItem) editMenu = Menu() menuItem.submenu = editMenu # create a menu item for 'show values' menuItem = MenuItem("Show values") # attach method to call when menu item is selected listen menuItem.activated, ref .showValues # add the menu item to the editMenu editMenu.append(menuItem) # create a check box item _checkbox = CheckMenuItem("Select me") editMenu.append(_checkbox) # create some radio buttons on a submenu _language = "cobra" # set initial item languageMenu = Menu() radioItem1 = RadioMenuItem("Cobra") languageMenu.append(radioItem1) listen radioItem1.toggled, ref .selectCobra radioItem2 = RadioMenuItem(radioItem1, "Java") languageMenu.append(radioItem2) listen radioItem2.toggled, ref .selectJava radioItem3 = RadioMenuItem(radioItem1, "Python") languageMenu.append(radioItem3) listen radioItem3.toggled, ref .selectPython languageMenuItem = MenuItem("Language") languageMenuItem.submenu = languageMenu editMenu.append(languageMenuItem) # -- menu 3: help menu menuItem = MenuItem("_Help") mainMenu.append(menuItem) helpMenu = Menu() menuItem.submenu = helpMenu menuItem = ImageMenuItem(Stock.about, acceleratorGroup) listen menuItem.activated, ref .aboutAction helpMenu.append(menuItem) # Add the menubar to the top of the window box = VBox(false, 0) # make this 'false' so menubar stays compact box.packStart(mainMenu, false, false, 0) .add(box) class MainProgram def main Application.init window = ExampleWindow() window.showAll Application.run }}}