For proper interactive use of Tk it is necessary to understand its event mechanisms. X Windows toolkits can be used for output, to display windows, draw lines, polygons, pictures etc. This is done simply by calling a specified Xlib primitive which will ask the X server to update the display accordingly and then it returns. The program that has issued this call can then either wait until the display is finished, or continue with any other computation.
For input, like e.g. moving the mouse, clicking a button, typing on the keyboard or resizing windows, the situation is different: The program does not necessarily know when any of these events are going to happen but when they do, it wants to know about them. There are two general approaches to handle this situation:
KEGI users will remember that KEGI-XPCE has used the former method. Its advantage is that the user program does not have to care about accepting the events and the program structure might be simpler. The disadvantage is that interrupt handling is usually more time-consuming than a simple function call and so with many interrupts it may run slower. Another problem, especially in Prolog, might be how to pass data to the interrupt handler routine. This has to be done with global variables, since the interrupt handler is executed asynchronously and it cannot access data from the currently executed code.
X Windows uses the latter approach, X events have to be explicitly polled. The Tk interpreter wish does this automatically in some cases, so that most Tk programs do not have to care about the events:
When we move the cursor to the button, its background changes, i.e. wish handles this event as soon as it occurs. If we then execute a loop that takes some time, e.g.button .b -text 1 -command exit; pack .b
we will notice this time that we we move the cursor to the button, nothing happens - until wish prompts back, no events are handled and the background of the button does not change. If we have clicked on the button during the loop, wish exits only after the loop is finished. This is important particularly for applications that use Tcl/Tk only as GUI to their own functionality, like is the case for ProTcXl , because most of the time the application will be executing external code, e.g. Prolog predicates. If we want to handle events in such cases, the user programs must poll them explicitly. In Tk, the update command waits untill all pending display output is finished and it also checks if there are any new events and if so, they are properly handled. When we modify our previous loop tofor {set i 1} {$i < 100000} {incr i} {}
we can see that it behaves as expected - the background of the button changes when we move the cursor to it and the programs exits immediately when we click on the button.for {set i 1} {$i < 100000} {incr i} {update}
Most of the built-in widgets have some predefined event handler, e.g. clicking on a button, typing into an entry etc. Tk has a very simple and general interface that allows any widget to specify X11 events which it wants to be notified of. It is in principle possible to handle any X11 event in any of the Tk's widgets. The bind command binds a specified event with a specified widget or widget class and with a given script. Each time this event is triggered inside this widget, e.g. cursor entry, typing in a character, mouse click etc., this script is executed. For instance, the following commands will trace the cursor entering and leaving the toplevel window:
bind . <Enter> {puts enter} bind . <Leave> {puts leave}
The script, which is the last argument of the bind command, can contain special fields which are replaced by the values from the X11 event structure when the script is executed. The following example will display the cursor coordinates when the left mouse button is pressed in the toplevel window:
bind . <ButtonPress-1> {puts "%x %y"}
The description of all special event fields can be found in the Tk manual page of the bind command.