Event Handling in Graphical User Interfaces
A state machine is something that has a state and can change state in response to events or inputs, and its response to an event depends on the state it is in when the event occurs.
The Same Press, Two Different Results
Imagine a button in a program that you press repeatedly. Sometimes pressing it opens a menu, and at other times the same press closes it. Nothing about the press itself has changed. What has changed is the program's memory of what it is currently doing.
Keep one question in mind as you read: if an event arrives, what information must the program consult before it decides how to respond? By the end of this article you should be able to answer that question for a small program and trace how one event produces different outcomes in different situations.
Tracing a Wall Light Through Its States
Consider a simple wall light controlled by a single button. The light has two states, on and off, and it has one kind of event: a button press. The state can be stored in a single boolean variable named lightIsOn. The response to a press depends on that state, so the same event leads to two different results.
What do you think happens?
The light is off. What happens when the button is pressed?
Reveal answer
The light turns on
The press is an event, and the machine responds to it based on its current state. Because the state is off, the machine follows the arrow that leads to the on state.
Now take the same button press while the light is on. The event is identical, but the state is not, so the machine follows the other arrow and turns the light off. Nothing in the button itself distinguishes the two cases. The state variable is what makes the difference.
What a State Machine Is
A state machine is something that has a state and can change state in response to events or inputs. Its response to an event depends on the state it is in when the event occurs.
Computer scientists use the name state machine for anything that remembers a condition of its own and changes that condition when something happens to it. The wall light fits this definition: it remembers whether it is on or off, and a button press changes that memory.
In an object-oriented program, the information stored in an object's instance variables is called the state of that object. The state is the collection of values that describe the object at a given moment, and those values determine how the object looks or behaves.
This produces two consequences. First, when one of the object's methods is called, the action the object takes can depend on its state, because the method can read the instance variables and decide what to do based on what it finds there. Second, the state can change, because the method can assign new values to the instance variables, so the next call may behave differently from the last one.
The state machine viewpoint is a planning tool as well as a description. If you can name an object's states and the events that move it between them, you have a clear plan for the methods that the class needs. Each event becomes a method, and each method's behavior is written as a function of the current state.
Event-Oriented Programs and Their State
The state machine viewpoint is especially useful in event-oriented programming, the style required by graphical user interfaces. In such a program, nothing runs from top to bottom in one fixed sequence. Instead, the program waits for events, such as key presses or mouse actions, and each event triggers a handler that runs in response.
Because a handler can run at any moment, the program must always know its own condition when an event arrives. The source suggests asking a set of design questions when building a GUI program: what information about state must be tracked, which events can change that state, how the response to a given event depends on the current state, whether the appearance of the interface should change to reflect a state change, and how the drawing code should take the state into account.
Reading the State Variables in KeyboardAndFocusDemo
The source uses a program called KeyboardAndFocusDemo to show these ideas. The state of that program is recorded in three instance variables named squareColor, squareLeft, and squareTop. Variables of this kind, which store the state of an object or program, are called state variables.
State variables do two jobs. The paintComponent() method reads them to decide how to draw the panel, so the appearance of the program follows its state. The two key-event-handling methods assign new values to them, so the state changes as the user types. Reading and writing the same variables is what connects the events to the display.
Finding Hidden State in a Game-Like Program
State is not always obvious. In a different game-like program, the source asks what counts as state at all. The positions of the boat, submarine, and bomb are state, and so is the fact that the bomb is sometimes falling and sometimes not. That falling-or-not difference is represented by a boolean variable, bomb.isFalling. Similarly, whether the submarine is moving left or right is a boolean, sub.isMovingLeft, and whether the submarine is exploding is another boolean, sub.isExploding.
An explosion lasts over several frames, so a single true or false value is not enough. The author uses an integer, sub.explosionFrameNumber, to count how many frames have been drawn since the explosion began. The value of that integer matters only while an explosion is in progress. A state can therefore need more than one variable, and some variables are meaningful only under particular conditions.
Same Event, Different Results in Code
The following class implements the wall light from earlier. The button press is a method, and the method's behavior depends on the instance variable lightIsOn. The code is an illustrative example written for this article, not taken from the source.
After the first buttonPressed() call, isOn() returns true. After the second call, isOn() returns false.lightIsOnis the state variable that records the light's conditionbuttonPressed()is the event handler, and it reads the state before deciding what to do- The assignments inside the if and else branches change the state for the next call
Trace the two calls. Both calls run the same method with the same event, but the first call finds lightIsOn as false and takes the else branch. The second call finds it as true and takes the if branch. The method body is the same both times; the only thing that differs is the value stored in the state variable.
Mistakes Beginners Make With State
Common mistake Assuming the event alone determines the response
What it looks likeBelieving that a button press always opens the menu because the press looks the same every time.
Why it failsThe source's central point is that the response to an event depends on the state the machine is in when the event occurs. The press is identical in both cases; the stored condition is what differs.
Do this insteadBefore deciding what an event does, identify the state variables the handler will read.
Common mistake Forcing every state into a single boolean
What it looks likeUsing only a true or false value to represent an explosion that lasts several frames.
Why it failsThe source shows that an explosion needs a counter, sub.explosionFrameNumber, because a single true or false value cannot record how many frames have passed.
Do this insteadAsk whether the state needs more than one variable, and recognize that some variables matter only under particular conditions.
Common mistake Planning an event-oriented program as one top-to-bottom sequence
Why it failsEvent-oriented programs wait for events and run handlers at arbitrary moments. The source says top-down, step-wise refinement does not apply to their overall design.
Do this insteadPlan a collection of states, the events that can occur, and the response for each combination.
Practice: Tracing a Light Through Presses
Using the WallLight class from earlier, start with the light off. Trace the state of lightIsOn and the output of isOn() after each of these calls in order: buttonPressed(), buttonPressed(), buttonPressed(). Then explain why the third press gives a different result from the first, even though the event is identical.
Hints
- Write down the value of
lightIsOnbefore each call, then apply the if or else branch. - The first press starts from the off state. The third press starts from whichever state the second press left behind.
Key Takeaways
- A state machine has a state and changes that state in response to events or inputs, and its response to an event depends on the state it is in when the event occurs.
- In an object, the state is held in instance variables, which methods read to decide what to do and assign to change what happens next.
- Event-oriented programs such as GUIs wait for events and run handlers at arbitrary moments, so they are organized around identifying state variables, the events that change them, and how responses depend on the current state.
- The same event can produce different results in different states, as the wall light shows: an identical button press turns the light on or off depending on
lightIsOn. - Some states need more than one variable, such as a boolean plus a frame counter, and state can be less obvious than it first appears.