Concepts / Event Listeners and Registration

Event Listeners and Registration

Mouse motion events are handled through the MouseMotionListener interface, which declares mouseDragged and mouseMoved.

  • Programming

Why a Program Listens to the Mouse

Every time the mouse moves, the computer produces mouse motion events. The operating system uses those events to redraw the pointer on screen, but a program can also observe the same events and react to them. The usual reason is to let the user drag something: pick up an object with the mouse, move it, and let go. This article follows how a program hooks into those motion events, which methods receive them, and how to trace the flow of a drag through the code.

Keep one idea in mind as you read: the program does not decide which kind of motion event it is receiving. The system makes that decision from the state of the mouse buttons at the moment the pointer moves. Your job as the programmer is to write handlers for each situation and to connect those handlers to the component you care about.

Two Handlers for One Movement

What do you think happens?

The user holds the left mouse button and moves the pointer across a window. Which handler does the program receive?

  • mouseMoved, because the pointer is moving

  • mouseDragged, because a button is held down while the pointer moves

  • Both handlers, one after the other

Reveal answer
Answer:

mouseDragged, because a button is held down while the pointer moves

The deciding factor is whether any mouse button is held down while the pointer moves. A button held down produces a call to mouseDragged. This is the case the drag-and-drop pattern depends on.

The two cases are handled by two separate methods of one interface, MouseMotionListener. The interface declares mouseDragged and mouseMoved. If a mouse button is down when the pointer moves, the program receives a call to mouseDragged. If no button is down, the program receives a call to mouseMoved instead. The prediction you just made depends on noticing the button state, and that is the single fact that separates the two handlers.

Choosing Between mouseDragged and mouseMoved

Pointer movesAny button held down?mouseDragged(evt)button is downmouseMoved(evt)no button is downsystem checks button stateyesno
When the mouse moves, what decides whether mouseDragged or mouseMoved is called, and what is checked first?

The diagram shows the order of checks. The first and only deciding question is whether a button is held down at the moment of movement. The program does not run the check itself. By the time your handler is called, the system has already chosen the method that matches the button state.

A drag is not a single event. While the user keeps moving the mouse with a button held, the matching method is called once for every motion event. One drag therefore produces a long run of calls to mouseDragged. A handler must be written to run many times in quick succession, and it should not assume that one call equals one complete drag.

AspectmouseDraggedmouseMoved
When it is calledThe mouse moves while a button is pressedThe mouse moves with no button down
Typical useLetting the user drag something across the screenReacting to the pointer when no button is pressed
How often it runs during one gestureOnce per motion event, so many times during a dragOnce per motion event while the pointer moves without a button
Who chooses itThe system, from the button stateThe system, from the button state

Comparing the two methods of MouseMotionListener

Implementing MouseMotionListener

Implementing the interface means writing a class that declares it and supplies both of its methods. Both methods take one parameter of type MouseEvent. That object carries the x and y coordinates of the pointer at the moment the event occurred. A class that implements the interface must provide both methods, even if it only cares about dragging. The parameter name evt is a convention. Inside a handler, you read the coordinates from that event object to learn where the pointer is during the drag.

java
Notes on the code
  • Both methods take a MouseEvent parameter named evt
  • getX() and getY() read the pointer location from the event object
  • mouseMoved must still be present because the interface declares it

Registering the Listener on a Component

Implementing the interface is only half of the job. The listener object must also be connected to the component whose mouse motion it should hear. That connection is made by calling the component's addMouseMotionListener() method and passing in the listener object. Until this registration happens, the listener receives no motion events from that component. Once registered, it receives mouseDragged and mouseMoved events associated with that component, and a listener registered on one component does not hear motion over another.

Componentthe area the mouse movesoverMouseEventcarries x and y of thepointermouseDragged ormouseMovedcalled by the systemListener objectimplementsMouseMotionListeneraddMouseMotionListener()producesdelivered as parametermethod runs
After registration, how are the component, the event, and the listener object connected, and which object actually calls the handler?

The diagram shows that the component produces the motion events, but the listener is the object whose method runs. The system calls the handler on the listener, passing in a MouseEvent for the current movement. Your program does not call mouseDragged or mouseMoved directly during a drag.

java
Notes on the code
  • The class implements MouseMotionListener
  • addMouseMotionListener(this) registers this window as the listener
  • Without that call, neither handler receives motion events from this window

Tracing a Drag from Start to Finish

Worked example

Tracing the handler calls for one gesture

The DragWindow above is running. The user presses the left button, moves the pointer through three positions while holding the button, releases the button, and then moves the pointer through two more positions. Which handler is called for each motion, and how many times in total?

  1. 1
    Press the button

    Pressing a button is a mouse event handled by the MouseListener interface, not by MouseMotionListener. It does not call mouseDragged or mouseMoved, because no motion has happened yet.

  2. 2
    Move three times with the button held

    Each motion event occurs while a button is down, so the system calls mouseDragged once per motion event. That is three calls, and each one receives the pointer coordinates at that moment.

  3. 3
    Release the button

    Releasing the button is also not a motion event for this interface. No motion handler runs at the release itself.

  4. 4
    Move two times with no button down

    Now no button is down, so the system calls mouseMoved for each motion event. That is two calls, and mouseDragged is not called for them.

  5. 5
    Total the calls

    mouseDragged runs three times and mouseMoved runs two times, for five motion handler calls in all.

Result

mouseDragged is called 3 times during the held-button movement, and mouseMoved is called 2 times after release. The button-state check decides every call.

UserMouseListener1. press and hold button2. move: mouseDragged3. move: mouseDragged4. move: mouseDragged5. release button6. move: mouseMoved7. move: mouseMoved
For each mouse action in order, which handler fires, and at what step does a predicted handler differ from the actual one?

The sequence view makes the divergence point easy to find. A common wrong prediction is that every movement in the gesture calls mouseMoved, or that mouseDragged keeps running after the release. Locate the first step where your prediction and the actual handler differ. In the sequence above, that step is usually a move right after the release, or a move made while the button was still held.

Mistakes When Handling Mouse Motion

  • Common mistake

    Expecting one call to mouseDragged per drag

    What it looks like

    Assuming a handler runs once when the user starts dragging and again when they stop.

    Why it fails

    While the user keeps moving with a button held, the matching method is called once for each motion event, which produces a long run of calls.

    Do this instead

    Write the drag handler to run repeatedly and to tolerate that frequency.

  • Common mistake

    Implementing the interface but leaving out one method

    What it looks like

    A class declares implements MouseMotionListener and supplies only mouseDragged.

    Why it fails

    The interface declares both mouseDragged and mouseMoved, and a class that implements it must supply both, even if it only cares about dragging.

    Do this instead

    Provide mouseMoved too, even as an empty method.

  • Common mistake

    Forgetting to register the listener

    What it looks like

    The class implements the interface correctly, but addMouseMotionListener() is never called.

    Why it fails

    A listener must be registered with a component's addMouseMotionListener() method before it receives any motion events from that component.

    Do this instead

    Call addMouseMotionListener() on the component, passing the listener object.

  • Common mistake

    Registering on the wrong component

    What it looks like

    Registration is done on a panel, but the user is moving the mouse over a different window.

    Why it fails

    A listener registered on one component does not hear motion over another.

    Do this instead

    Register the listener on the component whose motion you want to observe.

  • Common mistake

    Treating mouseMoved as the handler for drags, when the button state decides the method

Keeping Motion Handling Separate

Mouse motion methods live in their own interface, separate from the other mouse events. The reason is volume. Motion events are generated continuously whenever the pointer moves, so the number is very large. A program that only cares about clicks would be inefficient if it were forced to hear every movement. Keeping the motion methods in MouseMotionListener lets a program listen for MouseListener events without automatically receiving every motion event as well.

In practice, a listener that handles dragging often also implements MouseListener so it can respond to the other mouse events. The two interfaces remain separate in the language, but a single object can implement both when its job requires it. The guiding rule is that a listener should implement only the interfaces its job needs.

Practice: Trace the Handler Calls

MEDIUM

A DragWindow is registered with addMouseMotionListener(this). The user does the following in order: holds the button and moves four times, releases the button, moves two times, then presses again and moves once while holding. Write down which handler runs for each motion, and identify the first step where you would be most likely to predict wrongly.

Hints
  • Ask first whether a button is down at the moment of each movement, not whether the user pressed a button at some earlier time.
  • Pressing and releasing are not motion events for this interface, so they do not themselves trigger mouseDragged or mouseMoved.
  • The step most often predicted wrongly is the first movement after a release.
EASY

Suppose the DragWindow registration line were removed, but the class still implements MouseMotionListener and has both methods. Predict whether a drag over the window would call mouseDragged, and explain which fact from the registration section decides your answer.

Hints
  • Consider what the registration does for the component, not what the class declares.
  • The source says a listener must be registered before it receives any motion events from that component.

Key Takeaways

  • The system chooses between mouseDragged and mouseMoved based on whether a mouse button is held down when the pointer moves, and the program does not make that choice itself.
  • A single drag produces many calls to mouseDragged, one for each motion event, so drag handlers must be written to run repeatedly.
  • A class implementing MouseMotionListener must supply both mouseDragged and mouseMoved, and each receives a MouseEvent carrying the pointer coordinates.
  • A listener only receives motion events after it is registered with addMouseMotionListener() on the specific component, and it hears nothing from other components.
  • When tracing a sequence of mouse actions, find the first step where the predicted handler differs from the actual one, since that divergence points to a button-state misjudgment or a missing registration.