イベント処理の基本(ActionListenerなど)

2025-08-06

Swingアプリケーションにインタラクティブ性を追加するためには、イベント処理の仕組みを理解する必要があります。ユーザーの操作(ボタンクリック、キー入力など)に応じて適切な処理を実行できるようになります。

イベント処理の基本モデル

event_handling

主要なコンポーネント

  1. イベントソース – イベントを発生させるコンポーネント(ボタンなど)
  2. イベントオブジェクト – 発生したイベントの情報を保持
  3. イベントリスナー – イベントを処理するオブジェクト

基本的なActionListenerの実装

方法1: 匿名インナークラスを使用

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

public class ActionListenerExample1 {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("ActionListener例");
            frame.setSize(300, 200);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new FlowLayout());

            JButton button = new JButton("クリックしてください");

            // 匿名インナークラスでActionListenerを実装
            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showMessageDialog(frame, 
                        "ボタンがクリックされました!",
                        "情報",
                        JOptionPane.INFORMATION_MESSAGE);
                }
            });

            frame.add(button);
            frame.setVisible(true);
        });
    }
}

方法2: ラムダ式を使用(Java 8以降)

import javax.swing.*;

public class ActionListenerExample2 {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("ラムダ式例");
            frame.setSize(300, 200);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new FlowLayout());

            JButton button = new JButton("ラムダ式で処理");

            // ラムダ式でActionListenerを実装
            button.addActionListener(e -> {
                JOptionPane.showMessageDialog(frame, 
                    "ラムダ式で処理されました",
                    "成功",
                    JOptionPane.PLAIN_MESSAGE);
            });

            frame.add(button);
            frame.setVisible(true);
        });
    }
}

主要なイベントリスナー一覧

リスナーインターフェース主な使用コンポーネントイベントメソッド発生条件
ActionListenerJButton, JTextFieldactionPerformed()ボタンクリック、Enterキー押下
ItemListenerJCheckBox, JComboBoxitemStateChanged()選択状態の変更
MouseListener全コンポーネントmouseClicked()などマウス操作
KeyListener全コンポーネントkeyPressed()などキーボード操作
FocusListener全コンポーネントfocusGained()などフォーカスの移動
DocumentListenerJTextField, JTextAreainsertUpdate()などテキスト変更

複数のイベントソースを1つのリスナーで処理

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

public class MultiSourceHandler {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("複数イベントソース処理");
            frame.setSize(400, 300);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new GridLayout(3, 1, 10, 10));

            JButton redButton = new JButton("赤");
            JButton greenButton = new JButton("緑");
            JButton blueButton = new JButton("青");

            // 1つのActionListenerで複数ボタンを処理
            java.awt.event.ActionListener colorChanger = e -> {
                JButton source = (JButton)e.getSource();
                String colorName = source.getText();

                switch(colorName) {
                    case "赤":
                        frame.getContentPane().setBackground(Color.RED);
                        break;
                    case "緑":
                        frame.getContentPane().setBackground(Color.GREEN);
                        break;
                    case "青":
                        frame.getContentPane().setBackground(Color.BLUE);
                        break;
                }
            };

            redButton.addActionListener(colorChanger);
            greenButton.addActionListener(colorChanger);
            blueButton.addActionListener(colorChanger);

            frame.add(redButton);
            frame.add(greenButton);
            frame.add(blueButton);

            frame.setVisible(true);
        });
    }
}

MouseListenerの実装例

import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class MouseListenerExample {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("MouseListener例");
            frame.setSize(400, 300);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JPanel panel = new JPanel();
            JLabel statusLabel = new JLabel("マウスイベント待機中...");
            statusLabel.setHorizontalAlignment(SwingConstants.CENTER);

            // MouseAdapter(抽象クラス)を使用して必要なメソッドのみ実装
            panel.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    statusLabel.setText(String.format(
                        "クリック位置: X=%d, Y=%d, クリック数=%d",
                        e.getX(), e.getY(), e.getClickCount()));
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    panel.setBackground(Color.CYAN);
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    panel.setBackground(null); // デフォルト色に戻す
                }
            });

            frame.add(panel, BorderLayout.CENTER);
            frame.add(statusLabel, BorderLayout.SOUTH);
            frame.setVisible(true);
        });
    }
}

DocumentListenerによるテキスト変更検知

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;

public class DocumentListenerExample {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("DocumentListener例");
            frame.setSize(400, 200);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());

            JTextField textField = new JTextField();
            JLabel counterLabel = new JLabel("文字数: 0");
            counterLabel.setHorizontalAlignment(SwingConstants.CENTER);

            textField.getDocument().addDocumentListener(new DocumentListener() {
                private void updateCount() {
                    int length = textField.getText().length();
                    counterLabel.setText("文字数: " + length);
                }

                @Override public void insertUpdate(DocumentEvent e) { updateCount(); }
                @Override public void removeUpdate(DocumentEvent e) { updateCount(); }
                @Override public void changedUpdate(DocumentEvent e) { updateCount(); }
            });

            frame.add(textField, BorderLayout.NORTH);
            frame.add(counterLabel, BorderLayout.CENTER);
            frame.setVisible(true);
        });
    }
}

イベント処理のベストプラクティス

  1. EDT(イベントディスパッチスレッド)の遵守 – Swingコンポーネントの操作は必ずEDTで行う
  2. リスナーの適切な選択 – 用途に合ったリスナーを選択(例: テキスト変更はDocumentListener)
  3. リスナーの分離 – 複雑な処理は別クラスに分離
  4. リソース解放 – 不要になったリスナーは削除
  5. 長時間処理の回避 – イベント処理内で重い処理を行わない(別スレッドを使用)
// リスナーを削除する例
ActionListener listener = e -> {...};
button.addActionListener(listener);
// 後で削除する場合
button.removeActionListener(listener);

実践的なフォーム処理の例

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

public class RegistrationForm {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("ユーザー登録フォーム");
            frame.setSize(500, 350);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
            mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

            JPanel formPanel = new JPanel(new GridLayout(4, 2, 10, 10));

            JTextField nameField = new JTextField();
            JPasswordField passField = new JPasswordField();
            JPasswordField confirmPassField = new JPasswordField();
            JComboBox<String> genderCombo = new JComboBox<>(new String[]{"男性", "女性", "その他"});

            formPanel.add(new JLabel("ユーザー名:"));
            formPanel.add(nameField);
            formPanel.add(new JLabel("パスワード:"));
            formPanel.add(passField);
            formPanel.add(new JLabel("パスワード確認:"));
            formPanel.add(confirmPassField);
            formPanel.add(new JLabel("性別:"));
            formPanel.add(genderCombo);

            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
            JButton registerButton = new JButton("登録");
            JButton clearButton = new JButton("クリア");

            registerButton.addActionListener(e -> {
                String name = nameField.getText();
                char[] password = passField.getPassword();
                char[] confirmPassword = confirmPassField.getPassword();
                String gender = (String)genderCombo.getSelectedItem();

                if (name.isEmpty() || password.length == 0) {
                    JOptionPane.showMessageDialog(frame, 
                        "必須項目を入力してください", 
                        "エラー", 
                        JOptionPane.ERROR_MESSAGE);
                    return;
                }

                if (!Arrays.equals(password, confirmPassword)) {
                    JOptionPane.showMessageDialog(frame, 
                        "パスワードが一致しません", 
                        "エラー", 
                        JOptionPane.ERROR_MESSAGE);
                    return;
                }

                JOptionPane.showMessageDialog(frame, 
                    String.format("登録完了!\n名前: %s\n性別: %s", name, gender),
                    "成功",
                    JOptionPane.INFORMATION_MESSAGE);
            });

            clearButton.addActionListener(e -> {
                nameField.setText("");
                passField.setText("");
                confirmPassField.setText("");
                genderCombo.setSelectedIndex(0);
            });

            buttonPanel.add(clearButton);
            buttonPanel.add(registerButton);

            mainPanel.add(formPanel, BorderLayout.CENTER);
            mainPanel.add(buttonPanel, BorderLayout.SOUTH);

            frame.add(mainPanel);
            frame.setVisible(true);
        });
    }
}

次の章では、「簡単なダイアログ(JOptionPane)」について学び、ユーザーとの対話をより豊かにする方法を習得します。