Monday, December 17, 2007

Glimmer Listens

[updated as per Chauk-Mean's suggestion to have listener syntax follow the Ruby style convention]

In Glimmering Philosophy, I went over Glimmer's design principles, and the basics of how it works to simplify SWT development. Here, I will explain how to attach event listeners to SWT widgets using Glimmer's simplified syntax.

First, let's go over how to do so in Java. We usually call an add***Listener method on the widget and pass it a listener implementation, which is invoked whenever the widget encounters an event of a particular type.

For example, in order to have the user login everytime a Login button is pushed, we can write Java code like this:

Button button = new Button(composite, SWT.PUSH);
button.setText("Login");
button.addSelectionListener(new SelectionAdapter() {
  public void widgetSelected(SelectionEvent e) {
    user.login();
  }
});

The listener implementation is an anonymous class extending SelectionAdapter, which implements the expected SelectionListener interface:

public interface SelectionListener extends SWTEventListener {
  public void widgetSelected(SelectionEvent e);
  public void widgetDefaultSelected(SelectionEvent e);
}

Once the Login Button is pushed, a SelectionEvent is generated and passed to the widgetSelected method, which is invoked on the SelectionListener implemention.

If you notice, widgetDefaultSelected was not implemented in this case as we were not interested in that event. We placed our logic in a code block representing the widgetSelected implementation instead, so this is the minimum information needed to accomplish the task. Based on Glimmer's Philosophy, that is all we need to attach a listener, so with Glimmer's syntax, here is how to attach a listener:

button {
  text "Login"
  on_widget_selected { user.login }
}

By declaring on_widget_selected, we indicate that we would like to implement the widgetSelected method, which exists only on one of the listeners supported by the Button widget. Based on that minimum amount of information needed, Glimmer automatically figures out which listener to implement (SelectionListener), plugs our code block { user.login } into an anonymous implementation of it, and then attaches the listener to the widget using the correct add***Listener method (addSelectionListener).

Glimmer's syntax bypasses the need to implement an interface as it only needs a code block and the name of the event we care about. Here is another example:

text {
  on_focus_lost { user.save }
}

This saves the user object whenever the text widget loses focus (e.g. tabbing out)

The listener that was implemented automatically by Glimmer is FocusListener:

public interface FocusListener extends SWTEventListener {
  public void focusGained(FocusEvent e);
  public void focusLost(FocusEvent e);
}

Note that the block of code that follows the listener declaration in Glimmer is a standard Ruby block, meaning it can optionally receive parameters if need be. In the case of listeners, the only parameter we sometimes care about is the event object. Here is an example that benefits from the optional event parameter:

text {
  on_verify_text {|verify_event| print verify_event.text }
}

Glimmer's concise syntax requires us to enter only the minimum information needed to attach listeners, not requiring us to include the event parameter unless it truly becomes part of the minimum information needed to accomplish the task as demonstrated in the last example.

In my next Glimmer post, I will introduce data-binding support in Glimmer, which easily enables two-way synchronization between SWT widgets and domain model properties.

4 comments:

Chauk-Mean said...

Hi Andy,

Glimmer is great but I have some comments :
- your listener methods does not follow the Ruby style convention :
onWidgetSelected => on_widget_selected
- an easier way to use SWT with JRuby than what you suggest in your README, is to download the "SWT binary and source" archive from the Eclipse site and just extract the swt.jar into the JRUBY lib directory.

Chauk-Mean.

Phil said...

Andy -

How much inspiration for Glimmer did you take from JavaFX? There seem to be a lot of common elements between the two. I'm interested to see how this project progresses.

BTW, attended your practical design patterns session at EW; it was fun.

-Phil

Andy Maleh said...

- your listener methods does not follow the Ruby style convention :
onWidgetSelected => on_widget_selected


Thanks for catching that chauk-mean. Done. As per your suggestion I updated the listener syntax in Glimmer to adhere to the Ruby style convention (e.g. on_widget_selected.)

- an easier way to use SWT with JRuby than what you suggest in your README, is to download the "SWT binary and source" archive from the Eclipse site and just extract the swt.jar into the JRUBY lib directory.

Thanks for providing this valuable hint. I added it to the README.

This is the kind of feedback I appreciate so much in open-source communities. Thanks again chauk-mean. Keep it coming!

Andy Maleh said...

I wanted to build something like Glimmer in Ruby since before I heard of JavaFX Script. However, learning about JavaFX Script definitely helped inspire some of the ideas I later had for Glimmer.

Glad to know you had fun during my Practical Design Patterns presentation at EclipseWorld.