Tcl/Tk GUI Programming
Lesson #4: the menu widget

Course content Enter chat room Send email
to mailing list
Check calendar

In memory of Linda.  Worldwide Cancer sites here.    Canadian Cancer donations here.
 

In this lesson we are going to learn how to work with the menu widget.   The menu widget will be essential for our graphical interface  work later in the course.

We are also going to learn about the frame container widget and a little about how to manage the Tk window properities.
 
 
REMINDER:
In a previous lesson we showed you how the Wish console also understands a lot of other commands. 

One of these is the command to set the default folder for the source.   For PC users this command is:

    cd  C:/level1

Before we begin the code for lesson #4, here is a possible solution to the exercise we left you with in lesson #3.
 
#=======================================
# scott - entry point
#=======================================
proc scott {mycolor} {

puts stdout [format "lastcolor was %s" $mycolor]

if {$mycolor == "red" } {
	.hello configure -text "change me to yellow" -background green
	set newcolor green
} else {

	if {$mycolor == "yellow" } {
		.hello configure -text "change me to green" -background red
		set newcolor red
	} else {
		.hello configure -text "change me to red" -background yellow
		set newcolor yellow
	}
}

puts stdout [format "newcolor is %s" $newcolor]

return $newcolor

} ;# end of proc scott



#========================================
#  main - entry point
#========================================
set lastcolor red
destroy .hello

button .hello -text "change me to green" -background red \
	-command {set lastcolor [scott $lastcolor]}
pack .hello -padx 20 -pady 20

Notice that the only thing we added was a third "if" branch to handle the case for the yellow condition.
 

Step 1: the menubar

Most of you will have used computer software with pull down menus.     The familiar "File" "Edit"  etc. menubar is across the top of most program windows including the browser you are using to view this page right now.    We are going to learn how to create menus in Tcl/Tk as part of this lesson.

Before we begin we must discuss terminology.

Let us illustrate our lesson by way of an example.

As we did in lesson #3 let's first create a lesson4 folder inside our level1 folder.  Using the now familiar text editor you used in lesson #2,3 create a new file called "lesson4.tcl" and enter the following partial program .
 
#========================================
#  main - entry point
#========================================
destroy .menubar
menu .menubar

.  config -menu .menubar

Note the "." in front of config is on its own. ie. there is a space before the word config.

When you run this program with "wish" it won't be all that impressive.    In fact for you PC Windows users it will look exactly like nothing happened.     The "problem" here is that different computers (PC Windows, Mac, Linux) handle windows slightly differently.

This is as good a point as any to introduce a couple of constructs which will help make our Tk windows behave better.
 

Step 1a: adding a frame

Using your text editor once again add the following statements just before the "menu .menubar" statement above.
 
 
wm geometry  .   200x250+10+10
wm title  .   "lesson 4"

Don't forget to leave a space before and after the "dot" in these statements.     The purpose of this "dot" will be come apparent shortly.   In the meantime if you run your little program once again you should see a slightly bigger window with a proper "lesson4" displayed as the title.     Unfortunately we still don't have an obvious menubar showing up.

To help with this we need to introduce a new widget called a "frame".  Frames can be thought of as their picture frame counterparts.   A picture frame holds a painting or a photograph.  Tk frames are kind of like rectangular containers into which we place widgets.    At this point we are going to simply use the frame to color a section of our window thus leaving the menubar obvious.

You will need to add the following statements after the "wm title" statement above.
 
destroy .myArea
set f [frame .myArea -borderwidth 5 -background blue]
pack $f -side top -expand true -fill both

 
HINT:

Remember to click Save in your editor after each change.

Just in case you are being frustrated because the changes you are making in the editor are not taking hold.

Presto!  When we run our little program now at least PCWindows users will see a blank area under the title ... our menubar!  You may have to look quite hard  to notice it.   It's just above the blue area.

Let's examine the statements in more detail.

Let's deal with the "wm" and "frame" statements first.

We notice a couple of new statements beginning with the command "wm".   Those of you running on a Linux platform might recognize that "wm" is short for window manager.   Tcl/Tk was first developed on a UNIX platform  (UNIX is an older much more expensive version of Linux).   Many of us will be doing these lessons on a Windows or a Macintosh platform.    On these systems the windowing interface is "built in".   The term window manager loses its meaning in that case.    The designers of Tcl/Tk elected to keep with the name in any event.

For our purposes the "wm" command allows us to control the wish window.    We can specify its size.   We can specify where we want it to appear on the desktop.   We can specify which title is to appear at the top of the window.

The first of the "wm" commands concerns the location and size of our window:
 
wm geometry . 200x250+10+10

Recall that in our first Tk lesson we mentioned that the window in Tk is known simply as "." (dot).   The explanation lies once again in Tk's UNIX roots.    Suffice to say that the "." immediately after the word geometry in the command is the name of the Tk window.     The next argument consists of a set of 4 numbers joined by a "x" and a couple of "+".    The first pair of numbers represents the width x height of the window in units of pixels.   ie. our window is to be 200 pixels wide and 250 pixels high.  The next pair of numbers represents the position of the window as measured in pixels from the left of the desktop screen and the top of the desktop screen.  ie. our window will be 10 pixels in from the left and 10 pixels down from the top of the desktop screen.

The second "wm" statement is somewhat obvious:
 
wm title . "lesson4"

It will add the title "lesson4" to the top of our wish window when the program starts running.

We have introduced our first example of a frame construct.
 
set f [frame .myArea -borderwidth 5 -background blue]

Notice the compound statement consisting of an inner and an outer part.   The inner part (inside the [ ]) will be evaluated first and the result will be what "f" is set to.    The inner part sets up a frame widget called myArea.   This frame is attached to the top level window called ".".   This frame widget has 2 attributes set on it:  one for the width of the border and the other for the background color.  This statement is exactly analogous to the button .hello statement which we had in previous examples.

We are then using a pack command to position the outer (parent) frame inside the window.
 
pack $f -side top -expand true -fill both

The "-expand true" arguments tell the packer to allow the packing space containing the frame "f" to expand to as needed into the available window cavity.  The "-fill both" arguments tell the packer to let the frame expand in both (x and y) directions.  Don't worry I find the distinction between these two very difficult to understand ... fortunately I've almost always seen them come together like this.    Suffice to say that if you add "-expand true -fill both" to your pack command things will grow to fill whatever space you have for them in your window.
 

Finally back to discussing menubars!

The first thing we need to recognize is that the Tcl/Tk menu widget designers are a cruel lot.    They decided that menubars and menus are really just the menu widget with different attributes turned on.    I for one find this confusing ... but bear with us it is really not all that bad.

The first statement creates menubar instance of a menu widget called ... you guessed it ... menubar.
 
menu .menubar

This is exactly similar to the
 
button .hello

statement that we used in the previous lesson to create an instance of a button widget.     The command "menu" says "create me a menu widget".    The argument ".menubar" says call it "menubar" and attach it in the main window (called ".").       As with our previous example of the button, nothing will happen until we force the widget to render itself visible.    In the previous button example this was accomplished with the "pack" command.     Menu widgets are special and we don't use a "pack" command to render them.

This is because menus cannot exist unless they are attached directly to other widgets.     In our little example "What other widgets do we have up?"  you might ask.    The answer is we always have the main window up which is itself a widget.    Because menus can only exist when part of a window,  the designers of Tcl/Tk decided to manipulate the menu widget as a special window attribute.

Stay with me here ... it does get easier once we are through this part.    This does explain the next statement:
 
. config -menu .menubar

 
A little tricky ... put not overly so.    The leading "dot" is the representation for the main (or parent) window widget.     The first argument "configure" (or config in the shortened form) behaves exactly the same as the configure argument we used to change an attribute of our button widget in the previous example.    In this case we are changing the attributes of the main window itself.     What we are doing is attaching our menu widget as the menubar in the window.     Just to thoroughly confuse everything the Tcl/Tk designers decided to use "-menu" rather than "-menubar" to do this attachment.   So much for concise terminology.

There is a saying amongst programmers which goes like this:

"If you don't understand a set of statements thoroughly,  go ahead and use them anyway as long as they work."

It is probably good advice for the menubar.
 

Step 2: the menu label

Let's enhance our little program with some menu labels now.     For this we need to add these two statements to the bottom of your little program above:
 
set File [menu .menubar.mFile]
.menubar add cascade -label File  -menu  .menubar.mFile

When you run your program now you will see that we will have added a label called "File" to our menubar.   If you press this label with your mouse you will see that it tries to pop up a menu but all it succeeds in doing is showing a small dashed line.

Here's where the Tcl/Tk menu widget designers tax our understanding a little more.

The first statement is an example of a compound statement not unlike the "format" statements we have already used.   Remember that the stuff inside the "[ ]" gets worked out first.     The result of that is substituted and the whole statement is then resolved.    The "[ ]" above creates another menu widget we have called ".menubar.mFile".     We are then calling this new widget "File" using the "set" command.       Recall from our discussion above how a menu widget cannot exist on its own ... it must be attached to another widget.       This other widget could just as well be another already existing menu widget ... our menubar for example.

The statement :
 
.menubar add cascade -label File -menu .menubar.mFile

does the attachment for us.       The "-label" attribute is what gives us the "File" menu label.

It now might make sense to some of you why we chose that awful name for our newest menu widget:

.menubar.mFile
Think of it as a convenient way of showing a hierarchy.
top level window called "." -> menu widget called "menubar" -> menu widget called "mFile"
If you don't understand this ... don't worry just use it.
 

Step 3: add the menu item

Recall that by using the "$" in front of a variable means use the "value stored at".     We had lots of examples in the previous lesson if you want to refresh your memory.     In the section above we used to "set" command to create a variable we called "File".

We can now reference our pull down menu widget as $File.

Add the following statement to the end of your little program.
 
$File add command -label Quit

Now when you run the program it is starting to look much more like a graphical menu.      The menu item "Quit" should appear.   However, when you click your mouse on the item nothing happens ... yet.

If you recall the button example we had the same challenge.    We resolved that with a "-command" attribute.    Menus are no different.   The only thing we need to add now is an action command when the particular menu item is selected.
 

Step 4: add the action command

The menu widget supports the "-command" attribute much like the button widget did before.     Let's enhance our last statement to look like:
 
$File add command -label Quit -command exit

 
Congratulations.   You now have created your very first menu driven Tcl/Tk program.

 
 

Step 5: final listing

The full listing of the source code for lesson #4 is below.
 
#========================================
#  main - entry point
#========================================

#========================================
# explicitly setup our main window
#========================================
wm geometry  .   200x250+10+10
wm title  .   "lesson 4"

#========================================
# setup the frame stuff
#========================================
destroy .myArea
set f [frame .myArea -borderwidth 5 -background blue]
pack $f -side top -expand true -fill both

#========================================
# create a menubar
#========================================
destroy .menubar
menu .menubar
. config -menu .menubar

#========================================
#  create a pull down menu with a label 
#========================================
set File [menu .menubar.mFile]
.menubar add cascade -label File  -menu  .menubar.mFile

#========================================
# add the menu item
#========================================
$File add command -label Quit -command exit

For those running PCWindows the result of running this program should be something like:


 

Summary

You have been introduced to a bunch of new Tcl/Tk statements and constructs in this lesson.   Let's review:

Exercises

  1. Try extending your little program to add another menu item called "Open" under the File menu
  2.  Extend the menubar by adding the "Edit" and "Help" menu labels
We will leave this exercise for you to complete on your own or by soliciting help from fellow students on the mailing list.

End of Lesson 4.


Copyright of iCanProgram Inc. 2002