-
Notifications
You must be signed in to change notification settings - Fork 2
tutorial3
This is the third part of the VLDocking Framework tutorial for Java Swing applications.
In this lesson, you will learn about the docking event model and about writing event listeners.
The VLDocking Framework works with an event model : to be notified of changes, you have to add some listeners to the DockingDesktop, not to override specialized methods.
This way, there should be no need for you to subclass DockingDesktop, and you will reduce the coupling between listening components and their source.
This package contains events and listeners class, so don't forget to import it in your listener classes.
There are 2 kinds of events, dedicated to different purposes :
-
Events that are triggered when an action is performed on a Dockable (or just before) :
These events are usefull to provide feedback on dockable closing (the "are you sure ?" message) or to keep track of components visibility and position.
-
DockEvent
events are triggered during the drag and drop process of a dockable component. These lower-level events are used to perform docking and are of no use for normal application programming (but they are the key to the framework extension).
Note : As of VLDocking 2.1, a new set of classes has been introduced to improve the event model (they are called DockingAction Events). The DockableStateChange classes can still be used if you are only interested in high-level changes *
There are two types of DockableStateChange events :
-
Events triggered before a state change are instances of
DockableStateWillChangeEvent
. Those are vetoable, meaning you can cancel the state change process if a condition of your own is not fulfilled. -
Notification events, triggered after a state change are instances of
DockableStateChangeEvent
.
To be notified before a state change occur, you have to implement the
DockableStateWillChangeListener
interface on an existing class, or
as on the following example, on an anonymous class :
DockingDesktop desk = ...
DockableStateWillChangeListener listener = new DockableStateWillChangeListener() {
public void dockableStateWillChange(DockableStateWillChangeEvent event) {
// event processing
}
};
desk.addDockableStateWillChangeListener(listener);
The DockableStateWillChangeEvent object contains fields that inform you on the dockable which is changing, on what its current state is, and on what its next state will be if not vetoed.
Look at this example, where we cancel a CLOSE operation if it occurs on the editorPanel dockable.
DockingDesktop desk = ...
DockableStateWillChangeListener listener = new DockableStateWillChangeListener() {
public void dockableStateWillChange(DockableStateWillChangeEvent event) {
DockableState current = event.getCurrentState();
if (current.getDockable() == editorPanel) {
if (event.getFutureState().isClosed()) {
// we are facing a closing of the editorPanel
event.cancel(); // refuse it, always
}
}
}
};
desk.addDockableStateWillChangeListener(listener);
These events are triggered after the state change, so you cannot veto them.
You listen to them by implementing a DockableStateChangeListener
which is
different from DockableState*Will*ChangeListener
.
They are usefull to keep track of the state of your dockables, especially in the following situations :
- You want to "dispose" your dockable and GC its resources : a closed dockable is just "not visible", but still referenced by the desktop (it might show up again). As there is currently no "{{{setDefaultCloseOperation()}}}" on the dockkey you have to properly code the removal of the dockable after it is closed :
DockingDesktop desk = ...
DockableStateChangeListener listener = new DockableStateChangeListener() {
public void dockableStateChange(DockableStateChangeEvent event) {
DockableState newState = event.getNewState();
if (newState.isClosed()) {
// the dockable has been closed
desk.unregisterDockable(newState.getDockable()); // forget about it !
}
}
};
desk.addDockableStateChangeListener(listener);
-
You want to know when a dockable becomes visible/not visible to allocate resources only when needed (expecially if the dockable is a Heavyweight AWT component).
-
You want to show a dialog to let the user select the dockables to show and those to close, by a click on a checkbox, and want to update the visible dockables list dynamically .
But keep it mind that there is already a customizable dialog included in the
framework : com.vlsolutions.swing.docking.DockingSelectorDialog
.
As of VLDocking 2.1, it is possible to keep track of actions performed on dockables. Most of these actions are vetoable, and this method is for example used to anchor dockable (by rejecting actions that would break the anchoring).
Every action that can be performed on a dockable (or a set of dockables) has its corresponding class in the event package.
Here are the main classes introduced :
Class | Usage |
---|---|
DockingActionAddDockableEvent | Event produced when adding the first dockable to a top-level container |
DockingActionCloseEvent | Produced when the close button is used on a dockable |
DockingActionCreateTabEvent | Produced when a dockable is added as a new tab |
DockingActionSimpleStageChangeEvent | Produced by different action that don't involve parameters, like 'detach', 'auto-hide' |
DockingActionSplitComponentEvent | Produced when a dockable is moved to another split position (drag and drop) |
DockingActionSplitDockableEvent | Produced when a dockable is added besides another one (split() API call) |
To listen to these events, you just have to register a DockingActionListener to your
DockingDesktop with the addDockingActionListener()
method.
DockingActionListener defines two methods :
public boolean acceptDockingAction(DockingActionEvent event)
and
public void dockingActionPerformed(DockingActionEvent event)
The accept method is vetoable (returns a boolean) and is invoked before the action is performed, to give you a chance to react to it before.
The dockingActionPerformed method is called after the action, and gives you a means to track the dockable state or position change
Some application need to know when a dockable is selected (for example, to show a different set of icons on their toolbar). By selection, we mean "the title bar is highlighted" of, if you prefer, a component inside the dockable has obtained the keyboard focus (which is exactly the same... as the framework tracks focus events to highlight title bars).
So here are the dedicated events and listeners :
Class | Description |
---|---|
DockableSelectionEvent | Describes the dockable that has just been selected |
DockableSelectionListener | Listener invoked on selection change |
To add a listener to the desktop, just use the followind methods :
Method | Description |
---|---|
DockingDesktop.addDockableSelectionListener(DockableSelectionListener listener) | Adds a listener for selection changes |
DockingDesktop.addDockableSelectionListener(DockableSelectionListener listener) | Removes the listener |
Note : There is also another way to know which dockable is currently selected : just ask the desktop :
DockingDesktop desk = ...
Dockable selected = desk.getSelectedDockable(); // may return null
This section is for API extenders : developpers that want to add docking features to the API.
If you (most probably) are not of that kind, you can skip the end of the lesson and go to the next one.
There are 3 classes of events : one ancestor class DockEvent
,
and two specialized subclasses DockDragEvent
and DockDropEvent
.
Those events are related to two other classes :
-
DockableDragSource
: an interface implemented by a UI component used to drag a dockable (for example, the default title bar of aSingleDockableContainer
is a DockableDragSource).
DockableDragSource contains methods to get the associated Dockable
and to be notified of a drag gesture start.
-
DockDropReceiver
: an inteface implemented by a UI component used to drop a dockable (for example, the whole content of aSingleDockableContainer
is a DockDropReceiver).
A DockDropReceiver is responsible for accepting (and processing) a "drop" of a dockable.
The DockEvent
class contains informations about the DockableDragSource
of the event, and the MouseEvent associated to the gesture (pointer coordinates are converted
to be used in the target component coordinates system).
The DockDragEvent
event is a subclass of DockEvent
which
is transmitted to DockDropReceiver
during a drag gesture.
When the drag gesture begins over a DockableDragSource
, the DockingDesktop
switches to "Drag and Dock" mode :
-
When mouse pointer is over a component implementing DockDropReceiver, a DockDragEvent is triggered and transmitted to this receiver. The receiver can
acceptDrag()
,rejectDrag()
, ordelegateDrag()
(tell the DockingDesktop to look up in the containment hierarchy for another receiver). -
To accept the drag, the DockDropReceiver invokes
dragEvent.acceptDrag(Shape outline)
on the event, providing a shape that will be used to give a visual feedback to the user (usually, a rectangular shape is enough). -
The DockingDesktop displays the shape on its glass pane, and the user can complete the drop (releasing the mouse button) or continue the drag gesture over another place in the same container (in that case, the same DockDropReceiver can return different shapes according to the mouse location) or over another DockDropReceiver.
The DockDropEvent
is a subclass of DockEvent which is transmitted
to a DockDropReceiver
at the end of a drag gesture.
The event is triggered only if the preceeding DockDragEvent was accepted by the same DockDropReceiver.
The DockDropReceiver must process the drop, usually by invoking split
or
createTab
methods on the DockingDesktop.