質問に投稿したコードについては触れませんが、電卓のデモを作成するという全体的な目標を達成するのに役立ちます。
最初のステップは、問題を書き留めて、問題を明確に把握することです。
ディスプレイと、0 ~ 9 の数字と演算子 +、-、x、/、および = ボタンを備えたキーパッドを備えた電卓が必要です。電卓は、キーパッドから一連の数字を読み取り、次に数学演算子、次に別の一連の数字などを読み取る必要があります。途切れのない一連の数字はそれぞれ整数値に変換する必要があります。
計算機は、数学演算子を最初と 2 番目の整数値に適用した結果を計算する必要があります。追加の演算子と整数が入力された場合、数学演算子は前の計算の結果と追加の整数に適用されます。このプロセスは、等号ボタンが押されるまで続行する必要があります。キーパッドで数字を押すと、それまでに入力した数字に追加されたテキスト表示に表示されます。
演算子または等号ボタンが押されると、これは整数の入力の終了を知らせます。これで計算が完了すると、結果がディスプレイに表示されます。そうでない場合、整数は別の数字が押されるまでディスプレイに残ります。以前と同様に、表示がクリアされ、新しい桁が表示され、後続の桁が追加されます。
この説明から、いくつかの名詞を識別できます: Calculator、Button、Display、Keypad、Digit、Operator、Integer、Result ... およびいくつかの動詞: Read、Press、Convert、Calculate、Apply、Enter、Complete、Show、Remain、Clear 、表示、追加
これらは、プログラムに必要な状態と動作のアイデアを提供します。次に、実装でこれらをモデル化する方法を決定します。通常、名詞はクラス/インスタンス変数 (状態) として、動詞はメソッド (動作) としてモデル化できます。
考えられる設計の 1 つを次に示します。
Swing コンポーネントを使用してボタン/キーパッドおよびディスプレイを表す Calculator というクラス。整数/結果/数字を表すためにプリミティブな int 型を使用します。Operator を表すために Java 算術演算子を使用します。
これの骨を作り始めましょう:
public class Calculator {
private JFrame window;
private List<JButton> keypad;
private JLabel display;
private int result;
private StringBuffer digitsEntered;
private int integerEntered;
}
ここで、ボタンを読み取り/押す方法を検討する必要があります。アクティブ化に応答するように を設定し、JButton
そのイベントを Calculator クラスで定義したメソッドに接続する必要があります。
これを行う 1 つの方法は、 を作成し、JButton
それらにリスナーを追加することです。単一の引数を持つメソッドを定義することを強制するインターフェースをCalculator
実装することができます。inのコンストラクタを作成することで、これがどのように機能するかを確認できます。ActionListener
actionPerformed
ActionEvent
JButton
Calculator
public class Calculator implements ActionListener {
private JFrame window;
private List<JButton> keypad;
private JLabel display;
private int result;
private StringBuffer digitsEntered;
private int integerEntered;
public Calculator() {
JButton zeroButton = new JButton("0");
zeroButton.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
// this would get executed when zeroButton is pressed
}
}
ウィンドウをセットアップしてボタンを接続していないため、このコードはまだ何も実行しないことに注意してください。ただし、コードは、ボタンを押してコードを実行する方法を示す必要があります。
すべてをセットアップして、このコードを動作状態にしましょう。
public class Calculator implements ActionListener {
private JFrame window;
private List<JButton> keypad;
private JLabel display;
private int result;
private StringBuffer digitsEntered;
private int integerEntered;
public Calculator() {
window = new JFrame("Calculator");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton zeroButton = new JButton("0");
zeroButton.addActionListener(this);
window.add(zeroButton, BorderLayout.CENTER);
window.pack();
window.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
// this would get executed when zeroButton is pressed
JOptionPane.showMessageDialog(window, "Button pressed");
}
public static void main(String[] args) {
new Calculator();
}
}
OK、複数のボタンが必要です。ロード全体が必要です。数字を 0 から 9 にしましょう:
for (int digit = 0; digit <=9; digit++) {
JButton button = new JButton(Integer.toString(digit));
button.addActionListener(this);
window.add(button);
}
うーん、うまくいきませんでした。ウィンドウにボタンが 1 つしか表示されません。これは、必要としないデフォルトのウィンドウ レイアウトがあるためです。ボタンをグリッドに表示し、ウィンドウにグループ化します。JPanel
ボタンをまとめてグループ化する を作成し、パネルに を使用するGridLayout
と、パネルをウィンドウに追加できます。
public Calculator() {
window = new JFrame("Calculator");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel digitsPanel = new JPanel();
digitsPanel.setLayout(new GridLayout(4, 3));
for (int digit = 0; digit <=9; digit++) {
JButton button = new JButton(Integer.toString(digit));
button.addActionListener(this);
digitsPanel.add(button);
}
window.add(digitsPanel);
window.pack();
window.setVisible(true);
}
それは悪くありませんが、数字はテンキーに表示される通常の順序では表示されません。これは、左上から右下に追加された順序で表示されるためです。配列で必要な順序を指定することでこれを修正し、それを繰り返すことができます (これにはfor-eachスタイルのイテレータを使用します。これはより適切だからです)。これを行っている間、数学演算子と等号ボタンに対して同様のことを行い、それらをフレームに追加することもできます (ここでは、ウィンドウに使用するレイアウトについて明示し、 a を使用しますBorderLayout
)。
public Calculator() {
window = new JFrame("Calculator");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new BorderLayout());
JPanel digitsPanel = new JPanel();
digitsPanel.setLayout(new GridLayout(4, 3));
int[] digitOrder = new int[] { 7,8,9,4,5,6,1,2,3,0 };
for (int digit : digitOrder) {
JButton button = new JButton(Integer.toString(digit));
button.addActionListener(this);
digitsPanel.add(button);
}
window.add(digitsPanel, BorderLayout.CENTER);
JPanel operatorsPanel = new JPanel();
operatorsPanel.setLayout(new GridLayout(5,1));
String[] operators = new String[] { "+","-","x","/","=" };
for (String operator : operators) {
JButton button = new JButton(operator);
button.addActionListener(this);
operatorsPanel.add(button);
}
window.add(operatorsPanel, BorderLayout.EAST);
window.pack();
window.setVisible(true);
}
OK、コンポーネントはほぼ完成です。ディスプレイを追加するだけです。
...
private JLabel display;
...
public Calculator() {
window = new JFrame("Calculator");
...
display = new JLabel();
display.setHorizontalAlignment(JLabel.RIGHT);
display.setText("0");
window.add(display, BorderLayout.NORTH);
...
window.pack();
window.setVisible(true);
}
あとは、ボタンの押下に応答するロジックを実装するだけです。まず、数字が押された場合に何をする必要があるかを見てみましょう。Append 動詞と Show 動詞を処理し、その数字を入力に追加して表示する必要があります。
StringBuffer digitsEntered;
...
public Calculator() {
...
digitsEntered = new StringBuffer();
...
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
String buttonText = ((JButton)e.getSource()).getText();
if (Character.isDigit(buttonText.charAt(0))) {
digitsEntered.append(buttonText.charAt(0));
display.setText(digitsEntered.toString());
}
}
}
涼しい。ここで、Convert 動詞を実装して、数字を整数に変換する必要があります。これは、演算子または等号が押されたときに発生します。2 番目の整数が入力されたときにどのような計算を行うかを知るために、どの演算子が押されたかを覚えておく必要があります。
private String currentOperator;
...
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
String buttonText = ((JButton)e.getSource()).getText();
if (Character.isDigit(buttonText.charAt(0))) {
digitsEntered.append(buttonText.charAt(0));
display.setText(digitsEntered.toString());
} else {
integerEntered = Integer.parseInt(digitsEntered.toString());
digitsEntered.setLength(0); // clear out the input so a new integer can be entered
currentOperator = buttonText; // remember the operator
}
}
}
ここで、整数と演算子が既に保存されている場合に、演算子または等号が 2 回押されたときに実際に処理する必要があります。ここで、Calculate/Apply 動詞の + 部分を実装し、結果を表示できます。
...
} else {
if (currentOperator == null) {
integerEntered = Integer.parseInt(digitsEntered.toString());
} else {
int previousInteger = integerEntered;
integerEntered = Integer.parseInt(digitsEntered.toString());
if ("+".equals(currentOperator)) {
result = previousInteger + integerEntered;
display.setText(Integer.toString(result));
}
}
digitsEntered.setLength(0); // clear out the input so a new integer can be entered
currentOperator = buttonText; // remember the operator
}
...
これは正しくありません。これまでに入力されたすべての整数の合計ではなく、前の 2 つの整数の合計が結果に入れられます。result
最初の値をに保存してから、後続の各整数を に保存された値に追加する必要がありますresult
。previousInteger
これは、変数がもう必要ないことを意味し、if
との両方に重複したコードがあり、 のelse
前に実行できif
ます。
...
integerEntered = Integer.parseInt(digitsEntered.toString());
if (currentOperator == null) {
result = integerEntered;
} else {
if ("+".equals(currentOperator)) {
result = result + integerEntered;
display.setText(Integer.toString(result));
}
}
...
他の演算子を実装しましょう。
...
integerEntered = Integer.parseInt(digitsEntered.toString());
if (currentOperator == null) {
result = integerEntered;
} else {
if ("+".equals(currentOperator)) {
result = result + integerEntered;
} else if ("-".equals(currentOperator)) {
result = result - integerEntered;
} else if ("x".equals(currentOperator)) {
result = result * integerEntered;
} else if ("/".equals(currentOperator)) {
result = result / integerEntered;
} else if ("=".equals(currentOperator)) {
result = integerEntered;
} else {
// Unrecognised operator
}
display.setText(Integer.toString(result));
}
...
ここで = をリセットのように機能する演算子にして、新しい計算を開始できるようにします。= を押してから + (結果に数値を追加するため) を押しようとすると、エラーが発生することに気付くかもしれません。これは、入力に + 演算子の整数に変換する数字がないためです。この場合、計算をスキップすることでこれを解決できます。
...
if (digitsEntered.length() > 0) {
integerEntered = Integer.parseInt(digitsEntered.toString());
if (currentOperator == null) {
result = integerEntered;
} else {
if ("+".equals(currentOperator)) {
result = result + integerEntered;
} else if ("-".equals(currentOperator)) {
result = result - integerEntered;
} else if ("x".equals(currentOperator)) {
result = result * integerEntered;
} else if ("/".equals(currentOperator)) {
result = result / integerEntered;
} else if ("=".equals(currentOperator)) {
result = integerEntered;
} else {
// Unrecognised operator
}
display.setText(Integer.toString(result));
}
}
...
これまでの完全なコードは次のとおりです。0 による除算を処理せず、keypad
使用されることはなく、削除することもできますintegerEntered
。実際に必要なのはインスタンス変数ではなく、ローカル変数のみです。ただし、コードはほとんど問題なく動作するはずです。問題が見つかった場合はお知らせください。私はよりクリーンなバージョン (私が行った最初の実装) も持っていますが、説明するのはそれほど単純ではありませんでした。
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Calculator implements ActionListener {
private JFrame window;
private List<JButton> keypad;
private JLabel display;
private int result;
private StringBuffer digitsEntered;
private int integerEntered;
private String currentOperator;
public Calculator() {
window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new BorderLayout());
digitsEntered = new StringBuffer();
display = new JLabel();
display.setHorizontalAlignment(JLabel.RIGHT);
display.setText("0");
window.add(display, BorderLayout.NORTH);
JPanel digitsPanel = new JPanel();
digitsPanel.setLayout(new GridLayout(4, 3));
int[] digitOrder = new int[] { 7,8,9,4,5,6,1,2,3,0 };
for (int digit : digitOrder) {
JButton button = new JButton(Integer.toString(digit));
button.addActionListener(this);
digitsPanel.add(button);
}
window.add(digitsPanel, BorderLayout.CENTER);
JPanel operatorsPanel = new JPanel();
operatorsPanel.setLayout(new GridLayout(5,1));
String[] operators = new String[] { "+","-","x","/","=" };
for (String operator : operators) {
JButton button = new JButton(operator);
button.addActionListener(this);
operatorsPanel.add(button);
}
window.add(operatorsPanel, BorderLayout.EAST);
window.pack();
window.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
String buttonText = ((JButton)e.getSource()).getText();
if (Character.isDigit(buttonText.charAt(0))) {
digitsEntered.append(buttonText.charAt(0));
display.setText(digitsEntered.toString());
} else {
if (digitsEntered.length() > 0) {
integerEntered = Integer.parseInt(digitsEntered.toString());
if (currentOperator == null) {
result = integerEntered;
} else {
if ("+".equals(currentOperator)) {
result = result + integerEntered;
} else if ("-".equals(currentOperator)) {
result = result - integerEntered;
} else if ("x".equals(currentOperator)) {
result = result * integerEntered;
} else if ("/".equals(currentOperator)) {
result = result / integerEntered;
} else if ("=".equals(currentOperator)) {
result = integerEntered;
} else {
// Unrecognised operator
}
display.setText(Integer.toString(result));
}
}
digitsEntered.setLength(0); // clear out the input so a new integer can be entered
currentOperator = buttonText; // remember the operator
}
}
}
public static void main(String[] args) {
new Calculator();
}
}
これは、よりクリーンですが、より複雑なバージョンです。
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class CalculatorDemo extends JFrame {
private static final long serialVersionUID = 1L;
private StringBuffer inputBuffer = new StringBuffer();
private String queuedOperator = null;
private int leftHandSide = 0;
private JLabel inputDisplay;
private JLabel operatorIndicator;
private class DigitButtonAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final int digit;
public DigitButtonAction(final int digit) {
super(Integer.toString(digit));
this.digit = digit;
}
@Override
public void actionPerformed(ActionEvent e) {
enterDigit(digit);
}
}
private class OperatorButtonAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final String operator;
public OperatorButtonAction(final String operator) {
super(operator);
this.operator = operator;
}
@Override
public void actionPerformed(ActionEvent e) {
performOperation(operator);
}
}
public CalculatorDemo() {
super("Calculator");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setSize(100, 200);
// Create display text field
inputDisplay = new JLabel();
inputDisplay.setHorizontalAlignment(JLabel.RIGHT);
inputDisplay.setText(Integer.toString(leftHandSide));
operatorIndicator = new JLabel();
operatorIndicator.setBorder(new EmptyBorder(0, 4, 0, 4));
final JPanel display = new JPanel();
display.setLayout(new BorderLayout());
display.add(inputDisplay, BorderLayout.CENTER);
display.add(operatorIndicator, BorderLayout.WEST);
// Create number buttons
final JPanel digitPanel = new JPanel();
digitPanel.setLayout(new GridLayout(4,3));
final int[] digitKeyOrder = new int[] { 7,8,9,4,5,6,1,2,3 };
for (int digit : digitKeyOrder) {
digitPanel.add(new JButton(new DigitButtonAction(digit)));
}
digitPanel.add(new JPanel()); // Blank spacer panel
digitPanel.add(new JButton(new DigitButtonAction(0)));
// Create operators
final String[] OPERATORS = { "+","-","*","/","=" };
final JPanel operatorPanel = new JPanel();
operatorPanel.setLayout(new GridLayout(OPERATORS.length, 1));
for (String op : OPERATORS) {
operatorPanel.add(new JButton(new OperatorButtonAction(op)));
}
add(digitPanel, BorderLayout.CENTER);
add(operatorPanel, BorderLayout.EAST);
add(display, BorderLayout.NORTH);
pack();
}
private void enterDigit(final int digit) {
if (digit == 0 && inputBuffer.length() == 0) return;
inputBuffer.append(Integer.toString(digit));
inputDisplay.setText(inputBuffer.toString());
}
private int calculate(final int leftHandSide, final String operator, final int rightHandSide) {
if (operator == null) return rightHandSide;
else if ("+".equals(operator)) return leftHandSide + rightHandSide;
else if ("-".equals(operator)) return leftHandSide - rightHandSide;
else if ("*".equals(operator)) return leftHandSide * rightHandSide;
else if ("/".equals(operator)) return leftHandSide / rightHandSide;
else if ("=".equals(operator)) return rightHandSide;
else {
throw new IllegalStateException("Unrecognised operator " + operator);
}
}
private void performOperation(final String operator) {
try {
final int rightHandSide = Integer.parseInt(inputBuffer.toString());
leftHandSide = calculate(leftHandSide, queuedOperator, rightHandSide);
} catch (NumberFormatException e) {
// Ignore failure to parse inputBuffer to integer
// calculate() not called, just carry on and clear the
// inputBuffer and queue a new operator
} catch (ArithmeticException e) {
// Divide by 0 in calculate()
operatorIndicator.setText("");
inputDisplay.setText(e.getMessage());
queuedOperator = null;
return;
} catch (IllegalStateException e) {
// Unrecognised operator
operatorIndicator.setText("");
inputDisplay.setText(e.getMessage());
queuedOperator = null;
return;
}
inputBuffer.setLength(0); // Clear inputBuffer
queuedOperator = operator; // Queue next operator
// Update display
operatorIndicator.setText(queuedOperator);
inputDisplay.setText(Integer.toString(leftHandSide));
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new CalculatorDemo().setVisible(true);
}
});
}
}