Desktop Java

SWT Mouse Click Implementation

Doing a bit of SWT custom widget development lately, I stumbled across the question why is there no such thing as a default SWT mouse click listener? As this subject raises once in a while, I thought writing a word or two about the rational ground behind – and how to implement mouse clicks in general – would not hurt.

SWT Mouse Click

Event driven widget toolkits usually distinguish between low-level and semantic events. A low-level event represents window system occurrences or low level input. The mouse and keyboard inputs belong basically to this group.

Semantic events in turn are the result of control specific user interaction and might be composed of one or more low-level events. A button-click for example could be specified as a mouse-down followed by a mouse-up without the mouse leaving the bounds of the control.

The point of the matter is the control specific user interaction. An image-click might be specified as a mouse-down followed by a mouse-up without leaving the bounds of particular regions of the image. Which makes a small but mighty difference.

The semantic event type SWT.Selection e.g. corresponds to the button-click specification given above for the org.eclipse.swt.widgets.Button control. But its composition is quite different on org.eclipse.swt.widgets.Slider. The latter behaves rather like the image-click definition:

mouse-click-on-slider

It is obvious that nobody would like to add particular listeners for mouse-click events on each of the control’s regions. It is much more comfortable to have a semantic abstraction based on those low-level events that notifies observers about the crucial point or interest1.

Button Click for Custom Widgets

So how can a button-click event implementation look like on a (sub-)component of a custom SWT widget? Consider for example a Composite comprised of a few labels and one of those – for whatever reason – should serve as an action trigger.

The click behavior could be accomplished with a little action wrapper working on top of the typed event abstraction of SWT. It may implement/extend org.eclipse.swt.events.MouseListener/-MouseAdapter and can be registered at controls to serve as a button-click listener:

static class ClickBehavior extends MouseAdapter {

  private final Runnable action;

  ClickBehavior( Runnable action ) {
    this.action = action;
  }

  @Override
  public void mouseDown( MouseEvent event ) {
    // TODO: decent implementation
  }

  @Override
  public void mouseUp( MouseEvent event ) {
    // TODO: decent implementation
  }
}

As you can see the class ClickBehavior wraps a Runnable which should be triggered by a click on the observed control. To do so the first step is to verify that a left-mouse-button-down has occured and flag the observer to be trigger ready. A simple mouseDown implementation might look like this:

public static final int LEFT_BUTTON = 1;
[...]
public void mouseDown( MouseEvent event ) {
  if( event.button == LEFT_BUTTON ) {
    armed = true;
  }
}

The second step is to check whether a subsequent mouseUp event has occured within the bounds of the monitored control. If so (and armed) the semantic condition has been fulfilled and the action can be triggered 2:

public void mouseUp( MouseEvent event ) {
  if( armed && inRange( event ) ) {
    action.run();
  }
  armed = false;
}

static boolean inRange( MouseEvent event ) {
  Point size
    = ( ( Control )event.widget ).getSize();
  return    event.x >= 0 
         && event.x <= size.x
         && event.y >= 0
         && event.y <= size.y;
}

This implementation is sufficient to be able to handle a ‘button-click’ event on e.g. a org.eclipse.widgets.Label as shown by the following snippet:

final Shell shell = [...];
Label label = new Label( shell, SWT.NONE );
label.setText( "Click me!" );
label.addMouseListener(
  new ClickBehavior( new Runnable() {

  @Override
  public void run() {
    MessageBox box = new MessageBox( shell );
    box.setMessage( "Label was clicked." );
    box.setText( "Message" );
    box.open();
  }

} ) );

And voilà, this is how it looks like at runtime:

label-click

Wrap Up

As explained above there are good reasons for SWT to omit a general purpose mouse click implementation. And the given example showed how to implement a simple button-click semantic for custom widgets. However there is still more to consider. Widgets often react on mouse down visually to indicate that they are trigger-ready for example.

Because of this custom widget code gets quickly blown up and tend to blur the various event related reponsibilities. For a clean separation of the event-semantic from the visual-effect code, I usually extract the first one in a little helper class. I even have a general purpose version for button-click events called ButtonClick, which is part of the SWT utility feature of the Xiliary P2 repository.

In case all this mouse click related content raised a desire for some practical application of mouse clicking: how about using the social buttons below to share the knowledge?
 

  1. The attentive reader may have recognized that I omit the slider’s drag region which also adds to the selection semantic. This is because it does not match the click behaviour and would go beyond the scope of this discussion.
  2. It might be noteworthy to mention that a real world implementation should ensure that the armed flag gets also reset in case a runtime exception is thrown during action.run().
Reference: SWT Mouse Click Implementation from our JCG partner Frank Appel at the Code Affine blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button