Introduction
Adding events to Swing Components can be an annoying task, especially for Java beginners. Swing-Events with Annotations was designed to facilitate this task,
for both expert and beginner programmers, allowing them to focus on business logic and not on Controllers. Controllers for Swing
components can be difficult to manage or understand,
Swing-Events offer classes to standardize several Listener
s and events used by these components.
Swing-Events also offer a simple solution to add Listener
s to Swing
components tagging one or more methods with an Annotation that includes a
source component and an event class supported by this.
Background
Many standalone applications use Swing Components and their development can take a long time
for solving the implementation of events. Swing-Events apply a Command
Design Pattern partially that simplifies the using and the implementation of Listener
s for Swing
components and helps reduce the time of development.
Swing-Events, in contrast to EventBus or events-on-fire,
add Listener
s to Swing Components dynamically with Annotations located in each
method supporting multiple Swing Components, Listener
s, and Events.
Using the code
Swing-Events simplify the events call. For example, to create a typical call for a Swing
component like a JButton
, an ActionListener
should be added:
final JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");
action1Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
messageLabel.setText("Invoking ActionPerformed 1 from JButton");
}
});
The previous example is easy to understand because there is a single JButton
component. However, it can be complex when more JButton
s are included in the
application. Either adding an ActionListener
for each JButton
or just one ActionListener
for all JButton
s can be confusing
as well as can mix up the GUI (View) with the events (Controller). It is difficult to maintain or scale. Using Swing-Events you get the following:
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");
@SwingEvent(sources="action1Button")
public void invokeActionPerformed1() {
messageLabel.setText("Invoking ActionPerformed 1 from JButton");
}
Swing-Events is able to link several components to a common method when they implement the same Listener
:
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");
JButton action2Button = new JButton("Action 2");
@SwingEvent(sources={"action1Button","action2Button"})
public void invokeActionPerformed1() {
messageLabel.setText("Invoking ActionPerformed 1 from JButton1 or JButton2");
}
It is possible to link several methods to one or more components too:
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");
JButton action2Button = new JButton("Action 2");
@SwingEvent(sources={"action1Button","action2Button"})
public void invokeActionPerformed1() {
messageLabel.setText("Invoking ActionPerformed 1 from JButton1 or JButton2");
}
@SwingEvent(sources="action1Button")
public void invokeActionPerformed2() {
messageLabel.setText("Invoking ActionPerformed 2 from JButton1");
}
To retrieve the source event object, this can be included as param in the annotated method:
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");
@SwingEvent(sources="action1Button")
public void invokeActionPerformed1(ActionEvent e) {
messageLabel.setText("Invoking ActionPerformed 1 from " + e.getSource());
}
To define a Listener
Command or Events ID, they should be included into the Annotation (default Listener
command is ActionCommand.class but it can be adjusted
according to the Swing Component - see attached table):
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");
@SwingEvent(sources="action1Button", command=ActionCommand.class,
eventIds=ActionEvent.ACTION_PERFORMED)
public void invokeActionPerformed1() {
messageLabel.setText("Invoking ActionPerformed 1 from JButton");
}
Below there are other examples using Swing-Events (they are included in the demo):
JLabel messageLabel = new JLabel();
JFrame View = new JFrame();
@SwingEvent(sources="View", command=WindowCommand.class,
eventIds=WindowEvent.WINDOW_CLOSING)
public void invokeWindowClosingAndClosed() {
messageLabel.setText("Invoking WindowClosing from JFrame");
}
JLabel messageLabel = new JLabel();
@SwingEvent(sources="trayIcon", command=MouseCommand.class,
eventIds={MouseEvent.MOUSE_PRESSED,MouseEvent.MOUSE_RELEASED})
public void invokeMousePressedAndReleasedFromTrayIcon(MouseEvent e) {
if (e.isPopupTrigger()) {
messageLabel.setText("Invoking MousePressed and MouseReleased from TrayIcon "
+ "(Position: " + e.getX() + "," + e.getY() + ")");
}
}
JLabel messageLabel = new JLabel();
DefaultTableModel tableModel = new DefaultTableModel(
new Object [][]{null, null, null},
new String [] {"Title 1", "Title 2", "Title 3"});
JTable table = new JTable(tableModel);
ListSelectionModel tableRowSelectionModel = table.getSelectionModel();
@SwingEvent(sources="table", command=ListSelectionCommand.class)
public void invokeRowValueChanged() {
messageLabel.setText("Invoking ValueChanged from Row ListSelectionModel "
+ "(Index: " + tableRowSelectionModel.getLeadSelectionIndex() + ")");
}
JLabel messageLabel = new JLabel();
JFrame View = new JFrame();
JRootPane rootPane = View.getRootPane();
@SwingEvent(sources="rootPane", command=KeyStrokeCommand.class,
eventIds={JComponent.WHEN_IN_FOCUSED_WINDOW, KeyEvent.VK_ESCAPE})
public void invokeActionPerformedFromViewWithEscapeKey() {
messageLabel.setText("Invoking actionPerformed from View with the Escape key.");
}
Swing-Events support several components that are shown in the next table:
Architecture
Swing-Events apply Command Design Pattern partially. It offers a Command interface which makes
it easier to construct general components to execute method calls.
Every Concrete Command object implements a defined Listener
from
the Java API for Swing Components. Swing-Events include:
- Command interface: allows to call an operation independent of its contents.
- Receiver class: executes a method from a Concrete Command that implements a
Listener
for a Swing
component. - SwingEvent Annotation: is added to methods to be called by a Swing
component.
- CommandBinder class: enumerates all methods from the Controller object and processes SwingEvent Annotations.
This is the classes diagram for the project:
Besides, this project includes a simple demo using annotations based on the MVC architecture. MVC (Model-View-Controller) is an architecture pattern separating
information from its processing. For the demo, MVC is represented by three classes:
- Model class: represents the information processed by the application.
- View class: represents the Graphical User Interface (GUI).
- Controller class: invokes the Command objects tagged with the SwingEvent annotation. This annotation creates a link between Swing Components (from View)
and methods (from Controller). Every method in this class contains several tests with Swing Components and common
Listeners
for each one.
Upgrade
The
AbstractActionCommand,
ComponentCommand and
KeyStrokeCommand Listeners
were added.