Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Swing

Swing Events with Annotations v1.2

4.20/5 (3 votes)
4 May 2013CPOL3 min read 32.3K   819  
Swing Events with Annotations for Swing components.

Swing-Events Article

Swing-Events Article

Swing-Events Article

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 Listeners and events used by these components. 

Swing-Events also offer a simple solution to add Listeners 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 Listeners for Swing components and helps reduce the time of development. Swing-Events, in contrast to EventBus or events-on-fire, add Listeners to Swing Components dynamically with Annotations located in each method supporting multiple Swing Components, Listeners, 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: 

Java
final JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");

action1Button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {

        // Display message in JLabel.
        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 JButtons are included in the application. Either adding an ActionListener for each JButton or just one ActionListener for all JButtons 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: 

Java
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");

@SwingEvent(sources="action1Button")
public void invokeActionPerformed1() {

    // Display message in JLabel.
    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:  

Java
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");
JButton action2Button = new JButton("Action 2");

@SwingEvent(sources={"action1Button","action2Button"})
public void invokeActionPerformed1() {

    // Display message in JLabel.
    messageLabel.setText("Invoking ActionPerformed 1 from JButton1 or JButton2");
} 

It is possible to link several methods to one or more components too:   

Java
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");
JButton action2Button = new JButton("Action 2");

@SwingEvent(sources={"action1Button","action2Button"})
public void invokeActionPerformed1() {

    // Display message in JLabel.
    messageLabel.setText("Invoking ActionPerformed 1 from JButton1 or JButton2");
}

@SwingEvent(sources="action1Button")
public void invokeActionPerformed2() {

    // Display message in JLabel.
    messageLabel.setText("Invoking ActionPerformed 2 from JButton1");
} 

To retrieve the source event object, this can be included as param in the annotated method:  

Java
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");

@SwingEvent(sources="action1Button")
public void invokeActionPerformed1(ActionEvent e) {

    // Display message in JLabel.
    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):  

Java
JLabel messageLabel = new JLabel();
JButton action1Button = new JButton("Action 1");

@SwingEvent(sources="action1Button", command=ActionCommand.class,
        eventIds=ActionEvent.ACTION_PERFORMED)
public void invokeActionPerformed1() {

    // Display message in JLabel.
    messageLabel.setText("Invoking ActionPerformed 1 from JButton");
} 

Below there are other examples using Swing-Events (they are included in the demo): 

Java
JLabel messageLabel = new JLabel();
JFrame View = new JFrame();

// Simple JFrame Listener for the WindowClosing event.
@SwingEvent(sources="View", command=WindowCommand.class,
        eventIds=WindowEvent.WINDOW_CLOSING)
public void invokeWindowClosingAndClosed() {
    messageLabel.setText("Invoking WindowClosing from JFrame");
}
Java
JLabel messageLabel = new JLabel();

// Muliple Events Id for the same Listener Command.
@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() + ")");
    }
} 
Java
JLabel messageLabel = new JLabel();

// Create a TableModel to display a data model on a JTable.
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();

// Retrieve ListSelectionModel from JTable firing the valueChange event when a row is selected.
@SwingEvent(sources="table", command=ListSelectionCommand.class)
public void invokeRowValueChanged() {
    messageLabel.setText("Invoking ValueChanged from Row ListSelectionModel "
        + "(Index: " + tableRowSelectionModel.getLeadSelectionIndex() + ")");
} 
Java
JLabel messageLabel = new JLabel();
JFrame View = new JFrame();
JRootPane rootPane = View.getRootPane();

// Close application when the Escape key is pressed with the new KeyStrokeCommand Listener.
// KeyStrokeCommand supports keys & modifiers (alt, shift, control, meta, altGraph or combined)
@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: 

Swing Events 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:

Swing Events UML

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.
     

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)