Swing处理按钮点击及按键事件(适配器类、Action、KeyStroke等)

效果

通过按钮点击和按键(如Ctrl+B)更换背景颜色。

代码

Main

package test;

import javax.swing.*;
import java.awt.*;

public class Main {
    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            // `EventQueue.invokeLater()` 确保在正确线程中更新 GUI,避免线程安全问题。
            var f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.addWindowListener(new MyWindowListener());
            f.setSize(300, 300);

            var p = new JPanel();

            var b1 = new JButton(new ColorAction("black", p, Color.BLACK));
            var b2 = new JButton(new ColorAction("green", p, Color.GREEN));
            var b3 = new JButton(new ColorAction("yellow", p, Color.YELLOW));

            p.add(b1);
            p.add(b2);
            p.add(b3);

            f.add(p);
            f.setVisible(true);
        });
    }
}

Action类

继承了AbstractAction,间接实现了Action接口,而Action接口扩展了ActionListener

package test;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;

public class ColorAction extends AbstractAction {

    private final JComponent target;
    private final Color color;

    public ColorAction(String name, JComponent target, Color color) {
        super(name);

        this.target = target;
        this.color = color;

        putValue(Action.SHORT_DESCRIPTION, "将 颜色 变成 " + color + "色");
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        target.setBackground(color);
    }
}

事件处理中有几个重要的角色:事件源对象(例如按钮)、事件对象、监听器对象、事件处理逻辑。

事件处理的逻辑几乎总是和事件源对象(背景、各种组件)耦合。

适配器类

package test;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class MyWindowListener extends WindowAdapter {

    @Override
    public void windowClosing(WindowEvent e) {
        System.out.println("窗口关闭");
    }
}

通过按键改变颜色

package test;

import javax.swing.*;
import java.awt.*;

public class Main {
    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            // `EventQueue.invokeLater()` 确保在正确线程中更新 GUI,避免线程安全问题。
            var f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.addWindowListener(new MyWindowListener());
            f.setSize(300, 300);

            var p = new JPanel();
            
            var blackAction = new ColorAction("black", p, Color.BLACK);
            var b1 = new JButton(blackAction);
            var b2 = new JButton(new ColorAction("green", p, Color.GREEN));
            var b3 = new JButton(new ColorAction("yellow", p, Color.YELLOW));

            p.add(b1);
            p.add(b2);
            p.add(b3);

            InputMap inputMap = p.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);// 输入 -> 动作名
            inputMap.put(KeyStroke.getKeyStroke("ctrl B"), "black"); // B要大写

            ActionMap actionMap = p.getActionMap(); // 动作名 -> 具体动作
            actionMap.put("black", blackAction);

            f.add(p);
            f.setVisible(true);
        });
    }
}

关键代码:

            var blackAction = new ColorAction("black", p, Color.BLACK);
            var b1 = new JButton(blackAction);

            InputMap inputMap = p.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);// 输入 -> 动作名
            inputMap.put(KeyStroke.getKeyStroke("ctrl B"), "black"); // B要大写

            ActionMap actionMap = p.getActionMap(); // 动作名 -> 具体动作
            actionMap.put("black", blackAction);

需理解键盘焦点(keyboard focus)的概念。

posted @ 2024-12-21 14:31  xkfx  阅读(13)  评论(0编辑  收藏  举报