February 28, 2021
Hot Topics:

Perl/Tk Menus: Past, Present and Future

  • By Steve Lidie
  • Send Email »
  • More Articles »

perl tutorial

Whether they drop down as rectangles or pop up as pies, menus are widgets that manage bundles of related information. Menus are pervasive, appearing in nearly every graphical application. In this article we'll examine pulldown and popup menus, Tk 4 and Tk 8 style menubars, and finally, peek into the future and see one way menus might evolve.

Several years ago, Unix-only Tk 4 evolved into Tk 8, adding support for Windows and the Macintosh. The Tk team seized this opportunity to improve their menu design, by simplifying menus and unifying their management across the three operating systems. (Note that Tcl/Tk runs on Macs, but Perl/Tk doesn't. And by the way, there wasn't a Tk 5, 6, or 7: the jump was to synchronize Tk's number scheme with Tcl's.)

There's still a lot of Tk 4 code out there, so it's helpful to be familiar with both Tk 4 and Tk 8 menus. Indeed, most menu code is Tk 4 style, simply because it has been around the longest and works just fine in Tk 8.

If you're still using Tk 4, that's okay for the short term. But you miss out on the new features and widgets, and, most importantly, support and bug fixes. You also can't run some of the demonstration code that goes with this article.

Menu Terminology

You probably know how menus behave. In Tk lingo, menus are widgets containing one or more menu items. A menu remains hidden until it is "posted", usually by clicking a menubutton, and then the menu's items are displayed, vertically, in a rectangular window. Once a menu item is selected, the menu is unposted. Figure 1 shows a menubutton, two menus, and the six different Tk menu items (described shortly). Most applications have several menubuttons arranged in a row across the top of their main window, packaged in a construct termed a menubar. In Tk 4 a menubar is a frame widget filled with menubutton widgets, but in Tk 8 a menubar is a special menu widget filled with "cascade" menu items. We'll explore menubars in detail later.


Figure 1: Menu Items

In addition to cascades, there are five other menu items: command, checkbutton, radiobutton, separator, and tearoff, all shown in Figure 1. Except for separators and tearoffs, these items are composed of two fields each, a label and an accelerator. The label is usually a text string (but might be an image) that identifies what the menu item does. The optional accelerator activates a menu item with a keyboard shortcut rather than the mouse. We'll talk about the various menu items in detail shortly, but first, some brief descriptions.

Some Brief Descriptions Of Menu Items

The most common menu item, command, emulates a button widget because it executes a command (Tk callback) when clicked.

Checkbutton and radiobutton menu items resemble their widget counterparts: Checkbuttons are either on or off, while radiobuttons choose one item from several alternatives. Both of these menu item types can invoke a callback and modify a Perl variable. A cascade menu item posts a sub-menu that contains further menu items. Cascaded menus can contain more cascaded menus. We'll examine cascade menu items in the discussion on menubars.

A separator menu item is simply a thin horizontal line used to divide a menu into logical partitions.

The special tearoff menu item is a dashed line that, when clicked, reparents the menu inside its own decorative window manager border. The torn-off menu then remains permanently posted until destroyed by a window manager action. These window manager actions are often command menu items activated by clicking the top-left corner of the window manager's border, sometimes called the System Menubutton. A tearoff menu item is optional, but, when present, is always the first menu item. In Figure 1 notice that the "Geometry Manager" cascade menu has no tearoff.

Finally, there are times when we need to refer to an individual menu item. We refer to a menu's items with an index, which can be an integer, a Y-pixel coordinate relative to the menu's top left corner, a string to match against menu item labels, or a special identifier: "active", "last", or "none".

Popup Menus

Assuming $mw is our MainWindow, we can create a mostly-empty menu like this:

my $popup_menu = $mw->Menu;

This menu isn't completely empty because it has a tearoff menu item, and the tearoff's menu index is zero. If we add -tearoff => 'no' to the menu creation command, then menu index zero is assigned to the first menu item we create. This menu is also invisible, and can't be managed in the normal fashion with a geometry manager like place(), pack(), or grid(). Menus can only be posted by pressing a menubutton (or cascade), or by manually calling the post() or Popup() method. To make this menu useful, let's add its second menu item, a command:

$popup_menu->command(-label => 'Quit', -command => \&exit);

Menu widgets have methods to create the various menu item types like command(). The separator() method drew the thin horizontal line seen in Figure 1. We'll visit the remaining items types in later sections.


Figure 2: Popup

Now let's create a button whose callback posts the menu (the complete program, popup1, is on the TPJ web site):

my $b = $mw->Button(-text => 'Popup!')->grid;
$b->configure(-command => sub 
               $popup_menu->post(500, 500)

Running popup1 produces the window on the left half of Figure 2. Pressing the button invokes the post() method, and a naked menu appears at screen coordinates (500, 500), with dashed-tearoff and Quit-command items. Pressing the tearoff reparents the menu. Now we can treat the menu as a toplevel, move it around, make menu selections, iconify it, or whatever we like. One problem with the post() method is the need to specify where the menu is to appear. Placing it arbitrarily means that it often won't be near the cursor. That's not very user friendly. Menubuttons conveniently arrange for their menu to pop up right next to the cursor. Since a popup has no associated menubutton, we can use the Popup() method instead, as in the popup2 program:

$b->configure(-command => sub {
              $popup_menu->Popup(qw/-popover cursor/);

When this menu is posted, it's aligned so its north edge touches the cursor -- the contact point is known as the popanchor position. With -popanchor => 'n' (the default value) the menu lies below the cursor. Similarly, with -popanchor => 's' the menu lies above the cursor. All eight cardinal compass directions are legal popanchor values: n, ne, e, se, s, sw, w, nw, as well as c (for center).

Menus don't have to appear above the cursor. They can also pop over other widgets (you provide the widget reference), or even over the root window itself (you provide undef). When a menu pops over something, it can be aligned on any of the standard eight compass points (and center) along the widget's border. This is known as the overanchor position. With -overanchor => 'w', the menu appears on the widget's left edge, and -overanchor => 'e' makes the menu appear on the right edge. Combine -overanchor with -popanchor for fine -grained menu placement.

The Popup() method also works with toplevel widgets. A nice popup demonstration is included with the Perl/Tk distribution, and is on the TPJ web site as ptk-popup.

Page 1 of 3

This article was originally published on August 19, 1999

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date