Navigation Logo 11.2  The Tk Way of Thinking Navigation Logo

 

 

The wish?? program itself is an example of what a GUI application can be. When the Caps script of the previous section is running, you can

  • enter another command in the command window

  • enter text in the root window

  • click on either button in the root window
The choice of what to do belongs to you not the people who wrote the wish?? interpreter and the Caps script.

If these programmers had been working in the traditional way, they would have a horrible tangle of input possibilities to take care of. But GUI applications are not written in the traditional "top down," "one step at a time" manner. Instead, the GUI runtime system generates events and the programmer simply associates actions with those events that are of concern. The associations work something like the following.

For a keystroke belonging to the command window, do ...

For a keystroke belonging to the root window's text entry area, do ...

For a mouse click over the "Caps" button, do ...

For a mouse click over the "Quit" button, do ...

Window Managers

For the Tk programmer, the GUI runtime system consists of two pieces:

  1. The window manager provided by the operating system or a GUI overlay to the operating system. (My use of the term is more inclusive than users of X Windows are used to. Here "window manager" includes both X Windows and any X Windows window manager that may be running under X Windows.)

  2. The Tk runtime system.

The work of going from a key press, key release, mouse movement, or mouse click event to the application's action for that event is largely done by these two runtime systems. The Tk programmer works at a much higher level of abstraction. As the Caps example shows, you can write entire applications without needing to deal directly with keystrokes or mouse clicks.

A function of the window manager is to send messages to Tk about key presses, key releases, mouse movements, or mouse clicks. I call these messages user events to distinguish them from I/O events.

You have probably noticed that you cannot enter text for the Caps example unless you first click on the text entry subwindow. The concept that is important here is that of focus. One window at a time is said to have the focus. This means that keystrokes are directed toward that window. Focus is determined at two levels. The window manager determines which window should have the focus. It gives the focus to the program running that window. This program in the case of the Caps example is wish. The wish?? program then determines which of its windows or subwindows should have the focus.

Tk's default way of handling the focus is to leave the focus unchanged as the mouse moves – it takes a mouse click before Tk will change the focus. Your window manager, however, may handle the focus differently. Thus you could see the focus switching between applications as you move the mouse, but not switching within a Tk application unless you click the mouse.

A second function of the window manager is to control the position and size of all windows. Tk borrows the term geometry from X Windows to refer to a window's position and size. When you use your mouse to move a window around or resize it, the mouse is working with the window manager. The window manager then tells Tk what has been decided and Tk does its best with that decision.

A third function of the window manager is to put windows into a kind of picture frame that includes a title.

You can have some effect on the way the window manager does its job by sending requests to it through the appropriate Tk commands. Remember though, that the window manager is not Tk and it varies from platform to platform or, even, from X Windows user to X Windows user. Programming in a way that counts on window manager behavior can be a mistake.

Widgets

Tk's basic abstraction is the widget. A widget is a potential subwindow (or occasionally a window) that serves some purpose. To serve this purpose a widget has default ways of:

  • displaying itself on the screen

  • dealing with mouse and keyboard input that are directed to it
In the Caps example, there are three widgets, one for each of the two buttons and one for the entry area. The button widgets have each been assigned an action to execute when they are clicked. No actions have been assigned to the entry widget, its default behavior is enough for this example.

Tk gives you four ways of dealing with individual widgets:

  1. You can create a widget of a given widget type. This is done with a widget making command that is named after the widget type, for example, entry, button, or label. As you use this command you must name the new widget.

    For example, here is a command line to create an entry widget.

    entry .entry -textvariable Entry
    
    The widget's name is .entry and the -textvariable option is given a nondefault value of "Entry" which is the name of a variable in the top-level namespace.

  2. You can alter characteristics of a widget that has already been created. This is possible through the actions of an object action family that is created with the widget. This action family is implemented with a procedure whose name is the same as the name of the widget. This procedure is called a widget command but the term also seems to apply to particular actions within the object action family.

    This book distinguishes between three kinds of Tk commands: widget makers, widget commands, and nonwidget commands. The latter is a catchall category for Tk commands that do not fit into either of the first two classifications.

    For example, here is a configure action that will change the value of the -textvariable option of the widget named .entry.

    .entry configure -textvariable SecondEntry
    

  3. You can lay down guidelines concerning the size and position of a widget within another subwindow or window. You will almost always do this with the pack command.

    Any procedure such as pack that helps you fit a widget into another is called a geometry manager. Without a geometry manager, your widgets cannot be seen on the screen.

    Here is the simplest way to put the .entry widget under geometry management:

    pack .entry
    

  4. You can destroy a widget. This is done with the destroy command.

    For example,

    destroy .entry
    

A widget's appearance and behavior are determined by the values of its options. The default values are altered with the widget making command or with a configure widget command. Most defaults do not need to be altered to get some kind of working application running. A few do. The default action associated with clicking a button, for example, is to do nothing. You will hardly get a working application with that behavior.

In general, geometry is something imposed on a window or subwindow from above. However, the entity doing the imposing can be made aware of the window or subwindow's preferences. For example, if you use the -width option to declare the number of characters an entry widget should display, this knowledge percolates up to a size request that is sent to the window manager. The window manager knows what geometry is wanted, but, if the user requests something else, the window manager may very well let the user have his or her way.

Naming Widget Objects

You have to choose a name for each widget that you create. A widget name must be in a form similar to a file's pathname, for example,

.a
.a.b
.a.b.c
Each new widget name you choose either looks like a period followed by a string or is formed from an existing widget's name by appending a period and a string. The string may consist of lowercase letters, digits, and the underscore.

The one exception to this form of name is the root window which is itself a widget named simply ".". In fact, the period at the beginning of a widget's name represents the root window. So if you want a normal widget name to end with .gerbel, you will give it the widget name .gerbel if it is to be a subwindow of the root window and .animals.gerbel if it is to be a subwindow of a widget whose name is .animals.

Remark

Widget names can be long. Choosing names for each component can be a hassle. It is possible to generate them automatically. Of course, this produces widget path names that will be difficult to remember.

However, for many widgets there is no need to work with widget commands, that is, with widget names. After such widgets are under geometry management, you can forget them. Such widget names clearly can be generated automatically. So can widget names that will be stored in variables and not used directly.

When choosing name components by hand, your choices are to choose names the way you would choose variable names (that is, names that tell something of the widgets' purpose) or to choose names that reflect the type of widgets that are involved (for example, button, entry, and so forth).

When you are storing widget names in variables, the latter choice seems wiser because you will already have a variable name for the widget. Otherwise, I do not have a recommendation.

When two widgets have names that differ by one component the way .a.b and .a.b.c do, the shorter name identifies the parent widget and the longer name identifes the child widget. When a widget has a name with one period, for example, .a, its parent is the root window.

When two widgets are mapped to the screen in such a way that one is a direct subwindow of the other, the subwindow is called the slave and the containing window is called the master. The words "master" and "slave" indicate which widget has the last word about geometry.

Remark

For another less-common use of the words "master" and "slave," see above in Executing Scripts from within Scripts.

Thus, "master" and "slave" refer to a relationship on the screen whereas "parent" and child refer to a relationship built into the names. For widgets that, in fact, are represented on the screen, "parent" and "master" are almost always equivalent, as are "child" and "slave." There are only two ways in which this equivalence can be violated. The first involves toplevel windows which have parents but are not slaves because their geometry is managed by the window manager rather than Tk.

The second violation of this equivalence involves an option for using Tk's window managers that is not described in this book. The main purpose of this option seems to be to enable widget names to be shorter. I do not think that is necessary. If a widget name needs to be referenced a lot, then put it in a variable with a short name. That will keep things simple.

Overview of Programming in Tk

You program in Tk mainly by creating widgets and altering their default appearance and behavior. You do this mainly by passing options to the first two kinds of widget processing commands.

You also need to alter the way decisions are made about a widget's geometry. You usually do this with the pack command.

The behavior of some widgets involves executing a script under certain conditions. You control what this script is with the -command option. The script will be executed as a result of what the user does with the keyboard and mouse. Because of the -command option, the Tk programmer can work at a higher level of abstraction than provided by keystrokes and mouseclicks.

Sometimes, however, you want to work at a lower level of abstraction, that is, you want more direct control over what happens when the user does things. You get this control with a nonwidget command called bind. The bind command relies directly on the user-related events. The bind command lets you say: "If such and such a user event happens when I am responsible, then execute this script."

What is actually going on is that Tk takes user events and uses them to trigger appropriate actions. Some of these actions are built into Tk. Others are determined by you with -command or bind. None of these actions is executed immediately. Instead, the triggering mechanism places them on a queue, called the event queue. Tk's runtime system executes a continuous process of placing actions on the event queue and executing the action at the front of the event queue. This process is controlled by a loop called the event loop.

With Tk, everything that happens is controlled by this event loop. Even processing of commands you enter into the command window is controlled by the event loop. This will seem strange at first but you will find an explanation of how such things can happen below in A New Command Window.

Scripts associated with widgets through the -command option and bind command are called event handlers. Much, if not most, of your application's unique behavior comes from its event handlers.

To recap: programming in Tk means to set up widgets and associated actions. The associated actions are set up with the -command option and the bind command. The script that sets them up is called the initialization script. The initialization script can also do Tcl things, such as load data. When you run Tk interactively, what you are typing into the command window is the initialization script.

Two points to keep in mind in designing your Tk scripts:

  • Event handlers do not execute until they have been placed on the event queue. When they execute, event handlers always execute in the top-level namespace. This may be very different than the namespace in which they are defined. This difference can be confusing. For those event handlers which must use variable substitution in a way that is not very trivial, it is best to minimize the use of the top-level namespace by putting an event handler's real action in a procedure.

  • While an event handler is executing, other events cannot be triggered. This includes user events and can be very frustrating for a user. Try to keep the runtime of your event handlers short. If you must write an event handler that will run a long time, provide a visual cue to the user indicating that some waiting may be necessary.

Remark

The event queue and event loop are available in Tcl but the Tcl event loop does not start executing unless requested and, even when it does execute, it cannot handle user events. As an extension of Tcl, Tk adds the ability to handle these user events and starts with event-driven execution from the beginning. You can find more detail about Tcl's basic event loop above in The Event Loop and More about the Event Loop but you do not need that detail to write most Tk programs.

In any case, you should know that there are more kinds of events than user events. You should know this but you need not think seriously about it at this time because these other kinds of events are not important in many Tk applications. Some of them are are described above with Tcl's event loop. Others are mentioned briefly with this book's Tk material. These others are user-related events that tell widgets things like "the focus is being taken away from you."

 

 

[Sample TK Application]
Author's Home Page
Navigation Logo [Book's Cover]
Order from Amazon.