CodeGym /コース /JAVA 25 SELF /Swing と AWT のイベント:基礎と例

Swing と AWT のイベント:基礎と例

JAVA 25 SELF
レベル 50 , レッスン 1
使用可能

1. Swing と AWT のごく簡単な入門

もし Java が自動車だとしたら、Swing と AWT はその「メーター類」と「ハンドル」にあたります。AWT (Abstract Window Toolkit) は Java でデスクトップアプリを作るための最初のライブラリです。OS のネイティブな UI 部品を使うため、Windows、Linux、Mac で見た目が異なります。

Swing は AWT の上に作られた、完全に Java で実装されたより新しいライブラリです。Swing は見た目がよく柔軟で、追加機能も豊富で、どのプラットフォームでも同じ外観になります(まあ、ほぼ)。どちらの場合も、すべての UI 要素(ボタン、テキストフィールド、チェックボックスなど)がイベントに対応しています。

この講義では Swing を使います。初心者に扱いやすく、学習用のサンプルでもよく登場するからです。最も一般的なタスクである「ボタン押下への反応」を例に、イベント処理の仕組みを見ていきましょう。

ボタンの作成

Swing ではボタンは次のように作成します:

JButton button = new JButton("押してね!");

ここで「押してね!」はボタンに表示される文字列です。

リスナーの追加

クリックに反応するには、イベントにリスナーを「登録」します:

button.addActionListener(new MyActionListener());

ところでこの MyActionListener とは何者でしょうか。これは ActionListener インターフェースを実装したクラスです:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class MyActionListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("ボタンが押されました!");
    }
}

ユーザーがボタンを押すと、Swing は addActionListener で登録されたすべてのリスナーの actionPerformed メソッドを呼び出します。

全体例:ボタン付きの簡単なウィンドウ

すべてを組み合わせて、動くアプリケーションを作ってみましょう:

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

public class SimpleButtonApp {
    public static void main(String[] args) {
        JFrame frame = new JFrame("イベントの例");
        JButton button = new JButton("押してね!");

        // ボタンにリスナーを追加
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("ボタンが押されました!");
                JOptionPane.showMessageDialog(frame, "やった!ボタンが押されました!");
            }
        });

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(button);
        frame.setSize(300, 200);
        frame.setVisible(true);
    }
}

ここでの流れ:

  • ウィンドウ(JFrame)を作成します。
  • ボタン(JButton)を作成します。
  • リスナーを追加します(別ファイルを増やさないため匿名クラスを使用)。
  • actionPerformed の中でコンソール出力とポップアップ(JOptionPane)を表示します。
  • ボタンをウィンドウに追加し、ウィンドウをユーザーに表示します。

ぜひ試してみてください。このコードをコピーして実行し、ボタンを押してみましょう!

2.匿名クラスとラムダ式

現代の Java コードでハンドラ 1 つのために別クラスを書くのは、パンを買うのに戦車で出かけるようなものです。匿名クラスラムダ式を使う方がずっと便利です。

匿名クラス

このやり方はすでに上で見ました:

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // ハンドラ処理
    }
});

ここではクラスをその場で、名前なしで宣言しています。

ラムダ式 (Java 8+)

リスナーのインターフェースが関数型(抽象メソッドが 1 つだけ)の場合は、ラムダを使えます:

button.addActionListener(e -> {
    System.out.println("ラムダでボタンが押されました!");
});

本体が 1 行なら、さらに短くできます:

button.addActionListener(e -> System.out.println("ラムダ: ボタンが押されました!"));

これはコードが短くなるだけでなく、より読みやすくもなります。豆知識: ActionListener は関数型インターフェースです。なぜなら、メソッドは actionPerformed の 1 つだけだからです。

4. そのほかのイベントの種類

世界はボタンだけではありません!Swing と AWT のほぼすべての UI 要素には、それぞれのイベントがあります。代表的なものを見てみましょう。

マウスイベント: MouseListener と MouseAdapter

マウスクリックに反応したい場合は、MouseListener を使います:

button.addMouseListener(new MouseListener() {
    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("ボタンがマウスクリックされました!");
    }
    // 残りのメソッドは空のままで構いません
    @Override public void mousePressed(MouseEvent e) {}
    @Override public void mouseReleased(MouseEvent e) {}
    @Override public void mouseEntered(MouseEvent e) {}
    @Override public void mouseExited(MouseEvent e) {}
});

1 つのハンドラのために 5 つの空メソッドを書くのは不便です。そのために MouseAdapter があります:

button.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("(アダプタ経由で)ボタンがクリックされました!");
    }
});

MouseAdapter はインターフェースのすべてのメソッドを実装しており、必要なものだけをオーバーライドすれば OK です。

キーボードイベント: KeyListener/KeyAdapter

キー押下を捕捉したい場合:

button.addKeyListener(new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
        System.out.println("キーが押されました: " + e.getKeyChar());
    }
});

テキスト変更イベント: DocumentListener

テキストフィールド(JTextFieldJTextArea)には専用のリスナーがあります:

JTextField textField = new JTextField();
textField.getDocument().addDocumentListener(new DocumentListener() {
    @Override
    public void insertUpdate(DocumentEvent e) {
        System.out.println("テキストが変更されました: " + textField.getText());
    }
    @Override public void removeUpdate(DocumentEvent e) {}
    @Override public void changedUpdate(DocumentEvent e) {}
});

ちなみに、多くのイベントにはアダプタが用意されており、空メソッドを書かずに済みます。

5. 実践: ウィンドウとボタンのミニ例

最も簡単な GUI アプリを作りましょう。ボタンを押すたびにカウンタが増え、メッセージを表示します。

例: クリックカウンタ

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

public class ClickCounterApp {
    public static void main(String[] args) {
        JFrame frame = new JFrame("クリックカウンタ");
        JButton button = new JButton("押してね!");
        JLabel label = new JLabel("回数: 0");
        // クリック回数のカウンタ(final か effectively final である必要あり)
        final int[] count = {0};

        button.addActionListener(e -> {
            count[0]++;
            label.setText("回数: " + count[0]);
        });

        frame.setLayout(new FlowLayout());
        frame.add(button);
        frame.add(label);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(250, 100);
        frame.setVisible(true);
    }
}

解説:

  • ウィンドウ、ボタン、カウンタ表示用のラベルを作成します。
  • ラムダの final/実質 final 変数の制約を回避するため、1 要素の配列(final int[] count = {0};)を使います。
  • ボタンが押されるたびにカウンタを増やし、ラベルのテキストを更新します。

練習アイデア: 5 回ごとにボタンの色を変えてみましょう!

6. 内部でのイベントモデルの仕組み

少し内部を覗いてみましょう。次を呼び出すと:

button.addActionListener(listener);

ボタン(JButton オブジェクト)はあなたのリスナーを内部リストに追加します。 ユーザーがボタンを押すと、内部では次のことが起こります:

  1. ボタンがイベントオブジェクト(ActionEvent)を作成します。
  2. ボタンがリスナーのリストを走査し、各リスナーの actionPerformed メソッドを呼び出します。
  3. あなたのハンドラが必要な処理(たとえばラベルの更新)を実行します。

重要なポイント: 各イベントには任意の数のリスナーを登録できます。同じボタンに複数のハンドラを追加すると、順番に呼び出されます。

7. 図解: イベント処理の流れ

graph TD
    A[ユーザーがボタンを押す] --> B{JButton}
    B --> C[ActionEvent を作成]
    C --> D[すべてのリスナーの actionPerformed を呼び出す]
    D --> E[ハンドラが処理を実行]

7. Swing と AWT のイベントでよくあるミス

エラー No.1: リスナーの登録忘れ。 ボタンが反応しないのは、addActionListener を呼び忘れているからです。

エラー No.2: ハンドラ内で重い処理。 ハンドラで長いループを回したりネットワークからのダウンロードを行うと、UI が「フリーズ」します。長時間の処理には別スレッドや SwingWorker を使いましょう。

エラー No.3: final/実質 final でない変数をラムダから変更しようとする。 ラムダ内で使用できるのは final または「実質 final」の変数だけです。カウンタには配列や専用クラス(本格的にやるなら AtomicInteger)を使いましょう。

エラー No.4: リスナーの削除忘れ。 コンポーネントを削除したのにリスナーを外していないと、メモリリークの可能性があります。不要になったら購読を解除しましょう。

エラー No.5: インターフェースの全メソッドを実装していない。 たとえば MouseListener を直接実装する場合は、すべてのメソッドを忘れずに。アダプタ(MouseAdapterKeyAdapter)を使う方が無難です。

1
タスク
JAVA 25 SELF, レベル 50, レッスン 1
ロック未解除
スマートホームの挨拶 🏡
スマートホームの挨拶 🏡
1
タスク
JAVA 25 SELF, レベル 50, レッスン 1
ロック未解除
サーモスタットの有効化 🌡️
サーモスタットの有効化 🌡️
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION