Lab10_calculate.jpg
Design and code a Swing GUI calculator. You can use Display 17.19 as a starting
point, but your calculator will be more sophisticated. Your calculator will
have two text fields that the user cannot change: One labeled "Result" will contain
the result of performing the operation, and the other labeled "Operand" will
be for the user to enter a number to be added, subtracted, and so forth from the
result. The user enters the number for the "Operand" text field by clicking buttons
labeled with the digits 0 through 9 and a decimal point, just as in a real
calculator. Allow the operations of addition, subtraction, multiplication, and
division. Use a GridLayout manager to produce a button pad that looks similar
to the keyboard on a real calculator.
When the user clicks a button for an operation: the operation is performed, the
"Result" text field is updated, and the "Operand" text field is cleared. Include a
button labeled "Reset" that resets the "Result" to 0.0. Also include a button
labeled "Clear" that resets the "Operand" text field so it is blank.
Hint: Define an exception class named DivisonByZeroException. Have your code
throw and catch a DivisonByZeroException if the user attempts to “divide by
zero.” Your code will catch the DivisonByZeroException and output a suitable
message to the "Operand" text field. The user may then enter a new substitute
number in the "Operand" text field. Since values of type double are, in effect,
approximate values, it makes no sense to test for equality with 0.0. Consider an
operand to be “equal to zero” if it is in the range −1.0e−10 to +1.0e−10.
我寫了一個簡單版的計算機, 以及可以進行五則運算的計算機, 如上圖的左與右
import Calculator.*;
public class Demo {
public static void main(String[] args) {
Calculator gui = new Calculator();
gui.setVisible(true);
CalculatorII gui2 = new CalculatorII();
gui2.setVisible(true);
}
}
package Calculator;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Calculator extends JFrame {
public static final int WIDTH = 250;
public static final int HEIGHT = 400;
public String resultText = "0.0";
public String operandText = "";
public String lastOperator;
public JTextField result = new JTextField(30);
public JTextField operand = new JTextField(30);
public boolean hasOperand, hasOperator, hasPoint, errMsg;
public double resultAns = 0.0;
public class NumberListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//清除錯誤訊息
if (errMsg == true) {
operandText = "";
resultText = "" + resultAns;
errMsg = false;
}
String command = e.getActionCommand();
//限定使用者輸入一個小數位數
if (command.equals(".")) {
if (hasPoint == false) {
operandText += command;
hasPoint = true;
}
} else
operandText += command;
hasOperand = true;
result.setText(resultText);
operand.setText(operandText);
}
}
public class OperatorListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (errMsg == true) {
operandText = "";
resultText = "" + resultAns;
errMsg = false;
}
String command = e.getActionCommand();
if (command.equals("=")) {
//進行運算與例外處理
if (hasOperand == true) {
resultText += operandText;
result.setText(resultText);
}
try {
double tmp = Double.parseDouble(operandText);
if (lastOperator == null) {
} else if (lastOperator.equals("+")) {
resultAns += tmp;
} else if (lastOperator.equals("-")) {
resultAns -= tmp;
} else if (lastOperator.equals("*")) {
resultAns *= tmp;
} else {
if (Math.abs(tmp) <= 1E-10) {
throw new DivisonByZeroException();
}
resultAns /= tmp;
}
resultText = "" + resultAns;
operandText = "";
} catch (DivisonByZeroException ee) {
operandText = "無法除以0";
resultAns = 0.0;
errMsg = true;
}
lastOperator = null;
hasPoint = false;
hasOperand = false;
hasOperator = false;
} else if (hasOperator == true) {
//修改運算子
resultText = resultText.substring(0, resultText.length() - 1);
resultText += command;
lastOperator = command;
} else {
resultText += command;
lastOperator = command;
hasOperator = true;
}
result.setText(resultText);
operand.setText(operandText);
}
}
public class OtherListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
switch (command) {
case "Clear":
operandText = "";
hasOperand = false;
hasPoint = false;
break;
case "Reset":
resultText = "0.0";
resultAns = 0.0;
hasOperator = false;
lastOperator = null;
break;
}
operand.setText(operandText);
result.setText(resultText);
}
}
public Calculator() {
super("My Calculator");
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setResizable(false);
result.setText(resultText);
result.setEditable(false);
result.setBounds(60, 0, WIDTH, 30);
add(result);
operand.setText(operandText);
operand.setEditable(false);
operand.setBounds(60, 30, WIDTH, 30);
add(operand);
JLabel lab = new JLabel("Result", JLabel.RIGHT);
lab.setLabelFor(result);
lab.setBounds(0, 0, 60, 30);
add(lab);
lab = new JLabel("Operand", JLabel.RIGHT);
lab.setLabelFor(operand);
lab.setBounds(0, 30, 60, 30);
add(lab);
JPanel panel = new JPanel();
JButton button;
panel.setLayout(new GridLayout(4, 3));
for (int i = 7; i >= -2; i -= 3) {
for (int j = 0; j < 3; j++) {
if (i + j >= 0) {
button = new JButton("" + (i + j));
button.setSize(50, 50);
button.addActionListener(new NumberListener());
panel.add(button);
}
}
}
button = new JButton(".");
button.setSize(50, 50);
button.addActionListener(new NumberListener());
panel.add(button);
panel.setBounds(0, 60, 200, 200);
add(panel);
panel = new JPanel();
panel.setLayout(new GridLayout(5, 1));
String[] operator = { "=", "+", "-", "*", "/" };
for (int i = 0; i < 5; i++) {
button = new JButton(operator[i]);
button.setSize(50, 50);
button.addActionListener(new OperatorListener());
panel.add(button);
}
panel.setBounds(200, 60, 50, 200);
add(panel);
button = new JButton("Reset");
button.addActionListener(new OtherListener());
button.setBounds(0, 300, 125, 50);
add(button);
button = new JButton("Clear");
button.addActionListener(new OtherListener());
button.setBounds(125, 300, 125, 50);
add(button);
hasOperand = false;
hasOperator = false;
hasPoint = false;
errMsg = false;
resultAns = 0.0;
lastOperator = null;
}
}
/*
* 1. 必須將 setLayout 改成 null, 才能選擇按鈕的大小, 否則一律用預設值
* 2. 使用 setBounds 設定物件在視窗所在位置與寬高
* 3. setResizable 設定視窗不可修改大小
* 4. setEditable 設定 TextField 不可編輯
* 5. setLabelFor 設定為某個元件的 Label
*/
package Calculator;import javax.swing.*;import java.awt.*;import java.awt.event.*;public class CalculatorII extends JFrame { public static final int WIDTH = 250, HEIGHT = 380; public String resultText = "", operandText = ""; public JTextField result = new JTextField(30), operand = new JTextField(30); public boolean errMsg; public double resultAns = 0.0; public NumberListener numListener = new NumberListener(); public OperatorListener opeListener = new OperatorListener(); public class NumberListener implements ActionListener { public boolean hasNumber = false, hasPoint = false; public void actionPerformed(ActionEvent e) { if (errMsg == true) { operandText = ""; errMsg = false; } String cmd = e.getActionCommand(); if(cmd.equals(".")) { if(!hasPoint) { hasPoint = true; operandText += cmd; } } else { operandText += cmd; hasNumber = true; } operand.setText(operandText); } } public class OperatorListener implements ActionListener { public boolean hasOperator = false; public int rightBracket = 0; public void actionPerformed(ActionEvent e) { if (errMsg == true) { operandText = ""; errMsg = false; } String cmd = e.getActionCommand(); if(cmd.equals("=")) { if(numListener.hasNumber == true) { resultText += operandText; numListener.hasNumber = false; numListener.hasPoint = false; hasOperator = false; operandText = ""; } if(hasOperator == true) { resultText = resultText.substring(0, resultText.length()-2); hasOperator = false; } while(rightBracket > 0) { rightBracket--; resultText += ")"; } try { char[] in = new char[resultText.length()]; in = resultText.toCharArray(); resultAns = calculate(in); numListener.hasNumber = true; numListener.hasPoint = true; resultText = ""; operandText = String.format("%f", resultAns); numListener.hasNumber = true; } catch (DivisonByZeroException err) { resultText = ""; operandText = "無法除以0"; errMsg = true; } } else if(cmd.equals("(")) { if(numListener.hasNumber == true) { resultText += operandText; numListener.hasNumber = false; numListener.hasPoint = false; hasOperator = false; operandText = ""; } else { if(resultText.length() > 0) { int p = priority(resultText.charAt(resultText.length()-1)); if(p == 1 || p == 3 || p == 4) { rightBracket++; resultText += "("; hasOperator = false; } } else { rightBracket++; resultText += "("; hasOperator = false; } } } else if(cmd.equals(")")) { if(numListener.hasNumber == true) { resultText += operandText; numListener.hasNumber = false; numListener.hasPoint = false; hasOperator = false; operandText = ""; } if(rightBracket > 0 && hasOperator == false) { if(resultText.charAt(resultText.length()-1) == '(') resultText += "0"; rightBracket--; resultText += ")"; } } else { if(numListener.hasNumber == true) { if(resultText.length() > 0) { int p = priority(resultText.charAt(resultText.length()-1)); if(p == 2) resultText += "*"; } resultText += operandText; numListener.hasNumber = false; numListener.hasPoint = false; hasOperator = false; operandText = ""; } else { if(resultText.length() == 0) resultText += "0"; else if(resultText.charAt(resultText.length()-1) == '(') resultText += "0"; } if(hasOperator == true) { if(resultText.charAt(resultText.length()-1) == ')') rightBracket++; resultText = resultText.substring(0, resultText.length()-1); } resultText += cmd; hasOperator = true; } result.setText(resultText); operand.setText(operandText); } } public class OtherListener implements ActionListener { public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if(cmd.equals("Clear")) { operandText = ""; numListener.hasNumber = false; numListener.hasPoint = false; } else { resultText = ""; opeListener.hasOperator = false; opeListener.rightBracket = 0; } operand.setText(operandText); result.setText(resultText); } } public int priority(char c) { switch(c) { case '(':return 1; case ')':return 2; case '+':return 3; case '-':return 3; case '*':return 4; case '/':return 4; } return -1; } public double calculate(char[] in) throws DivisonByZeroException { double[] post = new double[100]; double[] stack = new double[100]; boolean[] diff = new boolean[100]; double tmp = 0.0; int sidx = -1, pidx = -1, g = 0; for(int i = 0; i < in.length; ) { while(i < in.length && in[i] >= '0' && in[i] <= '9') { tmp = tmp*10 + in[i]-'0'; i++; g = 1; } if(i < in.length && in[i] == '.') { i++; double t10 = 0.1; while(i < in.length && in[i] >= '0' && in[i] <= '9') { tmp += (in[i]-'0')*t10; i++; t10 /= 10; } g = 1; } if(g != 0) { post[++pidx] = tmp; diff[pidx] = true; tmp = 0; g = 0; } if(i >= in.length) break; int p = priority(in[i]); if(p != -1) { if(in[i] == ')') { while(sidx >= 0 && stack[sidx] != '(') { post[++pidx] = stack[sidx]; diff[pidx] = false; sidx--; } sidx--; } else { stack[++sidx] = in[i]; while(sidx >= 1 && priority((char)stack[sidx-1]) >= priority((char)stack[sidx]) && stack[sidx] != '(') { post[++pidx] = stack[sidx-1]; diff[pidx] = false; stack[sidx-1] = stack[sidx]; sidx--; } } i++; } } if(g != 0) { post[++pidx] = tmp; diff[pidx] = true; } while(sidx >= 0) { post[++pidx] = stack[sidx]; diff[pidx] = false; sidx--; } sidx = -1; for(int i = 0; i <= pidx; i++) { if(diff[i] == false) { switch((char)post[i]) { case '+':stack[sidx-1] += stack[sidx];sidx--;break; case '-':stack[sidx-1] -= stack[sidx];sidx--;break; case '*':stack[sidx-1] *= stack[sidx];sidx--;break; case '/': if(Math.abs(stack[sidx]) <= 1E-10) throw new DivisonByZeroException(); stack[sidx-1] /= stack[sidx];sidx--;break; } } else { stack[++sidx] = post[i]; } } return stack[0]; } public CalculatorII() { super("My CalculatorII"); setSize(WIDTH, HEIGHT); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(null); setResizable(false); result.setText(resultText); result.setEditable(false); result.setBounds(60, 0, WIDTH, 30); add(result); operand.setText(operandText); operand.setEditable(false); operand.setBounds(60, 30, WIDTH, 30); add(operand); JLabel lab; lab = new JLabel("Result", JLabel.CENTER); lab.setFont(new Font("", Font.PLAIN, 14)); lab.setLabelFor(result); lab.setBounds(0, 0, 60, 30); add(lab); lab = new JLabel("Operand", JLabel.CENTER); lab.setLabelFor(operand); lab.setFont(new Font("", Font.PLAIN, 14)); lab.setBounds(0, 30, 60, 30); add(lab); String[] name = { "7", "8", "9", "/", "(", "4", "5", "6", "*", ")", "1", "2", "3", "-", "=", "0", ".", "+" }; int[] x = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 2, 3 }; int[] y = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3 }; JPanel panel = new JPanel(); panel.setBounds(0, 70, WIDTH, 200); panel.setLayout(null); for (int i = 0; i < name.length; i++) { JButton button = new JButton(name[i]); Insets margin = new Insets(5, 5, 5, 5); int width = 45, length = 45; if (name[i].equals("=")) length += 50; if (name[i].equals("0")) width += 50; button.setMargin(margin); button.setFont(new Font("", Font.PLAIN, 18)); button.setBounds(x[i] * 50, y[i] * 50, width, length); if (Character.isDigit(name[i].charAt(0)) || name[i].charAt(0) == '.') button.addActionListener(numListener); else button.addActionListener(opeListener); panel.add(button); } add(panel); JButton button; button = new JButton("Reset"); button.addActionListener(new OtherListener()); button.setBounds(0, 280, 120, 50); add(button); button = new JButton("Clear"); button.addActionListener(new OtherListener()); button.setBounds(125, 280, 120, 50); add(button); errMsg = false; resultAns = 0.0; }}/* * 1. 必須將 setLayout 改成 null, 才能選擇按鈕的大小, 否則一律用預設值 * 2. 使用 setBounds 設定物件在視窗所在位置與寬高 * 3. setResizable 設定視窗不可修改大小 * 4. setEditable 設定 TextField 不可編輯 5. setLabelFor * 設定為某個元件的 Label * 5. Insets 為按鈕邊緣空白的操作 * * 2012/6/9 * 更改排版方法 * * 2012/6/10 * 新增中轉後, 後序運算, 自動補運算子與運算元 * java string.toCharArray() 不會補上空白字元 * 嘗試使用 .jar 附加數位簽章, 將此類轉成 extands JPanel 加入 JApplet * 但仍只能在本地進行, 客戶端仍有安全性提示, 但執行錯誤 * 更新科學符號表式法, 以防止字串分析錯誤 */
文章定位: