- What Is a Widget?
- Widget Hierarchy
- Events and Listeners
- Application Data
- Querying the Display
- Summary
1.3 Events and Listeners
An event is simply an indication that something interesting has happened. Events, such as "mouse down" and "key press," are issued when the user interacts with a widget through the mouse or keyboard. Event classes, used to represent the event, contain detailed information about what has happened. For example, when the user selects an item in a list, an event is created, capturing the fact that a "selection" occurred. The event is delivered to the application via a listener.
A listener is an instance of a class that implements one or more agreed-upon methods whose signatures are captured by an interface. Listener methods always take an instance of an event class as an argument. When something interesting occurs in a widget, the listener method is invoked with an appropriate event.
Most widgets track sequences of events and redraw based on them, sometimes issuing a higher-level event to indicate a state change. For example, a button may track "mouse press," "move," and "release" in order to issue a "selection" event when the mouse is released inside the button.
Some widget methods generate events. For example, when you call setFocus() on a control, "focus" events are issued. The rules governing which methods cause events and which do not are largely historical, based on the behavior of the Windows and X/Motif operating systems. In order to be able to write portable applications, these rules have been standardized across platforms.
SWT has two kinds of listeners: untyped and typed.
1.3.1 Untyped Listeners
Untyped listeners provide a simple, generic, low-level mechanism to handle any type of event. There are only two Java types involved: a single generic interface called Listener and a single event class called Event. Untyped listeners are added using the method addListener().
-
addListener(int event, Listener listener) Adds the listener to the collection of listeners that will be notified when an event of the given type occurs. When the event occurs in the widget, the listener is notified by calling its handleEvent() method.
The type argument specifies the event you are interested in receiving. To help distinguish them from all the other SWT constants, type arguments are mixed upper- and lowercase by convention. All other constants in SWT are uppercase. The following code fragment uses addListener() to add a listener for SWT.Dispose.
widget.addListener(SWT.Dispose, new Listener() { public void handleEvent(Event event) { // widget was disposed } });
When multiple listeners are added, they are called in the order they were added. This gives the first listener the opportunity to process the event and possibly filter the data before the remaining listeners are notified (see Event Filters in the chapter Display). Adding the same instance of a listener multiple times is supported, causing it to be invoked once for each time it was added. [12]
It is also possible to remove listeners using removeListener().
-
removeListener(int type, Listener listener) Removes the listener from the collection of listeners that will be notified when an event of the given type occurs.
In order for a listener to be removed, you must supply the exact instance of the listener that was added. If the same listener instance is added multiple times, it must be removed the same number of times it was added to remove it from the listener collection completely.
Generally speaking, removing listeners is unnecessary. Listeners are garbage collected when a control is disposed of, provided that there are no other references to the listener in the application program.
Application code can send events using notifyListeners().
-
notifyListeners(int type, Event event) Sets the type of the event to the given type and calls Listener.handleEvent() for each listener in the collection of listeners.
An important point to note is that notifyListeners() does not cause the corresponding operating system event to occur. For example, calling notifyListeners() with SWT.MouseDown on a button will not cause the button to appear to be pressed. Also, notifyListeners() does not ensure that the appropriate fields for the event have been correctly initialized for the given type of event. You can use notifyListeners() to invoke listeners that you define but it is probably easier simply to put the code in a helper method.
Class Event has a number of fields that are applicable only for a subset of the event types. These fields are discussed as each type of event is described. Table 1.1 shows the fields that are valid for all event types.
Table 1.1. Public Fields in Class Event That Are Applicable to All Untyped Events
Field |
Description |
---|---|
display |
the Display on which the event occurred |
widget |
the Widget that issued the event |
type |
the event type |
Table 1.2 shows the type constants that describe all of the untyped events that SWT implements. More details are available in the descriptions of the individual widgets.
Table 1.2. Untyped Events
Event Type Constant |
Description |
---|---|
SWT.KeyDown |
A key was pressed |
SWT.KeyUp |
A key was released |
SWT.MouseDown |
A mouse button was pressed |
SWT.MouseUp |
A mouse button was released |
SWT.MouseMove |
The mouse was moved |
SWT.MouseEnter |
The mouse entered the client area of the control |
SWT.MouseHover |
The mouse lingered over a control |
SWT.MouseExit |
The mouse exited the client area of the control |
SWT.MouseDoubleClick |
A mouse button was pressed twice |
SWT.Paint |
A control was asked to draw |
SWT.Move |
The position of the control was changed |
SWT.Resize |
The size of the client area of the control changed |
SWT.Dispose |
The widget was disposed |
SWT.Selection |
A selection occurred in the widget |
SWT.DefaultSelection |
The default selection occurred in the widget |
SWT.FocusIn |
Keyboard focus was given to the control |
SWT.FocusOut |
The control lost keyboard focus |
SWT.Expand |
A tree item was expanded |
SWT.Collapse |
A tree item was collapsed |
SWT.Iconify |
The shell was minimized |
SWT.Deiconify |
The shell is no longer minimized |
SWT.Close |
The shell is being closed |
SWT.Show |
The widget is becoming visible |
SWT.Hide |
The widget is being hidden |
SWT.Modify |
Text has changed in the control |
SWT.Verify |
Text is to be validated in the control |
SWT.Activate |
The control is being activated |
SWT.Deactivate |
The control is being deactivated |
SWT.Help |
The user requested help for the widget |
SWT.DragDetect |
A drag-and-drop user action occurred |
SWT.MenuDetect |
The user requested a context menu |
SWT.Arm |
The menu item is drawn in the armed state |
SWT.Traverse |
A keyboard navigation event occurred |
SWT.HardKeyDown |
A hardware button was pressed (handhelds) |
SWT.HardKeyUp |
A hardware button was released (handhelds) |
If you are writing your own widget, you may want to use notifyListeners() to support the built-in untyped events in SWT since this allows your widget to behave like the native widgets with respect to the mapping between untyped and typed listeners. However, for events that are particular to your widget, you will also typically implement typed listeners.
1.3.2 Typed Listeners
A typed listener follows the standard JavaBeans listener pattern. Typed listeners and their corresponding event classes are found in the package org.eclipse.swt.events. For example, to listen for a dispose event on a widget, application code would use addDisposeListener().
-
addDisposeListener(DisposeListener listener) Adds the listener to the collection of listeners that will be notified when a widget is disposed. When the widget is disposed, the listener is notified by calling its widgetDisposed() method.
The following code fragment listens for a dispose event on a widget.
widget.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent event) { // widget was disposed } });
DisposeListener is an interface. If there is more than one method defined by the listener, SWT provides an adapter class that contains no-op implementations of the methods. [13] For example, the interface SelectionListener has two methods, widgetSelected() and widgetDefaultSelected(), that take SelectionEvents as arguments. As a result, the class SelectionAdapter is provided that provides no-op implementations for each method.
Typed listeners are removed using the corresponding remove method for the listener. For example, a listener for a dispose event is removed using removeDisposeListener().
-
removeDisposeListener(DisposeListener listener) Removes the listener from the collection of listeners that will be notified when the widget is disposed.
Table 1.3 shows all of the typed events that SWT implements. These are described in more detail in the descriptions of the individual widgets.
Table 1.3. Typed Events
Event |
Listener |
Methods |
Untyped Event |
---|---|---|---|
ArmEvent |
ArmListener |
widgetArmed(ArmEvent) |
SWT.Arm |
ControlEvent |
ControlListener (and ControlAdapter) |
controlMoved(ControlEvent) controlResized(ControlEvent) |
SWT.Move SWT.Resize |
DisposeEvent |
DisposeListener |
widgetDisposed(DisposeEvent) |
SWT.Dispose |
FocusEvent |
FocusListener (and FocusAdapter) |
focusGained(FocusEvent) focusLost(FocusEvent) |
SWT.FocusIn SWT.FocusOut |
HelpEvent |
HelpListener |
helpRequested(HelpEvent) |
SWT.Help |
KeyEvent |
KeyListener (and KeyAdapter) |
keyPressed(KeyEvent) keyReleased(KeyEvent) |
SWT.KeyPressed SWT.KeyReleased |
MenuEvent |
MenuListener (and MenuAdapter) |
menuHidden(MenuEvent) menuShown(MenuEvent) |
SWT.Hide SWT.Show |
ModifyEvent |
ModifyListener |
modifyText(ModifyEvent) |
SWT.Modify |
MouseEvent |
MouseListener (and MouseAdapter) |
mouseDoubleClick(MouseEvent) mouseDown(MouseEvent) mouseUp(MouseEvent) |
SWT.MouseDoubleClick SWT.MouseDown SWT.MouseUp |
MouseEvent |
MouseMoveListener |
mouseMove(MouseEvent) |
SWT.MouseMove |
MouseEvent |
MouseTrackListener (and MouseTrackAdapter) |
mouseEnter(MouseEvent) mouseExit(MouseEvent) mouseHover(MouseEvent) |
SWT.MouseEnter SWT.MouseExit SWT.MouseHover |
PaintEvent |
PaintListener |
paintControl(PaintEvent) |
SWT.Paint |
SelectionEvent |
SelectionListener (and SelectionAdapter) |
widgetDefaultSelected(SelectionEvent) widgetSelected(SelectionEvent) |
SWT.DefaultSelection SWT.Selection |
ShellEvent |
ShellListener (and ShellAdapter) |
shellActivated(ShellEvent) shellClosed(ShellEvent) shellDeactivated(ShellEvent) shellDeiconified(ShellEvent) shellIconified(ShellEvent) |
SWT.Activate SWT.Close SWT.Deactivate SWT.Deiconify SWT.Iconify |
TraverseEvent |
TraverseListener |
keyTraversed(TraverseEvent) |
SWT.Traverse |
TreeEvent |
TreeListener (and TreeAdapter) |
treeCollapsed(TreeEvent) treeExpanded(TreeEvent) |
SWT.Collapse SWT.Expand |
VerifyEvent |
VerifyListener |
verifyText(VerifyEvent) |
SWT.Verify |
1.3.3 Why Are There Two Listener Mechanisms?
In early versions of SWT, there were only untyped listeners. After considerable discussion between the Eclipse implementers, the SWT user community, and the developers, it was decided to include a more "JavaBeans-like" listener mechanism. It was felt that this would ease the transition to SWT for developers who were already familiar with AWT/Swing. The untyped listeners remain as the implementation mechanism for event handling in SWT. The typed listeners are defined in terms of them.
We recommend that SWT applications always be implemented in terms of the typed listener mechanism, although this is largely based on the more familiar pattern they represent. Because of the simplicity of the untyped mechanism and our closeness to the implementation, we tend to use it in many of the small examples we write. To see a clear example of the typed mechanism in action, take a look at the FileExplorer example in the Applications part of the book.
Effectively, the trade-off between the two listener models is one of space versus ease of use and adherence to a standard pattern. Using untyped listeners, it is possible to minimize the number of classes and methods used to listen for events. The same listener can be used to listen for many different event types. For example, the following code fragment listens for dispose as well as mouse events.
Listener listener = new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.Dispose: break; case SWT.MouseDown: break; case SWT.MouseUp: break; case SWT.MouseMove: break; } System.out.println("Something happened."); } }; shell.addListener(SWT.Dispose, listener); shell.addListener(SWT.MouseDown, listener); shell.addListener(SWT.MouseUp, listener); shell.addListener(SWT.MouseMove, listener);
In practice, unless space usage is the overwhelming constraint, we expect that most programmers will use the typed listener mechanism. [14] Note that typed events have very specific listener APIs, whereas the untyped events have only handleEvent(). Using untyped events can lead to switch logic that is more complicated. Refer to Table 1.3 to see the mapping between typed and untyped events.
1.3.4 Widget Events
SWT.Dispose (DisposeEvent)
Table 1.4 shows the dispose events that are provided by SWT.
Table 1.4. Dispose Events
Untyped Event |
Description |
|
---|---|---|
SWT.Dispose |
The widget was disposed |
|
Typed Event |
Listener |
Methods |
DisposeEvent |
DisposeListener |
widgetDisposed(DisposeEvent) |
The SWT.Dispose event (typed event DisposeEvent) is sent when a widget is disposed of. Dispose events contain meaningful values in only the display, widget, and type fields.