`
mylxiaoyi
  • 浏览: 327579 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

[翻译]Swing组件集合的事件处理(六)

    博客分类:
  • Java
阅读更多

2.3 Swing特定的事件处理

请记住,Swing组件是构建在AWT库之上的,Swing组件库具有一些改进的功能从而使得事件处理更为简单。功能改进覆盖AWT核心事件处理特性之上,由基本的动作监听到焦点管理。

为了简化事件处理,Swing库使用Action接口扩展了原始的ActionListener接口来存储具有事件处理器的可视属性。这使得事件处理器的创建独立于可视化组件。然后,当Action在稍后与一个组件相关联时,组件直接由事件处理器自动获取信息(例如按钮标签)。这包括当Action被修改时更新标签的通知。AbstractAction与TextAction类实现了这个概念。

Swing库同时添加了KeyStroke类从而使得我们更容易的响应键盘事件。当一个特定的击键序列被按下时,我们可以通知组件必须响应特定的动作,而无需监听一个特定键的所有按键事件。这些击键到动作的映射存储在InputMap与ActionMap对象的组合中。当组件容器具有信息时,InputMap就会特例化ComponentInputMap。Swing文本组件借助于Keymap接口可以更容易的使用这些来存储击键到动作的映射。第16章更详细的描述了TextAction支持的映射,以及文本事件处理功能的其余部分。

KeyboardFocusManager与DefaultKeyboardFocusManager,借助于FocusTraversalPolicy及其实现的帮助,管理焦点子系统。InputVerifier用于用户输入验证。这些内容都会在本章稍后的Swing组件管理部分进行讨论。

2.3.1 Action接口

Action接口是ActionListener接口的扩展,他可以非常灵活的用于定义与作为触发代理的组件相独立的共享事件处理器。这个接口实现了ActionListener,并且定义了一个查询表数据结构,其键值作为属性。然后,当Action与一个组件相关联时,这些显示属性会自动的传递到Action。下面是接口定义:

  1. public interface Action implements ActionListener {
      // Constants 
      public final static String ACCELERATOR_KEY;
      public final static String ACTION_COMMAND_KEY;
      public final static String DEFAULT;
      public final static String LONG_DESCRIPTION;
      public final static String MNEMONIC_KEY;
      public final static String NAME;
      public final static String SHORT_DESCRIPTION;
      public final static String SMALL_ICON; // Listeners
      public void addPropertyChangeListener(PropertyChangeListener listener);
      public void removePropertyChangeListener(PropertyChangeListener listener);
      // Properties
      public boolean isEnabled();
      public void setEnabled(boolean newValue);
      // Other methods
      public Object getValue(String key);
      public void putValue(String key, Object value);
    }
     
因为Action仅是一个接口,Swing提供了一个类来实现这个接口,这就是AbstractAction。

2.3.2 AbstractAction类

AbstractAction类提供了Action接口的一个默认实现。这就是属性行为实现的地方。

使用Action

一旦我们通过继承定义一个AbstractAction并且提供一个public void actionPerformed(ActionEvent actionEvent)方法,我们就可以将其传递给一些特殊的Swing组件。JCheckBox,JToggleButton,JMenuItem,JCheckBoxMenuItem以及JRadioButtonMenuItem提供了由动作创建组件的构造函数,而Swing文本组件通过Keymap,InputMap以及ActionMap对Action对象提供了内建支持。

当具有关联Action的组件被添加到相应的Swing容器中时,选中会触发Action的actionPerformed(ActionEvent actionEvent)方法的调用。组件的显示是通过添加到内部数据结构的属性元素来定义的。了为演示的需要,列表2-8提供了一个具有Print标签以及一个图标的Action。当其被激活时,会输出一个Hello, World消息。

import java.awt.event.*;
import javax.swing.*;
public class PrintHelloAction extends AbstractAction {
  private static final Icon printIcon = new ImageIcon("Print.gif");
  PrintHelloAction() {
    super("Print", printIcon);
    putValue(Action.SHORT_DESCRIPTION, "Hello, World");
  }
  public void actionPerformed(ActionEvent actionEvent) {
    System.out.println("Hello, World");
  }
}
 

一旦定义了Action,我们就可以创建Action并将其与我们所希望的组件相关联。

  1. Action printAction = new PrintHelloAction();
    menu.add(new JMenuItem(printAction));
    toolbar.add(new JButton(printAction));
     

在我们将Action与对象相关联之后,如果我们发现我们需要修改Action的属性,我们只需要在一个地方修改其设置 。因为所有的属性都是绑定的,他们会传播到使用Action的任意组件。例如,禁止Action(printAction.setEnabled(false))将会禁止分别在JMenu与JToolBar上所创建的JMenuItem与JButton。相应的,通过printAction.putValue(Action.NAME, "Hello, World")修改Action的名字将会修改相关联组件的文本标签。

图2-6JToolBar与JMenu上的PrintHelloAction的样子。可选中的按钮用来允许或是禁止Action,同时也可以修改其名字。

swing_2_6

此示例的完整代码显示在列表2-9中。不要担心工具栏与菜单栏的创建。我们将会在第6章对其进行详细的讨论。

  1. /**
     * 
     */
    package swingstudy.ch02;
     
    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
     
    import javax.swing.Action;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JPanel;
    import javax.swing.JToolBar;
     
    /**
     * @author lenovo
     *
     */
    public class ActionTester {
     
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
     
            Runnable runner = new Runnable() {
                public void run() {
                    JFrame frame = new JFrame("Action Sample");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
                    final Action printAction = new PrintHelloAction();
     
                    JMenuBar menuBar = new JMenuBar();
                    JMenu menu = new JMenu("File");
                    menuBar.add(menu);
                    menu.add(new JMenuItem(printAction));
     
                    JToolBar toolBar = new JToolBar();
                    toolBar.add(new JButton(printAction));
     
                    JButton enableButton = new JButton("Enable");
                    ActionListener enableActionListener = new ActionListener() {
                        public void actionPerformed(ActionEvent event) {
                            printAction.setEnabled(true);
                        }
                    };
                    enableButton.addActionListener(enableActionListener);
     
                    JButton disableButton = new JButton("Disable");
                    ActionListener disableActionListener = new ActionListener() {
                        public void actionPerformed(ActionEvent event) {
                            printAction.setEnabled(false);
                        }
                    };
                    disableButton.addActionListener(disableActionListener);
     
                    JButton relabelButton = new JButton("Relabel");
                    ActionListener relabelActionListener = new ActionListener() {
                        public void actionPerformed(ActionEvent event) {
                            printAction.putValue(Action.NAME, "Hello, World");
                        }
                    };
                    relabelButton.addActionListener(relabelActionListener);
     
                    JPanel buttonPanel = new JPanel();
                    buttonPanel.add(enableButton);
                    buttonPanel.add(disableButton);
                    buttonPanel.add(relabelButton);
     
                    frame.setJMenuBar(menuBar);
     
                    frame.add(toolBar, BorderLayout.SOUTH);
                    frame.add(buttonPanel, BorderLayout.NORTH);
     
                    frame.setSize(300, 200);
                    frame.setVisible(true);
                }
            };
     
            EventQueue.invokeLater(runner);
        }
     
    }
    
     

AbstractAction属性

正如表2-2所示,AbstractAction类有三个可用的属性。

属性名 
数据类型 

访问性

enabled 
boolean 

读写绑定

keys 
Object[] 

只读

propertyChangeListeners
PropertyChangeListener[]

只读

其余的绑定属性通过putValue(String key, Object value)放置在查询表中。获取当前的keys属性设置可以使得我们查看可以进行哪些设置,而不需要进行单独请求。表2-3描述了可以用作键值的Action预定义常量集合。我们也可以添加我们自己的常量,从而在以后动作发生时进行查询。



常量 

描述

NAME 

Action名字,用作按钮标签

SMALL_ICON 

Action图标,用作按钮标签

SHORT_DESCRIPTION 

Action的简短描述;可以用作提示文本,但是默认情况下并不用

LONG_DESCRIPTION 

Action的长描述;可以用作访问功能(查看第22章)

ACCELERATOR 

KeyStroke字符串;可以用Action的快捷键

ACTION_COMMAND_KEY

InputMap键;映射到与JComponent相关的ActionMap中的Action

MNEMONIC_KEY 

按键代码;可以用作Action的快捷键

DEFAULT 

可以用于我们自定义属性的未用常量


一旦一个属性已经存放在查询表中,我们可以通过public Object getValue(String key)进行获取。其作用方式类似于java.util.Hashtable类或是java.util.Map接口,区别在于:如果表中存在一个键值,那么我们尝试存入一个具有null值的key/value对,则查询表会移除这个键值。

2.3.3 KeyStroke类

KeyStroke类以及特定JComponent的inputMap与actionMap属性提供了一个简单的替换可以向组件注册KeyListener对象并监听特定键的按下。KeyStroke使得我们可以定义一个简单的按键集合,例如Shift-Ctrl-P或是F4。然后我们可以通过将其注册到组件来激活按键,并且在组件识别出时通知按键进行动作,从而通知ActionListener。

在我们探讨如何创建按键之前,我们先来了解一下可以激活按键的不同条件,从而添加不同的输入映射。有三个条件可以激活已注册的按键,并JComponent中的四个常量可以提供帮助。第四个用于未定义的状态。表2-4中列出了可用的四个常量。

常量 

描述

WHEN_FOCUSED 

当实际的组件获得输入焦点时激活按键

WHEN_IN_FOCUSED_WINDOW 

当组件所在的窗口获得输入焦点时激活按键

WHEN_ANCESTOR_OF_FOCUSED_COMPONENT

当在组件或是在组件的容器中按下时激活按键

UNDEFINED_CONDITION 

用于没有定义条件的情况

构建按键

KeyStroke类是AWTKeyStroke的子类,并且没有公开的构造函数。我们可以通过下面的方法来创建一个按键:

public static KeyStroke getKeyStroke(char keyChar)
public static KeyStroke getKeyStroke(String representation)
public static KeyStroke getKeyStroke(int keyCode, int modifiers)
public static KeyStroke getKeyStroke(int keyCode, int modifiers,
  boolean onKeyRelease)
public static KeyStroke getKeyStrokeForEvent(KeyEvent keyEvent)
 

列表中的第一个版本,public static KeyStroke getKeyStroke(char keyChar),可以使得我们由一个char变量创建按键,例如Z。

KeyStroke space = KeyStroke.getKeyStroke('Z');

public static KeyStroke getKeyStroke(String representation)版本是最有趣的版本。他可以使得我们通过一个文本字符串来指定按键,例如"control F4"。字符串的标识符集合为shift, control, meta, alt, button1, button2与button3以及可以指定的多标识符。字符串的其余部分来自KeyEvent类的VK_*常量。例如,下面的代三为Ctrl-Alt-7定义了一个按键:

KeyStroke controlAlt7 = KeyStroke.getKeyStroke("control alt 7");

public static KeyStroke getKeyStroke(int keyCode, int modifiers)public static KeyStroke getKeyStroke(int keyCode, int modifiers,boolean onKeyRelease)是两个最为直接的方法。他允许我们直接指定VK_*常量 以及用于标识符的InputEvent掩码(没有标识符时为0)。当没有指定时,onKeyRelease为false。

KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true);
KeyStroke shiftF4 = KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.SHIFT_MASK);
 

列表中的最后一个版本,public static KeyStroke getKeyStrokeForEvent(KeyEvent keyEvent),将特定的KeyEvent直接映射到KeyStroke。当我们希望允许用户使用按键来激活事件时,这个方法就十分有用。我们要求用户为某一事件按下一个键,然后注册KeyEvent,从而下次按键发生时,事件就会被激活。

KeyStroke fromKeyEvent = KeyStroke.getKeyStrokeForEvent(keyEvent);

注册按键

在我们创建了按键之后,我们需要将其注册到组件。当我们向组件注册一个按键时,我们提供一个当按键按下(或是释放)时要调用的Action。注册要提供一个由按键到Action的映射。首先,我们通过getInputMap(condition)方法获取基于焦点激活条件组件的相应的InputMap。如果没有指定条件,则假定为WHEN_FOCUSED。然后我们在InputMap中添加一个由按键到文本字符串的映射:

component.getInputMap().put(keystroke, string)

如果我们知道已存在动作的动作字符串,我们就可以使用这个字符串;否则我们要定义这个字符串。然后我们使用ActionMap将字符串映射到Action:

component.getActionMap.put(string, action)

我们可以通过共享ActionMap实例来在组件之间共享动作。列表2-10的例子中创建了四个按钮,每一个都注册了不同的按键以及不同的焦点激活条件。按钮标签表明了按键激活条件。Action只是简单的输出消息并激活按钮标签。

/**
 * 
 */
package swingstudy.ch02;
 
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
 
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
 
/**
 * @author lenovo
 *
 */
public class KeyStrokeSample {
 
    private static final String ACTION_KEY = "theAction";
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Runnable runner = new Runnable() {
            public void run() {
                JFrame frame = new JFrame("KeyStroke Sample");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
                JButton buttonA = new JButton("<html><center>FOCUSED
control alt 7");
                JButton buttonB = new JButton("<html><center>FOCUS/RELEASE
VK_ENTER");
                JButton buttonC = new JButton("<html><center>ANCESTOR
VK_F4+SHIFT_MASK");
                JButton buttonD = new JButton("<html><center>WINDOW
' '");
 
                Action actionListener = new AbstractAction() {
                    public void actionPerformed(ActionEvent event) {
                        JButton source = (JButton)event.getSource();
                        System.out.println("Activated: "+source.getText());
                    }
                };
 
                KeyStroke controlAlt7 = KeyStroke.getKeyStroke("control alt 7");
                InputMap inputMap = buttonA.getInputMap();
                inputMap.put(controlAlt7, ACTION_KEY);
                ActionMap actionMap = buttonA.getActionMap();
                actionMap.put(ACTION_KEY, actionListener);
 
                KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true);
                inputMap = buttonB.getInputMap();
                inputMap.put(enter, ACTION_KEY);
                buttonB.setActionMap(actionMap);
 
                KeyStroke shiftF4 = KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.SHIFT_MASK);
                inputMap = buttonC.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
                inputMap.put(shiftF4, ACTION_KEY);
                buttonC.setActionMap(actionMap);
 
                KeyStroke space = KeyStroke.getKeyStroke(' ');
                inputMap = buttonD.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
                inputMap.put(space, ACTION_KEY);
                buttonD.setActionMap(actionMap);
 
                frame.setLayout(new GridLayout(2,2));
                frame.add(buttonA);
                frame.add(buttonB);
                frame.add(buttonC);
                frame.add(buttonD);
 
                frame.setSize(400, 200);
                frame.setVisible(true);
            }
        };
 
        EventQueue.invokeLater(runner);
    }
 
}
 

图2-7显示了程序运行时的样子。

swing_2_7

2.3.4 使用快捷键

Swing库也可以使用KeyStroke对象用于一些内部功能。两个这样的功能为记忆键与快捷键,其工作如下:

  • 在组件记忆键中,标签中的一个字符以下划线出现。当这个字符平台特定的热键组合被按下时,组件就会被激活。例如,在图2-8所示的窗体中按下Alt-A则会在Windows XP平台下选中About按钮。
  • 菜单快捷键可以在菜单条目不可见的情况下激活条目。例如,在图2-8所示的窗体中按下Ctrl-P将会在File菜单不可见的情况下选中Print菜单条目。

swing_2_8

我们将会在第6章了解更多关于记忆键与快捷键的内容。

分享到:
评论

相关推荐

    Java Swing'组件集合

    本篇文章将深入探讨Java Swing组件集合,帮助初学者更好地理解和使用这些组件。 首先,Swing 提供了丰富的组件集,包括按钮(JButton)、文本框(JTextField)、标签(JLabel)、复选框(JCheckBox)、单选按钮...

    swing控件及事件

    Swing是Java Foundation Classes (JFC)的一部分,提供了丰富的组件集合,用于创建美观且功能强大的图形用户界面。其中,一些常见的Swing控件包括: 1. **JFrame**:作为窗口的基础,它是所有Swing应用的起点。在...

    Java Swing 组件全演示

    它提供了丰富的组件集合,使得开发者可以创建复杂的、交互式的用户界面。在Java Swing组件全演示中,我们将深入探讨Swing的核心概念、组件和设计原则。 首先,Swing是基于AWT(Abstract Window Toolkit)的,但提供...

    swing组件的详细介绍

    1. **元件多样性**:Swing提供了比AWT更丰富的组件集合,包括树状视图(Treeviews)、图片按钮等,让开发者能创建更为复杂的用户界面。 2. **跨平台一致性**:Swing组件是轻量级的,它们不依赖于底层操作系统,从而...

    几个漂亮的SWING组件(源代码)

    Java Swing 是Java GUI(图形用户界面...总的来说,通过研究这些源代码,开发者不仅可以学习到Swing组件的基本使用,还能了解到组件的定制、交互处理和界面设计的技巧,这对于提升Java桌面应用开发技能是非常有帮助的。

    Swing 组件大全

    综上所述,"Swing组件大全"不仅涵盖了Swing库中的所有核心组件,还涵盖了数据库操作、Excel文件处理和自定义布局管理,是学习和开发Swing应用的宝贵资源。通过深入理解和实践这些知识点,开发者可以构建出功能强大且...

    java swing组件例子

    通过深入学习和实践这个"java swing组件例子",你将能够熟练掌握如何使用Java Swing创建功能丰富的GUI应用程序,理解组件间的交互、事件处理机制以及布局管理的重要性和用法。同时,还能了解到如何通过自定义外观和...

    swing资料集合

    它可能涵盖了Swing组件的定制,如创建自定义外观和行为,以及如何利用模型-视图-控制器(MVC)模式来构建可维护的应用程序。源代码实例可能涉及到Swing的高级组件,如JTable、JTree和JList,以及如何与数据库进行...

    基于java的开源的Swing组件 JIDE.zip

    Java Swing组件库JIDE是一个强大的开发工具,专为Java开发者设计,用于构建功能丰富的桌面应用程序。JIDE提供了许多预构建的、高度可定制的Swing组件,极大地扩展了标准Java Swing的功能。这个开源项目旨在简化GUI...

    经典Swing事例集合

    Swing组件的一个重要特点是它们支持模型-视图-控制器(MVC)设计模式,使得代码结构更清晰,维护更容易。 1. **JFrame**: JFrame是顶级容器,常用于创建窗口应用程序。你可以添加各种组件到JFrame上,如菜单栏、...

    Java Swing 组件全演示源代码.rar_java swing_java 组件_java swing_java源代码_

    Java Swing 是Java GUI(图形用户界面)开发的重要库,它提供了丰富的组件集合,用于构建桌面应用程序。本资源“Java Swing 组件全演示源代码”包含了Java Swing中的各种组件的完整示例代码,可以帮助开发者深入理解...

    JAVA Swing常用组件

    在学习和使用Swing组件时,了解每个组件的属性、方法和事件处理机制非常重要。通过实例代码和案例分析,你可以更好地掌握如何创建功能丰富的桌面应用程序。提供的"Swing常用组件"资源很可能是包含各种示例代码的集合...

    Swing组件介绍(非常全)

    它是Java Foundation Classes (JFC) 的一部分,提供了一套丰富的组件集合,用于构建功能完善的用户界面。Swing在早期是为了弥补Java AWT(Abstract Window Toolkit)的不足而设计的,提供了更丰富的功能、更好的可...

    java-swing 实例集合及其源码

    通过分析这些实例,开发者可以深入理解Swing组件的使用、事件处理机制、自定义绘制方法以及如何将它们结合到实际项目中。这些源码实例为初学者提供了宝贵的实践资料,同时也为经验丰富的开发者提供了灵感和参考。

    jfc+swing—java基础类组件集

    它们提供了一套丰富的组件集合,使得开发者能够创建功能强大的桌面应用程序。Swing 是 JFC 的一部分,它扩展了 Java AWT(Abstract Window Toolkit)库,提供了更多的功能和更好的性能。 一、JFC 概述: Java ...

    java使用swing组件编写的简易计算器

    总的来说,这个"java使用swing组件编写的简易计算器"项目涵盖了Java GUI编程的基础,包括Swing组件的使用、事件处理、基本计算逻辑实现以及IDE的使用。通过这个项目,开发者可以深入理解Java Swing的原理和实践,...

    SWING资料大集合

    - **Java Desktop.org**:这个网站提供了大量的Swing组件集合和示例代码,对于开发者来说是一个不错的资源库。 - **ChinaJavaWorld论坛**:这个中文论坛也有关于Swing的讨论和技术交流,适合中文读者。 ### 性能...

    基于Swing组件编写华容道Java程序

    在本项目中,“基于Swing组件编写华容道...它不仅展示了Swing组件的使用,还涵盖了图形用户界面设计、事件处理、数据结构以及算法应用等多个IT领域的知识。这样的项目对于学习和提升Java GUI编程能力是非常有价值的。

    Swing组件+MySQL销售管理系统_java系统_swing系统mysql_java.zip

    首先,Swing是Java的标准GUI库,它提供了丰富的组件集合,如按钮、文本框、表格、菜单等,用于构建美观且功能强大的桌面应用。在销售管理系统中,Swing组件可以用来创建用户友好的界面,让用户能够方便地输入、查看...

    SWING—JAVA 基础类组件集

    标题和描述中提到的知识点是关于Java...总结来说,Swing是一个全面的用户界面工具包,它通过Java语言的纯粹性,提供了一套跨平台、模块化的用户界面组件集合。开发者利用Swing可以创建功能强大、界面美观的应用程序。

Global site tag (gtag.js) - Google Analytics