65.9K
CodeProject 正在变化。 阅读更多。
Home

使用注解的 Swing 事件 v1.2

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (3投票s)

2013 年 2 月 22 日

CPOL

3分钟阅读

viewsIcon

32754

downloadIcon

886

用于 Swing 组件的带注解的 Swing 事件。

Swing-Events Article

Swing-Events Article

Swing-Events Article

引言

向 Swing 组件添加事件可能是一项繁琐的任务,尤其是对于 Java 初学者而言。使用注解的 Swing 事件旨在方便专家和初级程序员完成此任务,使他们能够专注于业务逻辑,而不是控制器。Swing 组件的控制器可能难以管理或理解,Swing 事件提供了一些类来标准化这些组件使用的多个 Listener 和事件。

Swing 事件还提供了一个简单的解决方案,可以通过使用注解标记一个或多个方法,将 Listener 添加到 Swing 组件,该注解包含一个源组件和一个支持的事件类。

背景

许多独立应用程序使用 Swing 组件,并且它们的开发可能需要很长时间来解决事件的实现问题。Swing 事件部分地应用了命令设计模式,简化了 Swing 组件的 Listener 的使用和实现,并有助于缩短开发时间。与 EventBusevents-on-fire 相比,Swing 事件使用位于每个方法中的注解动态地将 Listener 添加到 Swing 组件,支持多个 Swing 组件、Listener 和事件。

使用代码

Swing 事件简化了事件调用。例如,要为像 JButton 这样的 Swing 组件创建一个典型的调用,应该添加一个 ActionListener

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");
    }
}); 

前面的例子很容易理解,因为只有一个 JButton 组件。但是,当应用程序中包含更多 JButton 时,它可能会变得复杂。为每个 JButton 添加一个 ActionListener,或者只为一个 JButton 添加一个 ActionListener 可能会令人困惑,并且可能会将 GUI(视图)与事件(控制器)混淆。它很难维护或扩展。使用 Swing 事件,您可以获得以下内容:

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");
}  

当多个组件实现相同的 Listener 时,Swing 事件能够将多个组件链接到一个公共方法:

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");
} 

也可以将多个方法链接到一个或多个组件:

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");
} 

要检索源事件对象,可以将其作为参数包含在带注解的方法中:

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());
} 

要定义 Listener 命令或事件 ID,应将其包含在注解中(默认的 Listener 命令是 *ActionCommand.class*,但可以根据 Swing 组件进行调整 - 请参阅随附的表格):

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");
} 

下面还有其他使用 Swing 事件的示例(包含在演示中):

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");
}
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() + ")");
    }
} 
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() + ")");
} 
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 事件支持下表中显示的多个组件:

Swing Events Table

架构

Swing 事件部分地应用了命令设计模式。它提供了一个命令接口,使构建通用组件以执行方法调用更容易。每个具体的命令对象都实现了 Java API 中为 Swing 组件定义的 Listener。 Swing 事件包括

  • 命令接口:允许调用独立于其内容的操作。
  • 接收者类:从实现 Swing 组件的 Listener 的具体命令执行方法。
  • SwingEvent 注解:添加到要由 Swing 组件调用的方法。
  • CommandBinder 类:枚举来自控制器对象的所有方法并处理 SwingEvent 注解。

这是该项目的类图

Swing Events UML

此外,该项目还包括一个基于 MVC 架构的使用注解的简单演示。MVC(模型-视图-控制器)是一种将信息与其处理分离的架构模式。对于该演示,MVC 由三个类表示

  • 模型类:表示应用程序处理的信息。
  • 视图类:表示图形用户界面 (GUI)。
  • 控制器类:调用使用 SwingEvent 注解标记的命令对象。此注解在 Swing 组件(来自视图)和方法(来自控制器)之间创建链接。此类中的每个方法都包含几个使用 Swing 组件进行的测试以及每个组件的通用 Listener

升级

添加了 AbstractActionCommandComponentCommandKeyStrokeCommand Listeners
     
© . All rights reserved.