Menus help to intuitively navigate your way through an application. We can easily create menus using Tcl/Tk.
Different methods are available to create a menubar in Tcl/Tk. This article follows the TkDocs Tutorial – Menus tutorial and credit due for the majority of the code presented here is theirs alone.
The main menu typically appears immediately below the title bar of the application. PopUps appear when we right-click the mouse, and toolbars may co-exist as part of the menu bar or reside in their own floating window.
A top-level window can only have one menubar. However, you can use the same menubar on any number of top-level windows.
Several menu configurations are available:
- Pulldown Menus in Menubar – Create one or more menu widgets and add one or more cascade entries to each widget. The menubar is the collection of menu widgets you create.
- Pulldown Menus in menu buttons – Create one menubutton widget for each top-level menu and add them to a menubar window. Each menubutton is the parent of a top-level menu and corresponding submenus.
- Popup Menus – Call the tk_popup procedure to post the top-level menu containing the menus and cascaded submenus.
- Options Menus – Use the tk_optionMenu procedure to create option menubuttons and their menus.
- Tear-off Menus (not available in Aqua/MacOS)
Pulldown Menus in Menubars
We will focus on the first of these menu configurations: Pulldown Menus in menubars
It is easier to maintain your “front end” code in a file separate from your procedures. You can execute your front-end code independent of the back-end code using default procedures as placeholders until the real code is developed.
The syntax for the menu and tk_menuSetFocus commands appear as follows:
- menu pathName ?options?
- tk_menuSetFocus pathName
NOTE: The menu command creates a menu widget as a new top-level window given by the pathName argument. We can use this menu widget as a popup window or apply it to a top-level window using the “-menu” option.
Menu Entry Types
- Command – a Tcl command is executed when invoked.
- Separator – a horizontal separator ONLY.
- CheckButton – functions as a normal check box with optional -command when invoked.
- RadioButton – functions as a normal radio button group with optional -command when invoked.
- Cascade – has an associated menu as determined using the -menu option. (post cascade) with optional -command when invoked.
- Tear-Off – A dashed “tear off” line appears at the top of the menu and left-clicking it creates a copy of the menu and all of its submenus. This functionality is not common to most applications and is best disabled using
Create a Simple Menu
The code is a compilation of the code presented in TkDocs Tutorial – Menus code for a simple menu system using Tcl/Tk 8.6.12. Tcl/Tk commands are shown with a BOLD font. Lines beginning with a # (octothorpe) are comments.
# https://tkdocs.com/tutorial/menus.html
package require Tcl
# > 8.6.12
# Our GUI uses Tk
package require Tk
# > 8.6.12
# Before attempting to make changes or additions to your system menus, you need
# to know and confirm the platform you are working on as each has it's own unique
# features and parameters.
set osPlatform [tk windowingsystem]
# > win32
# A new "toplevel" window appears when package require Tk command is invoked. To
# create a new window to test the code, use the toplevel command followed by a
# path and name for your window.
toplevel .wndw
# Create a menubar in the new window.
menu .wndw.menubar
.wndw configure -menu .wndw.menubar
#----------------------------------------------------
# GLOBAL method to disable the "Tear-Off" feature.
# option add *tearoff 0
#----------------------------------------------------
# Save typing set "m" to menubar
set m .wndw.menubar
# The following code does NOT disable the menu tearoff feature
$m configure -tearoff 0
# Add menu entries
menu $m.file -tearoff 0
menu $m.edit -tearoff 0
$m add cascade -menu $m.file -label File
$m add cascade -menu $m.edit -label Edit
# Add menu items
$m.file add command -label "New" \
-command "fileNew" \
-accelerator "Ctrl + N" \
-underline 4
$m.file add command -label "Open..." \
-command "fileOpen" \
-accelerator "Ctrl + O" \
-underline 4
$m.file add command -label "Close" -command "closeFile"
# Add Separator
$m.file add separator
# Add submenus
# Create a list of items to use as submenus
set items [list One Two Three Four]
menu $m.file.items -tearoff 0
$m.file add cascade -menu $m.file.items -label "Items"
foreach item $items {
$m.file.items add command -label $item -command "puts $item"
}
# Add Separator
$m.file add separator
#--------------------------------------------------------------------------------
# The following procedure is "called" by the checkbox and radiobutton menus
# using: -command stub variableName
#
proc stub { ChkBoxRadBtn } {
puts "entered: proc stub"
puts $ChkBoxRadBtn
puts "exiting: proc stub"
}
#--------------------------------------------------------------------------------
# checkbutton and radiobutton use GLOBAL variables to store values. Precede the
# variable name with two colons ($::) to get the value stored in a global variable, # as in this example: puts $::variableName
# Check Button
# Create the global variable for the check button
set checkVal 1
# Add Check Button
# Wrap the command with braces {} to prevent variable substitution.
$m.file add checkbutton -label Check -variable checkVal -onvalue 1 -offvalue 0 -command {stub $::checkVal}
# Add Separator
$m.file add separator
# Radio Button
# Create the global variable for the radio buttons
set radioVal 1
# Add Radio Buttons
# Wrap the command with braces {} to prevent variable substitution.
$m.file add radiobutton -label One -variable radioVal -value 1 -command {stub $::radioVal}
$m.file add radiobutton -label Two -variable radioVal -value 2 -command {stub $::radioVal}
$m.file add radiobutton -label Three -variable radioVal -value 3 -command {stub $::radioVal}
$m.file add radiobutton -label Four -variable radioVal -value 4 -command {stub $::radioVal}
# Use the MENU in a new top-level window
toplevel .newWndw -menu $m
Menu Entries
Menu entries contain three fields depending on the entry type:
- The main field is a label and may be either -label, -bitmap, or -image
- The -accelerator field appears to the right of label and is for display purposes only. Use the bind command to set the binding for the applicable key combination.
- The indicator field appears to the left of the label and indicates the selection status for radio buttons and check boxes.
One Menu – Many Windows
You can set the top-level window menubar to any menu you create. All top-level windows using the same menu are
toplevel PathName -menu MenuWidget
?Options?
Next Steps
Part 2 of this post delves into manipulating menus, system menus, popups, virtual events, and more.
Related Articles and Resources
menu manual page – Tk Built-In Commands (tcl.tk)
TkDocs Tutorial – Menus (Supports multiple languages: Python, Tk, Ruby, and Perl)
Tk Built-In Commands – menu manual page (tcl.tk)
menubar – Create and manipulate menubars (tcl-lang.org)
Tk_ConfigureWidget manual page – Tk Library Procedures (tcl.tk)
bind manual page – Tk Built-In Commands (tcl.tk)
menubutton manual page – Tk Built-In Commands (tcl.tk)
ttk::menubutton manual page – Tk Themed Widget (tcl.tk)
menubar – A command that creates menubar objects (tcl-lang.org)
Tcl Language Sites
Tcl Developer Site (tcl-lang.org)
Download Tcl/Tk
Download Enterprise-grade Tcl from ActiveState
Magicsplat Tcl/Tk for Windows | Magicsplat
Recommended Reading
book.PDF (columbia.edu) (Part 1)