This chapter introduces you to the fundamental concepts of programming in Tk. Unlike the previous chapters, I’m not going to use a game program to illustrate the text. Instead, I’m falling back to that most ubiquitous of all programs, “Hello World,” to illustrate Tk programming. As an introductory chapter, this chapter will be light on code and long on text, as it discusses topics including event-driven programming and widget attributes and operations. Covering this information here simplifies my job in the rest of the chapters because most Tk programming assumes familiarity with material presented in this chapter. The chapter closes with a description of each of the widgets available to Tk programs.
The following script demonstrates most of the features of a Tk program (see hi.tcl in this chapter’s code directory):
label .l -width [string length "Hello, Tk World!"] -text "Hello, Tk World!"; button .b -text "Exit" -command exit; pack .l -padx 40 -pady 10; pack .b -padx 40 -pady 10;
wish
Unlike text-mode Tcl programs, which use the tclsh interpreter, Tk programs need to be interpreted using wish, the Tk interpreter (short for windowing shell). If you try to execute Tk scripts using tclsh, you’ll get errors about invalid commands:
$ ttclsh hi.tcl
invalid command name "label"
while executing
"label .l -width [string length "Hello, Tk World!"]
-text "Hello, Tk World!""
(file "hi.tcl" line 5)
When executed, hi.tcl displays the screen shown in Figure 9.1.
Left-clicking the Exit button closes the window and terminates the application.
Tk consists of about 45 Tcl commands that create user-interface widgets. Widgets are user-interface items such as windows, text boxes, drop-down boxes, scrollbars, and buttons that provide a particular type of functionality in a graphical user interface. For example, in Figure 9-2, the Hello World! application has two user-interface (UI) widgets: a label widget that contains the “Hello, Tk World!” text and a button widget that serves as the Exit button.
Tk programs are event-driven. In this context, an event can be keyboard activity; mouse movement or clicks; window creation, destruction, resizing, or movement; or I/O completion (both local and network I/O). Fortunately, Tk widgets handle most events automatically, so all you have to do is write the code specific to your application. If you want, you can use the bind
command to associate commands and events. The reason you might do this would be to exercise greater control over the control flow in your Tk program or to override or supplement Tk’s default event handling.
The Hello World program in the previous section contains all of the components a Tk application needs, for example, UI widgets for receiving input and displaying output, the graphical conventions of the host platform, and the application-specific code that provides the functionality you want.
As you can see in Figure 9.2, Hello World sports two Tk-specific widgets, a text label and a button. The button, naturally, creates an on-click event when it is pressed and released, causing the command associated with that button to execute. The label is the canvas, if you will, on which our cheery message displays (Tk also has a canvas widget, but that is the subject of Chapter 15, “The Canvas Widget”). Figure 9.2 also calls out the foreground and background areas. These are not widgets themselves, but they are widget attributes that you can set, for example, by changing their color.
The other graphical elements of the window shown in Figure 9.2, such as the title bar and the control buttons on the left and right sides of the title bar, are not Tk widgets. Rather, they are created and managed by the underlying graphical system in use. I captured Figure 9.2 on a Linux system (Ubuntu 7.04, to be precise) using the GNOME window manager. For comparison, have a look at Figure 9.3, which shows the Hello World application running on Mac OS X, while Figure 9.4 shows Hello World running on a Windows XP system.
For the record, I didn’t modify the code at all to run on OS X or Windows. I just copied the script file to the appropriate system and used each platform’s native wish
executable to run the script. Notice that Tk readily adapts to the UI conventions (the “look-and-feel”) of the host operating system or graphical system.
The other component of any Tk application is the application-specific Tcl (or Tk) code you write that provides the desired functionality. Hello World’s code is pretty simple. The first line creates a label named .l
containing the text Hello, Tk World! I use a plain vanilla Tcl command, string length
, to set the width of the label, but this is not strictly necessary because Tk automatically sizes the label to contain the specified text. The second line of code creates a button named .b
with the word Exit on it that invokes Tcl’s exit
command when the button is activated.
The final two commands use the pack geometry manager to arrange the specified widgets in the parent widget. I’ll discuss geometry managers in later chapters (the pack geometry manager in particular is covered in the next chapter), but they are responsible for laying out and managing the widgets in a window. In this case, I use the pack
command to position the text label at the top of the window with 40 pixels of space, or padding, on either side and 10 pixels of padding above and below the label. Next, I place the button below the label, again using 40 pixel pads on the sides and 10 pixel pads on the top and bottom. Order matters—if I had reversed the two pack
commands, the button would appear above the label. More about pack
in the next chapter.
Geometry managers serve another important function: They register widgets with the windowing system so they will be visible. Just defining a widget isn’t enough; it must be activated by asking the geometry manager to map it into a window.
Tk widgets are arranged in a hierarchy which establishes a parent-child relationship. The top-level widget is named.
(period), which corresponds to the main application window. The initial period in the name is required. Subsequent periods denote that the widget to the right of the period is a child of the widget whose name appears to the left of the period. Accordingly, widget names cannot contain embedded periods.
The main application window is the parent of all other widgets in the application. Thus, the .l
label widget and the .b
button widget are children of the main application window. Similarly, if I create two smaller labels inside the .l
label named top
and bottom
, they would be named .l.top
and .l.bottom
. This means, for example, that the label named top
is the child of the label named l
, which in turn is the child of the top-level or root widget, which is named... Widget names must begin with either lowercase letters or numbers, an artifact of Tk’s origins in UNIX and the X Window System. Without going into the gory details, the X resource database is a configuration system for X applications and their constituent widgets. The resource database uses initial uppercase letters in its resource names, so Tk uses lowercase letters (and digits) to avoid conflicts with the resource database and to provide an easy, mnemonic method to relate Tk’s widget configuration items to X’s configuration items.
To summarize, the following rules apply to Tk widget names:
The initial period is required.
Names cannot include embedded periods.
Names must begin with a lowercase letter or a digit.
Although it sounds intimidating, event-driven programming is simple from the application programmer’s perspective. After widgets are initialized and an application is running, Tk-based programs enter an event loop. Consider the event loop to be a big switch
command (as discussed in Chapter 5, “Working with Lists”). Each widget in the application can generate one or more unique events. In terms of the switch
command as described in Chapter 5, each event corresponds to a pattern. When an event occurs, such as a key press, Tk searches for the matching pattern in its list of possible events to find the event handler (the body of code that needs to be executed) corresponding to that event and executes it. After executing the handler, control reenters the main event loop and waits for another event to occur. In most applications, multiple events can occur nearly simultaneously, so the event loop includes a queue onto which pending events are enqueued until they are handled.
The good news for you is that Tk handles the event loop and the event queue for you. Your mission is to decide to which events you want to respond. For example, in my Hello World program, when the Exit button is clicked, I want the exit
command invoked. Tk’s button widget is already “wired” to invoke a handler (you can tell this is the case because it supports the -command
option); all I had to decide was what the handler would be. In Hello World, I used Tcl’s exit
command, but I could have invoked any built-in Tcl command or written a procedure of my own.
If all you could do with Tk was create widgets using their stock appearance and default behaviors, Tk’s usefulness would be limited. However, all of Tk’s widgets support a common set of attributes and options that considerably extend their capabilities. In addition to the standard options and attributes (see Table 9.1), each individual widget has its own unique attributes and options that enable it to function and enable developers to customize and control that widget. Instead of repeatedly listing the standard options and attributes that all Tk widgets support, Table 9.1 lists them once. Subsequent chapters will introduce only options and attributes unique or specific to the widgets under discussion.
Table 9-1. Standard Tk Widget Options
Option | Description |
---|---|
| Sets the background color of the active element; the active element is the element over which the cursor is positioned or on which a mouse button is pressed. |
| Sets the width in pixels of the border of the active element. |
| Sets the foreground color of the active element (see -activebackground). |
| Sets the position of text in a widget (one of |
| Sets the background color. |
| Alias for |
| Alias for |
| Specifies the bitmap to display in the widget. |
| Sets the width of border around (outside) a widget. |
| Indicates whether a widget should display both text and a bitmap simultaneously and the position of the bitmap relative to the text (one of |
| Sets the mouse cursor used when the cursor is positioned over the widget. |
| Sets the foreground color used for disabled widgets. |
| Toggles whether or not the selected text in a Tk widget should also be the X selection. |
| Alias for |
| Sets the font used to draw text on a widget. |
| Sets the foreground color for a widget. |
| Sets the background color of a highlighted region of a widget that has the input focus. |
| Sets the color of a highlighted region of a widget that has the input focus. |
| Sets the width of the highlighted region of a widget that has the input focus. |
| Sets the image displayed in a widget, overriding |
| Sets the alignment of text in a multi-line text widget; must be one of |
| Sets the amount of padding to the right and left sides of a widget. |
| Sets the amount of padding above and below a widget. |
| Sets the 3D effect of a widget; must be one of |
| Sets the delay in milliseconds a button or key must be depressed before it starts to autorepeat, used with |
| Sets the number of milliseconds between auto-repeated key and mouse button presses; used with |
| Sets the foreground color used for selected items. |
| Sets the string displayed in a widget. |
| Sets the variable whose value is the string to display in a widget; when the value changes, the widget text updates automatically. |
| Sets the character index of a character to underline in a widget. |
| Specifies the maximum length of a line of text before it will be wrapped. |
That an option is considered standard does not also mean that all widgets support the option. For example, the option -activeborderwidth
is standard, but in practice, only those widgets that display multiple elements simultaneously, such as menus or top-levels, support it. Menus, for example, only display a single submenu at a time, so they do not support the -activeborderwidth
option.
Despite its length, Table 9.1 is not an exhaustive list of all of Tk’s standard widget options. The options manual page (man 3tk options
) lists all options that are considered standard in any given release of Tk. As of Tk 8.4.14, I counted 42 so-called standard options. I recommend browsing the list to see the complete list.
Table 9.2 lists the widgets supported in Tk 8.4 and the chapter in this book where they are discussed. There are “only” 18 widgets, but when you consider the attributes and options they support, you’ll quickly realize that the Tk toolkit is rich and full-featured.
Strictly speaking, the widget names listed in Table 9.2’s first column are actually the commands that create the corresponding widget. The distinction is subtle and not important in practice, but if you need to be precise, well, there you are. In this chapter, I won’t describe the listed widgets because I cover all of them in subsequent chapters.
Table 9-2. Tk Widgets
Chapter | Description | |
---|---|---|
button | 10 | Creates a command button. |
canvas | 15 | Creates a canvas on which graphic primitives and widgets can be drawn. |
checkbutton | 10 | Creates a checkbox or toggle button. |
entry | 12 | Creates an editable, one-line text-entry box. |
frame | 11 | Creates a container for positioning other widgets. |
label | 11 | Creates a read-only, multi-line text box. |
labelframe | 11 | Creates a frame that also has label-like features. |
listbox | 13 | Creates a scrollable, line-oriented list. |
menu | 10 | Creates a menu. |
menubutton | 10 | Creates a menu item that displays a menu. |
message | 11 | Creates a read-only, multi-line text box in a dialog box. |
panedwindow | 11 | Creates a container for displaying other widgets in a pane-like manner. |
radiobutton | 13 | Creates one of a set of radio buttons for setting a variable’s value. |
scale | 15 | Creates a slider widget that can scale the value of a variable. |
scrollbar | 14 | Creates a widget that scrolls the viewport of another widget. |
spinbox | 12 | Creates a text-entry widget that adjusts a variable’s value using spinner buttons. |
text | 14 | Creates a general-purpose text-entry widget. |
toplevel | 11 | Creates a frame that becomes a new top-level window. |
Tk programs are more than just Tcl programs with a layer of eye candy applied. Tk implements a full event-driven programming model for graphical applications and includes a rich set of highly configurable UI elements, called widgets, to give Tcl applications the same smooth, easy-to-use graphical interface as other graphical toolkits. Although Tk’s widgets are its own, Tk applications adopt the look and feel of the host platform’s native windowing system, freeing Tk developers to focus on functionality instead of emulating an interface.
Like many graphical toolkits, the Tk programming model arranges widgets in a hierarchical, parent-child relationship. This arrangement makes it easy to manage groups of widgets at once. Although Tk relies heavily on event-driven programming, application developers rarely need to be concerned with the mechanics of the event loop; rather, developers only need to select or write the handler for a given event generated by a widget. Tk takes care of the rest of the event model automatically, again, freeing Tk developers to focus on their application. Tk 8.4 defines 18 widgets for programmers to create and use. This might seem like a small number, but the range of available widgets covers the gamut of standard graphical UI elements (buttons, frames, text entry and display, list boxes, and scrollbars). Between the variety of widgets available and their flexibility, you could write a lot of Tcl programs and never need anything more than what’s available in the standard Tk toolkit.