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

【Swingアプリ開発】電卓アプリの解答例

前回の電卓アプリの解答例を紹介した内容になります。電卓アプリの問題形式については前回の記事を参照してください。

以下は、Swingを使用した基本的な電卓アプリケーションの完全な実装例です。四則演算(加減乗除)とクリア機能を備えています。

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

public class SimpleCalculator {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            // 電卓フレームの作成
            JFrame frame = new JFrame("簡単な電卓");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(300, 400);
            frame.setLayout(new BorderLayout(5, 5));

            // 計算結果表示用のテキストフィールド
            JTextField display = new JTextField();
            display.setEditable(false);
            display.setHorizontalAlignment(JTextField.RIGHT);
            display.setFont(new Font("Arial", Font.BOLD, 24));
            frame.add(display, BorderLayout.NORTH);

            // ボタンパネルの作成
            JPanel buttonPanel = new JPanel();
            buttonPanel.setLayout(new GridLayout(4, 4, 5, 5));

            // 電卓ボタンのラベル
            String[] buttonLabels = {
                "7", "8", "9", "/",
                "4", "5", "6", "*",
                "1", "2", "3", "-",
                "C", "0", "=", "+"
            };

            // ボタンの作成と追加
            for (String label : buttonLabels) {
                JButton button = new JButton(label);
                button.setFont(new Font("Arial", Font.BOLD, 18));
                button.addActionListener(new CalculatorActionListener(display));
                buttonPanel.add(button);
            }

            frame.add(buttonPanel, BorderLayout.CENTER);
            frame.setVisible(true);
        });
    }
}

// 電卓のアクションリスナー
class CalculatorActionListener implements ActionListener {
    private JTextField display;
    private String firstNumber;
    private String operator;
    private boolean startNewNumber;

    public CalculatorActionListener(JTextField display) {
        this.display = display;
        this.firstNumber = "";
        this.operator = "";
        this.startNewNumber = true;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();

        if (command.charAt(0) >= '0' && command.charAt(0) <= '9') {
            // 数字ボタンが押された場合
            if (startNewNumber) {
                display.setText(command);
                startNewNumber = false;
            } else {
                display.setText(display.getText() + command);
            }
        } else if (command.equals("C")) {
            // クリアボタンが押された場合
            display.setText("0");
            firstNumber = "";
            operator = "";
            startNewNumber = true;
        } else if (command.equals("=")) {
            // イコールボタンが押された場合
            if (!operator.isEmpty() && !firstNumber.isEmpty()) {
                String secondNumber = display.getText();
                double result = calculate(
                    Double.parseDouble(firstNumber),
                    Double.parseDouble(secondNumber),
                    operator
                );
                display.setText(String.valueOf(result));
                operator = "";
                startNewNumber = true;
            }
        } else {
            // 演算子ボタンが押された場合
            if (!operator.isEmpty()) {
                // 既に演算子が選択されている場合は先に計算
                String secondNumber = display.getText();
                double result = calculate(
                    Double.parseDouble(firstNumber),
                    Double.parseDouble(secondNumber),
                    operator
                );
                display.setText(String.valueOf(result));
                firstNumber = String.valueOf(result);
            } else {
                firstNumber = display.getText();
            }
            operator = command;
            startNewNumber = true;
        }
    }

    // 計算を実行するメソッド
    private double calculate(double num1, double num2, String op) {
        switch (op) {
            case "+":
                return num1 + num2;
            case "-":
                return num1 - num2;
            case "*":
                return num1 * num2;
            case "/":
                if (num2 == 0) {
                    JOptionPane.showMessageDialog(display, "0で割ることはできません", "エラー", JOptionPane.ERROR_MESSAGE);
                    return num1;
                }
                return num1 / num2;
            default:
                return num2;
        }
    }
}

コードの解説

アプリ内で定義しているクラスの挙動についてそれぞれ解説を行なってます。

SimpleCalculatorクラス

SimpleCalculatorクラスは、Swingを使用して簡単な電卓アプリケーションを作成するメインクラスです。JFrameを作成し、計算結果を表示するJTextFieldと、数字や演算子を入力するためのボタンを配置しています。ボタンはGridLayoutを利用して4×4の表形式に並べられており、それぞれのボタンにはCalculatorActionListenerが登録されています。これにより、どのボタンが押されたかを判定し、適切な計算処理を実行できるようになっています。

CalculatorActionListenerクラス

CalculatorActionListenerクラスは、電卓のすべてのボタン操作を処理するイベントリスナークラスです。数字ボタンが押されると表示欄に数値を入力し、演算子ボタンが押されると最初の数値と演算子を保存します。=ボタンでは保存された数値と現在入力されている数値を使って計算を行い、その結果を表示します。また、Cボタンでは表示内容や保存していた計算情報を初期化し、最初から入力し直せる状態に戻します。さらに、演算子を続けて押した場合には、それまでの計算を先に実行して結果を保持することで、連続した計算にも対応しています。

calculate()メソッド

calculate()メソッドは、2つの数値と演算子を受け取り、実際の計算を行うメソッドです。switch文を利用して「+」「-」「*」「/」の各演算を判定し、それぞれの計算結果を返しています。また、割り算では0で割ることができないため、除数が0の場合はJOptionPaneでエラーメッセージを表示し、不正な計算を防いでいます。計算処理を専用のメソッドにまとめることで、プログラム全体の見通しが良くなり、機能の追加や修正もしやすい構成になっています。

この電卓アプリの特徴

基本機能

数字の入力(0~9)、四則演算(+、-、*、/)、クリア(C)、計算実行(=)といった基本的な電卓機能を備えており、GUIアプリケーションにおけるイベント処理の流れを学ぶことができます。

  • 数字入力(0-9)
  • 四則演算(+, -, *, /)
  • クリア機能(C)
  • 計算実行(=)

UI構成

画面は、上部に計算結果を表示するJTextField、中央に4×4のボタンを配置したシンプルな構成になっています。

  • 上部に計算結果表示用のテキストフィールド
  • 4x4のボタン配置(数字、演算子、クリア、イコール)

動作ロジック

数字ボタンを押すと数値が入力され、演算子ボタンで計算方法を選択し、=ボタンを押すことで計算結果が表示されます。また、Cボタンを押すと入力内容や計算状態が初期化され、最初から計算をやり直すことができます。

  • 数字ボタンで数値を入力
  • 演算子ボタンで計算方法を選択
  • イコールボタンで計算実行
  • クリアボタンでリセット

拡張可能なポイント

この基本実装をさらに発展させるためのアイデアは以下の内容です。

追加機能

  • 小数点ボタンの実装
  • パーセント計算機能
  • メモリ機能(M+, M-, MR, MC)

UI改善

  • ボタンの色分け(数字と演算子で色を変更)
  • ボタンのサイズ調整
  • キーボード入力のサポート

エラー処理の強化

  • オーバーフロー時の処理
  • 無効な入力への対応

コードの改良

  • 状態管理をStateパターンで実装
  • 計算ロジックを別クラスに分離

例えば、小数点ボタンを追加するには以下のように変更できます。buttonLabelsに「.(小数点)」ボタンを追加し、ユーザーが小数を入力できるようにしています。また、=ボタンを別の行へ移動することで、電卓のレイアウトをより見やすくしています。

さらに、actionPerformed()メソッドには小数点ボタンが押された場合の処理を追加しています。新しく数値を入力し始める状態で小数点が押された場合は、自動的に0.を表示して入力を開始します。一方、すでに数値を入力している場合は、表示されている数値に小数点が含まれていないときだけ.を追加します。

// ボタンラベルに小数点を追加
String[] buttonLabels = {
    "7", "8", "9", "/",
    "4", "5", "6", "*",
    "1", "2", "3", "-",
    "C", "0", ".", "+",
    "="  // イコールボタンを別の行に移動
};

// actionPerformedメソッドに小数点処理を追加
if (command.equals(".")) {
    if (startNewNumber) {
        display.setText("0.");
        startNewNumber = false;
    } else if (!display.getText().contains(".")) {
        display.setText(display.getText() + ".");
    }
}

これにより、1つの数値に複数の小数点が入力されることを防ぎ、正しい数値形式を維持できるようになっています。この電卓アプリはSwingの基本的なコンポーネントとイベント処理を理解するのに最適なサンプルです。まずはこの基本形を理解し、その後で機能拡張に挑戦してみてください。