Skip to content
Code Blue プログラミング学習ノート
Java/Swing

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

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

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

ActionListenerは、ボタンがクリックされたときなど、ユーザーの操作に応じて処理を実行するためのイベントリスナーです。ボタンへActionListenerを登録すると、クリックされたタイミングでactionPerformed()メソッドが自動的に呼び出され、その中に記述した処理が実行されます。

event_handling

例えば、メッセージを表示したり、入力内容を取得したり、画面を更新したりする処理を記述できます。イベント処理はGUIアプリケーションの基本機能であり、ユーザーの操作に応じて画面の動作を変えるために欠かせません。近年では匿名クラスよりもラムダ式で記述されることが多いですが、ActionListenerの基本的な仕組みはどちらも同じです。

主要なコンポーネント

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

基本的なActionListenerの実装

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

このプログラムでは、ActionListenerを利用してボタンがクリックされたときの処理を実装する方法を学びます。ボタンにActionListenerを登録することで、ユーザーがボタンを押したタイミングでactionPerformed()メソッドが自動的に呼び出されます。

このプログラムでは、JOptionPane.showMessageDialog()を使用して「ボタンがクリックされました!」というメッセージを表示しています。ActionListenerは、ボタンのクリックをはじめとしたユーザーの操作に応じて処理を実行するための基本的な仕組みであり、GUIアプリケーションでは非常によく利用されます。

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以降)

このプログラムでは、ラムダ式を使用してActionListenerを実装する方法を学びます。ボタンにActionListenerを登録し、クリックされるとラムダ式の中に記述した処理が実行されます。

この例では、ボタンを押すとダイアログが表示され、「ラムダ式で処理されました」というメッセージが表示されます。ラムダ式は、匿名インナークラスよりも短く読みやすく記述できるため、現在のJavaではイベント処理を実装する際によく利用されています。ActionListenerの動作は匿名インナークラスと同じですが、コードを簡潔に記述できる点が大きな特徴です。

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()などテキスト変更

ActionEventベストプラクティス

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

1つのActionListenerで複数のボタンのクリックイベントを処理する方法を学びます。3つのボタンすべてに同じActionListenerを登録し、e.getSource()を使ってどのボタンが押されたのかを取得しています。

取得したボタンの文字列を判定し、switch文によって背景色を赤・緑・青に変更しています。このように、複数の部品で共通の処理を利用することで、同じようなコードを何度も記述する必要がなくなり、プログラムを簡潔で保守しやすくすることができます。

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の実装例

このプログラムでは、MouseListenerを利用してマウスの操作に応じた処理を実装する方法を学びます。今回はMouseAdapterを継承して必要なメソッドだけをオーバーライドしているため、すべてのイベント処理を記述する必要がありません。

パネルをクリックするとクリックした座標とクリック回数が表示され、マウスがパネルに入ると背景色が水色に変わり、外へ出ると元の色へ戻ります。このように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によるテキスト変更検知

このプログラムでは、DocumentListenerを利用してテキストボックスの内容が変更されたときに処理を実行する方法を学びます。JTextFieldにDocumentListenerを登録すると、文字の入力や削除が行われるたびにイベントが発生し、updateCount()が呼び出されます。

このメソッドでは入力された文字数を取得し、ラベルに現在の文字数を表示しています。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);

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

以下実践的な例で、Swingを使用したユーザー登録フォームの作成方法を学びます。

ユーザー名、パスワード、性別を入力し、「登録」ボタンを押すと入力内容を取得してチェックを行います。ユーザー名やパスワードが未入力の場合や、パスワードと確認用パスワードが一致しない場合はエラーメッセージを表示し、問題がなければ登録完了のメッセージを表示します。

また、「クリア」ボタンを押すと、入力された内容を初期状態に戻すことができます。このように複数のSwingコンポーネントとイベント処理を組み合わせることで、実用的な入力フォームを作成できるようになります。

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)」について学び、ユーザーとの対話をより豊かにする方法を習得します。