Customising the Standard Menu Bar

By default, a PyGUI application comes with a standard set of menus containing all the commands that the PyGUI framework itself knows about - Open, Close, Save, Cut, Copy, Paste and so forth. It's likely that you won't use all of these commands in your application, will want to omit some of them. It's also likely that you will want to add new commands of your own. PyGUI offers a variety of mechanisms to do these things in a platform-independent way.

Choosing standard menu items

The basic_menus() function from the StdMenus module provides a starting point for building your application's main menu bar. Without any parameters, it returns a list of menus containing all of the standard commands, arranged according to platform conventions.

If you want to be more selective, there are a couple of ways to go about it. One is to start with all the standard items and take away the ones you don't want using the exclude parameter, which takes a sequence or set of command names. The StdMenus module exports a number of predefined command sets to make this easier. For example, the following creates a menu bar containing all the standard commands except those having to do with files or printing.

from GUI.StdMenus import basic_menus, file_cmds, print_cmds
menus = basic_menus(exclude = file_cmds + print_cmds)

The menu bar is installed by assigning it to the menus property of the application.

app = MyApplication()
app.menus = menus

The other way is to start with a minimal set of commands and add the extra ones that you want using the include parameter. When you specify a value for include, the menu bar will include only those items, plus the fundamental_cmds and edit_cmds, which are considered essential for most applications. The following creates a menu bar containing only the file-related commands and the "Preferences" command in addition to the essential ones.

menus = basic_menus(include = file_cmds + prefs_cmds)

You can use both include and exclude together; this is the only way to omit items from the essential set. The following includes all of the file-related commands except "Revert", and also omits the "Redo" command, which would otherwise be implicitly included because it is part of the edit_cmds set.

menus = basic_menus(include = file_cmds, exclude = ['revert_cmd', 'redo_cmd'])

Note, however, that it is generally a bad idea to exclude items from the essential set. On some platforms, for example, the editing commands need to be present in the menus in order for their keyboard equivalents to work in dialogs.

Modifying standard menu items

Sometimes you will want to give different titles or keyboard equivalents to standard menu commands. For example, in a game you might want the New, Open and Save commands to be called "New Game", "Load Game" and "Save Game", and give "Load Game" a keyboard equivalent of "L" instead of "O".

You can do this easily using the substitutions parameter to basic_menus(). It takes a dictionary whose keys are command names and values are replacement menu item strings. For example:

menus = basic_menus(substitutions = {
    'new_cmd':     "New Game",
    'open_cmd':    "Load Game.../L",
    'save_cmd':    "Save Game",
    'save_as_cmd': "Save Game As..."})

Each replacement can override just the title, just the keyboard equivalent, or both. In the above example, the keyboard equivalent of open_cmd is overridden, but the other commands are left with their standard equivalents.

Adding menus

The simplest way to add new commands is to create one or more extra menus containing your commands, and add them to the end of the application's menu bar. Here's an example of how to do this.

menus = basic_menus()
my_menu = Menu("Widget", [("Swizzle", 'swiz_cmd'), ("Defibrillate", 'defib_cmd')])
menus.append(my_menu)
app.menus = menus

Note that the new menu is added to the menu list before assigning the menu list to the application's menus property. This is important, to ensure that the menu bar is updated properly.

Adding commands to standard menus

Adding your own menus is all well and good, but you may want more control than that. For example, if you have some editing-related commands, you might want to add them to the Edit menu instead of putting them in a menu of their own.

The problem with this is finding the right menu to add them to. PyGUI tries to make as few assumptions as possible about the layout of the standard menus, and if you want your application to be portable, you should do the same. So you shouldn't assume, for example, that the Edit menu is the second menu in the menu bar. (On the Mac, it's not!) You shouldn't even assume that there will be an Edit menu at all.

Rather than a particular menu, it's better to think in terms of putting your commands near existing commands. PyGUI helps you out here by means of the MenuList class. A MenuList is just like an ordinary list, except that it also has a method that will take an internal command name and give you the menu which contains that command. So we can find the menu containing, say, the 'copy_cmd' command, and be fairly sure that it's the Edit menu, or whatever passes for it, on the platform we're running on. Once we've found the menu, we can use its append or extend methods to add our commands to it.

The basic_menus() function returns a MenuList, so here's how we can add some commands to the Edit menu:

menus = basic_menus()
edit_menu = menus.menu_with_command('copy_cmd')
edit_menu.extend(["-", ("Biggify", 'enlarge_cmd'), ("Smallify", 'reduce_cmd')])
app.menus = menus

Future plans

One further thing you might want to do is insert commands in the middle of a menu (to get them even closer to an existing command). This is not currently supported, but is planned for a future version.

---