PAGE supports toplevel menubars and context menus often called popup menus. PAGE does not support menubuttons.
A popup menu is essentially a callback function bound to a selected widget. Of course, that binding is specified using the Bindings Window.
There is a Menu Editor which facilitates the creation and modification of all the menus for PAGE.
Creation of Menu Bars can be confusing because PAGE bridges Tcl and Python. Let me try to explain! When you create a toplevel window and populate it, you are actually building an interactive tcl program that will later be translated into Python modules. If you populated the toplevel widget with a button PAGE binds Button 1 in such a way that when you click on it, all kinds of magic occurs - the Attribute Editor opens for business, and menus may popup allowing you to cut and copy, specify bindings, etc. - you don’t actually invoke any callback you associated with the button.
With the menu bar, things are different, in that the menu does function in the tcl world. That is, if you specified a cascade sub menu, say File, in the menu bar, and then you click on File in the menu bar the cascade menu opens so you can see it. I think that is good because it allows you to see the structure of the menu bar as you create it. However, if you put in a command entry like Quit and tie it to the function “quit”, which you intend to implement in the Python world, and then in PAGE click on Quit in a menu, Tcl/Tk will attempt to execute “quit”. However, there is no tcl “quit” function defined in PAGE; therefore, you would get a Error window stating “invalid command name “quit”. To avoid this confusing Error message, I have change PAGE in version 4.8.9 to prepend a “#” to the actual command entered in the Menu Editor though it is not shown in the Menu Editor window, so that selecting a command in the menu bar a comment is invoked, i.e, nothing happens; it’s a comment. When the Python code is created, the “#” is. of course, removed. These modifications are in effect for menu commands newly specified or modified. Menus commands specified with earlier version can still give rise to the error. If you see such an error message, you may confidently select OK and continue working with PAGE or you can change the offending command entry - just one character will do as I did with the examples - and then continue.
The confusion does not occur with context (popup) menus because they are callback functions and, therefore, never visible in PAGE.
The menu capability that I use most is the menubar at the top of a top level window. To create such a menu bar, one selects the Toplevel widget and then invokes the Menu Editor in one of several ways
As you edit the menu you will see the menu bar changes appear in the Toplevel Widget; you will not see any of the cascade menus appear.
To create a popup menu one selects the Popupmenu widget in the Widget Toolbar. Then right click on the Popupmenu widget and select Widget->Edit Menu. You can also select the widget and the <click-to-edit> menu field in the Attribute Editor. You do not place it in the toplevel window because that would have no meaning. However, there are menu attributes such as colors and fonts that can be modified in the Attribute Editor. As you edit the popup menu you will not see anything changes in PAGE windows. You can have more than one popup window and a popup window can be associated with more than one widget. The popup menus are called Popupmenu1, Popupmenu2, etc.; in turn, they are implemented in corresponding class functions called popup1, popup2, etc.
Note that while the Widget Tree shows menu bars as child widgets of a toplevel widget, context widgets are shown as child widgets of the root widget. The difference is because the context menus are associated with child widgets only by binding events, usually mouse buttons, to the widgets.
The Menu Editor creates menus. It is invoked as above.
Some of the items in a menu may be simple commands like “Quit” which invokes your quit function. Others are cascade menus like File which are sub-menu of items like “New”, “Open”, “Save”, etc. To specify an action like the “Quit” example,
To put in a cascade menu like File,
To add Open to the File menu,
Of course, you can add cascaded menus to cascaded menus, etc..
When you are all done hit the Check Button on the right.
The menu editing window is repeated below:
When adding entries to a cascade menu, that entry can be another cascade menu. See the reference to the example below.
When creating a menu, one can start by adding either commands which is most common case or a cascade menu which leads to a second level menu. Some of the Tcl/Tk documentation for menus bars say that one should only place cascade items in a menubar. However, I have found it useful and intuitive to have all kinds of items in the menu bar.
I have modified the Menu Editor to allow one to change various colors of individual menu items as well as the fonts for individual items. Then it occurred to me that one should be able to set preferences for default values of menu fonts and foreground and background colors. I have modified the Preference processing to do that. I have not allowed one to set preferences for active foreground or background values. The net setting are in the Fonts and Colors tabs; in the main PAGE menu go to File->Preferences...->Fonts or File->Preferences...->Colors.
Points about adding images to menu entries:
I have included menu.tcl in the examples subdirectory to illustrate some of the things that I have done to test the menu bar facility. Load it, generate the Python and execute it. I wrote the example to test the change in menu fonts and colors as well as having several images and several level of cascaded menus. I certainly do not advocate using weird images, colors and fonts all over the place. But you can.
I am uncertain about the best way to handle fonts in menus. PAGE now sets a variable that is used as the default menu font and that specification is forced everywhere in the menu that is not specified otherwise. However, once specified it is fixed. You cannot change it without re-specifying it everywhere it is used. I may revisit this issue.
The radio menu entry type has options “value” and “variable” which need attention. When a radio button is selected, the variable is set to value. That is, if variable is x and value is a then x is set to a, when the radio button is selected. The way the menu editor works is that when a radio entry is added to a menu, the label and value are set to “NewRadio” and the variable is set to “selectedButton”. If you wish to use the variable setting then you must change the variable to a different value, one you wish to use. PAGE will change create the correct Tkinter Variable Class of type string. It will also threat the value of the value field as a string constant. Change that field to a value that works with your application. Bare in mind that with radio entries in a menu they must all share a singe variable.
The Check menu entry type has options “onvalue”, “offvalue”, and “variable” much like radio entries. The main difference is that the check entry expects that each entry will have its own variable; they are not shared. Again, the PAGE implements the variables as StringVar objects and “onvalue” and “offvalue” as string constants. The variable stuff associated with menus can be bypassed by specifying distinct functions in the command options or by passing distinct parameters to the command function using the lambda function.
To modify a menubar, one needs to open the Menu Editor for the menu bar. That can be done several ways.
One way to open the Menu Editor is to select the Menu widget in the Widget Tree with Button-1 then select the <click-to-edit> field in the Attribute Editor window. The Attribute Editor can also be used to change the menu font, menu colors, etc.
Another way is to select the Menu Widget in the Widget Tree with Button-3. Then select Widget->Edit Menu....
Yet another way way is to select the Toplevel widget and then the <click-to-edit> field next to the menu label in the Attribute Editor.
Also, select the Toplevel widget in the Widget Tree with Button-3, then Widget->Edit Menu Bar.
The final topic to cover is the binding of popup menus to individual widgets. Popup menus are usually activated by mouse events bound to particular widgets. The Tk documentation discusses bindings of mouse events to widgets for different OS’s and PAGE attempts to follow those conventions. This is one of the above mentioned hacks. Note that a GUI may have more that one context menu and also more that one widget may be bound to a context menu. As an example, Lib Demo a photo album like example which displays a number of thumbnail images each of which can invoke the same popup menu.
PAGE implements the callback functions for popups as class methods of the toplevel class because these functions are generated by PAGE. Other callback functions are generated as skeletal functions in the support module. Callback functions for context menus and the menus themselves have special names. The context menus have PAGE generated names like Popupmenu1, Popupmenu2, etc. and the containing callback functions are popup1, popup2, etc. The latter names are reserved for pupup callback functions. This is part of the hack mentioned in the last paragraph. Since there is a close relation between the menu names and callback names, Popupmenu<n> and popup<n>, do not modify menu aliases.
If a popup menu is bound to a widget it is applicable for all subwidgets of that widget. So if you bind a popup menu to the toplevel widget and also bind another popup menu to a subwidget, say a button then hitting the popup button, Button-3 in Linux, both menus will popup.