Concepts / Writing Event Handlers in Java

Writing Event Handlers in Java

An event listener is an object that detects and reacts to events, and it must contain instance methods for the events it listens for.

  • Programming

A Click That Nothing Hears

Suppose a user clicks a window in a Java program and nothing visible happens. The click itself did not fail. It simply has no effect inside your program unless the program first detects that the click happened and then reacts to it. Detection is the first half of the job, and in Java that detection is handled by a special kind of object called an event listener.

This article follows one question from start to finish: what has to be true before a click on a particular component can cause your code to run? Along the way you will trace the path an event takes, write a listener class, register it, and learn how to diagnose a handler that never fires.

Why Detection Comes Before Reaction

Definition

An event listener is an object that detects and reacts to events. It must contain instance methods for the events it listens for.

The key idea is that your code cannot simply sit and wait for every possible click. Something has to be watching for mouse events and then running your reaction when one occurs. In Java, that watching object is the listener, and your reaction lives inside a method that belongs to it. The method's body is where your reaction goes.

Many events in Java are tied to a GUI component. When the user presses a mouse button, the component associated with that event is the one the user clicked on. A listener can only hear events for a component after it has been registered with that component. Without registration, the listener is simply an object sitting in memory, doing nothing.

Following One Click Through the Program

Before reading the mechanics, trace the path a single click takes. The diagram below shows the order of the steps. Notice that the final step, the call to your method, only happens along the route that registration created. The arrow from the component to the listener exists only because registration happened first.

Userpresses a mouse buttonComponentthe clicked componentListener objectregistered with thecomponentmousePressed methodyour reaction codemouse press on componentdelivers event to registered listenercalls the matching method
When the user clicks a component, which objects act in order before the handler's method runs?

Read the diagram as a chain with a gap in it. The user acts on the component. The component can only pass the event along if a listener has been registered with it. If no registration happened, the path stops at the component, and your method is never reached. That is the reason the rest of this article focuses on two things: writing the listener correctly, and registering it correctly.

What the MouseListener Contract Demands

The methods a mouse listener must have are listed in an interface named MouseListener. An interface, as this article uses the term, is only a list of instance methods. Writing that list down does not make any object react to anything. The list is a contract: any class that promises to follow it must supply a real definition for every method in it.

Definition

A class implements an interface when it does two things. First, the class is declared to implement the interface. Second, the class includes a definition for each instance method the interface specifies.

Anatomy of a Listener Class

The example below is a small listener class written for this article. It declares that it implements MouseListener in its class header, then defines each of the five methods the interface requires. The method mousePressed reads the position of the event through its evt parameter. The other four methods are present but empty, because the contract requires them even when a particular program has no reaction for that event.

java
Notes on the code
  • The implements clause on the class header is the declaration that makes this class a MouseListener.
  • Each method signature must match the interface, so each one takes a MouseEvent parameter named evt.
  • The body of mousePressed is where the reaction goes; here it only reads the event position.
  • The four empty methods satisfy the contract without doing anything.

When you read a listener class, check three things in order: the implements clause in the class header, the presence of every required method, and the body of the method where your reaction belongs. Missing the first check is the most common reason a handler silently fails, even when the methods look complete.

Registering the Listener on a Component

Registration is the step that connects a listener object to a component. Suppose a MouseListener object named mListener needs to hear the mouse events of a Component object named comp. You register it by calling addMouseListener on the component and passing the listener in as the argument.

java
Notes on the code
  • The first line creates the listener object from the class defined earlier.
  • The second line asks comp to hold the listener and notify it of mouse events.

The diagram below shows the relationship that these two lines create. The class describes the listener, the listener object is an instance of that class, and after addMouseListener runs, the component holds a reference to that object. Only then does the component have a listener to deliver events to.

ClickReporter classdeclares implementsMouseListenermListenerinstance of ClickReportercompa Component objectinstance created fromholds listener after addMouseListener
After addMouseListener is called, which object holds a reference to which?

Predicting the Result of a Missing Declaration

What do you think happens?

Suppose a class defines all five MouseListener methods with the correct signatures, but its header omits the implements MouseListener clause. An object of that class is passed to addMouseListener on a component. Does the handler run when the user clicks?

Reveal answer
Answer:

No. The program does not run the handler, and it does not compile.

The source is explicit that an object must belong to a class declared to implement the interface. Matching method names and bodies are not enough. A class without the implements declaration does not count as a MouseListener, so passing its object to addMouseListener is rejected before the program runs. Even if such a class could be passed in, it would still not be a listener for mouse events.

Why a Mouse Handler Never Runs

When a mouse handler does not fire, the cause is almost always one of two things: the listener class does not satisfy the contract, or the listener was never registered with the component that was clicked. The flowchart below sets out the order in which to check them. Start with the class declaration, because a missing implements clause makes the registration call fail regardless of what else is correct.

Class declaresimplementsMouseListener?All five methodsdefined?addMouseListenercalled on the clickedcomponent?Handler runs on mouseeventAdd the implementsclauseDefine the missingmethodsRegister the listenerwith the componentyesnoyesnoyesno
If a mouse handler never fires, which check comes first: the class declaration or the registration call?
  • Common mistake

    Writing all five methods without declaring the class as a MouseListener

    What it looks like
    public class ClickReporter { public void mousePressed(MouseEvent evt) { } ... }
    Why it fails

    The source states that writing the methods is not enough. The class must be declared to implement the interface, so the object does not count as a MouseListener.

    Do this instead

    Add implements MouseListener to the class header, as in the ClickReporter example.

  • Common mistake

    Assuming that an object with the right methods can be used as a listener

    Why it fails

    Two classes can have identical method names and bodies, and only the one carrying the implements declaration counts as a MouseListener.

    Do this instead

    Check the class header of the object you pass to addMouseListener, not only its method list.

  • Common mistake

    Creating a listener but never calling addMouseListener

    What it looks like
    ClickReporter mListener = new ClickReporter();  // no registration line follows
    Why it fails

    A listener hears a component's events only after it is registered. Without registration, the listener is just an object in memory.

    Do this instead

    Call comp.addMouseListener(mListener) on the component whose clicks you want to handle.

  • Common mistake

    Registering the listener on the wrong component

    Why it fails

    A listener hears only the events of the component it was registered with, so a listener on one component will not hear clicks on another.

    Do this instead

    Confirm that addMouseListener is called on the same component the user actually clicks.

Trying the Diagnosis Yourself

EASY

A student writes a class named ScoreTracker that declares implements MouseListener and defines all five required methods. The student creates a ScoreTracker object named tracker, but the program never calls addMouseListener. The student then clicks the window and wonders why the handler never runs. Using the flowchart, state which check fails first, what the fix is, and what you would verify after making it.

Hints
  • Start at the top of the flowchart and ask whether the class declares implements MouseListener.
  • Then check whether all required methods are defined, and finally whether the listener is registered with the clicked component.

Key Takeaways

  • A listener object detects and reacts to events, and it must contain instance methods for the events it listens for.
  • A mouse listener must implement the MouseListener interface: its class must be declared to implement it and must define every required method.
  • Writing the methods is not enough, because the class's declaration is what makes an object count as a MouseListener.
  • A listener hears a component's mouse events only after it is registered by calling addMouseListener on that component.
  • When a mouse handler never runs, check the class declaration first and then the registration call.