使用注解的 Swing 事件 v1.2






4.20/5 (3投票s)
用于 Swing 组件的带注解的 Swing 事件。
引言
向 Swing 组件添加事件可能是一项繁琐的任务,尤其是对于 Java 初学者而言。使用注解的 Swing 事件旨在方便专家和初级程序员完成此任务,使他们能够专注于业务逻辑,而不是控制器。Swing 组件的控制器可能难以管理或理解,Swing 事件提供了一些类来标准化这些组件使用的多个 Listener
和事件。
Swing 事件还提供了一个简单的解决方案,可以通过使用注解标记一个或多个方法,将 Listener
添加到 Swing 组件,该注解包含一个源组件和一个支持的事件类。
背景
许多独立应用程序使用 Swing 组件,并且它们的开发可能需要很长时间来解决事件的实现问题。Swing 事件部分地应用了命令设计模式,简化了 Swing 组件的 Listener
的使用和实现,并有助于缩短开发时间。与 EventBus 或 events-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 事件部分地应用了命令设计模式。它提供了一个命令接口,使构建通用组件以执行方法调用更容易。每个具体的命令对象都实现了 Java API 中为 Swing 组件定义的 Listener
。 Swing 事件包括
- 命令接口:允许调用独立于其内容的操作。
- 接收者类:从实现 Swing 组件的
Listener
的具体命令执行方法。 - SwingEvent 注解:添加到要由 Swing 组件调用的方法。
- CommandBinder 类:枚举来自控制器对象的所有方法并处理 SwingEvent 注解。
这是该项目的类图
此外,该项目还包括一个基于 MVC 架构的使用注解的简单演示。MVC(模型-视图-控制器)是一种将信息与其处理分离的架构模式。对于该演示,MVC 由三个类表示
- 模型类:表示应用程序处理的信息。
- 视图类:表示图形用户界面 (GUI)。
- 控制器类:调用使用 SwingEvent 注解标记的命令对象。此注解在 Swing 组件(来自视图)和方法(来自控制器)之间创建链接。此类中的每个方法都包含几个使用 Swing 组件进行的测试以及每个组件的通用
Listener
。
升级
添加了 AbstractActionCommand、ComponentCommand 和 KeyStrokeCommandListeners
。