Before we delve into the details of ET, it may be helpful to review the concept of an event loop and an event-driven program. Many ET users have never before written an event-driven graphical user interface (GUI) and may be unfamiliar with how such programs operate. If you are such a user, you may profit from this quick review. But if you are already familiar with event-driven programs, feel free skip ahead to section 5.
The only inputs to a GUI are ``events.'' An event is a notification that something interesting has happened. Events arrive whenever the mouse moves, or a mouse button is pressed or released, or a key of the keyboard is pressed, and so forth. A event-driven GUI differs from more familiar command-line programs in that its inputs (e.g. events) do not arrived in any predictable sequence. Any kind of events can arrive at any time, and the GUI program must be prepared to deal with them.
The code for an event-driven GUI can be divided into two parts: the initialization code and the event loop. The initialization code runs first and does nothing more than allocate and initialize the internal data structures of the application. As soon as the initialization code completes, the application enters the event loop. Within the event loop, the program waits for the next event to arrive, reads the event, and processes it appropriately. The loop then repeats. The event loop does not exit until the program terminates.
This is a schematic view of a typical GUI program:
main(){ /* Initialization code */ while( /* More work to do */ ){ /* Wait for the next event to arrive */ /* Read the next event */ /* Take appropriate action for the event just read */ } }Don't worry about the details here. Most of the event loop processing is handled automatically by Tcl/Tk and ET. The important things to know are that the event loop exists, it runs after the initialization code, and that it doesn't terminate until the program exits.
If you've never written an event-driven program before, and you are like most people, then you will have a little trouble at first. To help you get started, here are some important points to remember:
The initialization code does only one thing -- initialize. It creates the main windows of the application (but it doesn't draw the windows -- that happens in the event loop!) and it sets up internal data structures. But the initialization code should never wait for input or respond to an event. Waiting and reading inputs and responding to events should happen only in the event loop.
Everything that a GUI program does is in response to some event. Any C procedure or Tcl/Tk command that is called in response to an event is referred to as a callback. Because all inputs to a GUI program are in the form of events, the only place for user-initiated processing to occur is within the callback routines.
A callback should do its job quickly and then return. Otherwise, the event loop will not be able to respond to new events as they arrive, and the program will appear to ``hang''. If you have a callback that needs to execute for more than a few hundred milliseconds, you should either invoke the ``update idletasks'' Tcl/Tk command periodically within the callback, or you should break the callback's calculations up into several separate routines that can be invoked by separate events.
Once started, GUI programs tend to run for a long time -- hours, days,
weeks or even months. Hence, you should take special care to avoid
memory leaks. A memory leak occurs when you allocate a
chunk of memory from the heap using malloc()
but don't
return that memory to the heap using free()
when you are
done with it.
Because the memory was not released by free()
it can never
be reused.
When this happens, the amount of memory required by your application
will constantly increase, until at some point it will consume all
memory available, and then die.
Memory leaks are probably the most common bug in GUI programs (which is
why I mention them.)