簡易計算器
1.任務介紹
- 學會分析“簡易計算器”任務的實現思路;
- 根據思路獨立完成“簡易計算器”的源代碼編寫、編譯和運行;
- 掌握正則表達式來判定數字鍵或者數據是否合法;
- 掌握String類常用方法的使用,如:contains方法等;
- 掌握Java異常處理機制;
- 熟練掌握Swing包(JTextField控件、JButton控件和控件數組)的使用,以及常用佈局方式的使用;
- 掌握GUI開發過程中如何處理組件上發生的界面事件。
2.運行結果
3.實現思路
界面佈局實現思路:
- 根據實驗要求,利用GridBagLayout佈局將每個組件放在合適的位置,利用GridBagConstraints類中的Insets方法實現組件間隔;
- 利用數組存放每個組件顯示的文本。
事件處理實現思路:
- 設計ComputerListener接口繼承按鈕觸發事件ActionListener接口以增加其抽象方法實現將界面事件傳至PoliceListen類(PoliceListen類實現接口ComputerListener)做事件處理。
計算功能實現思路:
【輸入合法機制】
- 避免第一位爲符號: 設置判斷當第一位按非數字使不處理 ;
- 當第一位爲零,第二位也爲零:設置判斷當第一位爲零時輸入數字無效 ;
- 避免首位爲零,其後出現多個零(即0001):判斷該輸入的倒數第二位是否爲符號,倒數第一位是否爲0,在對按鈕0。是則不做處理;
- 避免輸出數字不合法(多個小數點 即6.6.6):利用循環以符號位爲分割線,判該數字是否存在已存在小數點 即 每個運算符號後的數字至多存在一個小數點;
- 排除多符號一起串連(即8+9+6/5): 點擊運算符觸發事件並判斷前一位是否爲符號,是則不做處理。
【計算字符串】
-
判斷最後一位是否爲運算符: 利用String類中的charAt()方法提取最後一位進行判斷,是則提示錯誤,否則運算;
-
字符和數字分離: 兩次利用StringTokenizer類進行字符串提取分析分別得到數字序列和運算符序列;
-
將數字序列和運算符序列存放在兩個鏈表中鏈表的刪除較爲便利 ;
-
根據優先級計算:設置兩個循環(當符號鏈表中的數據不爲空則繼續),第一個循環計算所有得乘除,即符號前後得兩個數乘除,結果放在第一個數中刪除第一個數和刪除符號;第二個循環計算所有的加減,結果放在第一個數中刪除第一個數和刪除符號。
4.UML圖
5.實現代碼
Text.java
package calculator;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
PoliceListen policeListen = new PoliceListen();
Win win = new Win();
win.setComputerListener(policeListen);
}
}
Win.java(窗口 View)
package calculator;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Win extends JFrame {
JTextField jTextField;
JTextArea jTextArea;
JButton jButton[] = new JButton[20];
JLabel jLabel;
ComputerListener computerListener;
public Win() {
init();
setTitle("計算器");
setSize(600, 600);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
GridBagLayout layout = new GridBagLayout();
this.setLayout(layout);
String[] strings = { "7", "8", "9", "/", "C", "4", "5", "6", "*", "Sqrt", "1", "2", "3", "-", "1/X", "+/-", "0",
".", "+", "=" };
for (int i = 0; i < jButton.length; i++) {
jButton[i] = new JButton(strings[i]);
// this.add(jButton[i]);
}
jTextArea = new JTextArea();
JScrollPane jScrollPane = new JScrollPane(jTextArea);
jTextField = new JTextField();
jLabel = new JLabel();
GridBagConstraints s = new GridBagConstraints();// 定義一個GridBagConstraints,
s.fill = GridBagConstraints.BOTH;
s.gridwidth = 1;
s.gridheight = 6;
s.weightx = 0;
s.weighty = 0;
s.insets = new Insets(5, 5, 2, 2);
s.ipadx = 200;
s.ipady = 10;
// jTextArea.setSize();
layout.setConstraints(jScrollPane, s);
this.add(jScrollPane);
s.ipadx = 10;
s.ipadx = 10;
// this.add(jTextArea);
s.gridwidth = 5;
s.gridheight = 1;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jTextField, s);
this.add(jTextField);
JPanel jPanel1 = new JPanel();
s.gridwidth = 0;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jPanel1, s);
this.add(jPanel1);
for (int i = 1; i < jButton.length + 1; i++) {
if (i % 5 == 0) {
s.gridwidth = 1;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jButton[i - 1], s);
this.add(jButton[i - 1]);
jPanel1 = new JPanel();
s.gridwidth = 0;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jPanel1, s);
this.add(jPanel1);
} else {
s.gridwidth = 1;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jButton[i - 1], s);
this.add(jButton[i - 1]);
}
}
}
void setComputerListener(ComputerListener computerListener) {
this.computerListener = computerListener;
computerListener.setJTextArea(jTextArea);
computerListener.setJTextField(jTextField);
for (int i = 0; i < jButton.length; i++) {
computerListener.setJBTextbotton(jButton);
jButton[i].addActionListener(computerListener);
}
}
}
PoliceListen.java(Controller)
package calculator;
import java.awt.event.ActionEvent;
import java.util.LinkedList;
import java.util.StringTokenizer;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class PoliceListen implements ComputerListener {
JTextArea jTextArea;
JTextField jTextField;
JButton jButton[] = new JButton[20];
double answer = 0;
@Override
public void actionPerformed(ActionEvent e) {
Operation(e);
}
void Operation(ActionEvent e) {
if (e.getActionCommand().equals("C")) {// 輸入框置空
jTextField.setText(null);
}
if (jTextField.getText().length() == 0) {// 保證第一位爲數字
if (e.getActionCommand().matches("[\\d]")) {
jTextField.setText(e.getActionCommand());
}
} else if (jTextField.getText().length() == 1 // 在第一位爲零情況下,第二位非數字排除開始 001的情況
&& ((jTextField.getText().charAt(0) + "").equals("0")) && e.getActionCommand().matches("[\\d]")) {
} else if (jTextField.getText().length() == 1 // 在第一位爲零情況下,第二位非數字排除開始 001的情況
&& !(jTextField.getText().charAt(0) + "").equals("0")) {
if (!e.getActionCommand().equals("=")) {
jTextField.setText(jTextField.getText() + e.getActionCommand());
}
} else {
// 保證第三位開始若輸入"0" 判斷前兩位是否爲符號,前一位是否爲"0" 排除 (+-*/00)情況
if (e.getActionCommand().matches("[\\d]")) {
String string2 = jTextField.getText().charAt(jTextField.getText().length() - 2) + "";
String string1 = jTextField.getText().charAt(jTextField.getText().length() - 1) + "";
if ((string2.equals("+") || string2.equals("/") || string2.equals("*") || string2.equals("-"))
&& string1.equals("0")) {
} else {
jTextField.setText(jTextField.getText() + e.getActionCommand());
}
}
// 以符號位爲分割點 保證輸入"數字"合法
if (e.getActionCommand().equals(".")) {
int count = 0;
for (int i = 0; i < jTextField.getText().length(); i++) {
String string = jTextField.getText().charAt(i) + "";
if (string.equals(".")) {
count = 1;
}
if (string.equals("+") || string.equals("/") || string.equals("*") || string.equals("-")) {
count = 0;
}
}
if (count == 0) {
jTextField.setText(jTextField.getText() + e.getActionCommand());
}
}
if (e.getActionCommand().equals("+") || e.getActionCommand().equals("/") || e.getActionCommand().equals("*")
|| e.getActionCommand().equals("-")) {
String string = String.valueOf(jTextField.getText().charAt(jTextField.getText().length() - 1));
if (string.matches("[\\d]")) {
jTextField.setText(jTextField.getText() + e.getActionCommand());
}
}
if (e.getActionCommand().equals("=")) {
String lastFlagString = jTextField.getText().charAt(jTextField.getText().length() - 1) + "";
if (lastFlagString.matches("[\\d]")) {
calculate();
} else {
jTextField.setText("輸入非法,以符號結尾");
}
}
}
if (e.getActionCommand().equals("+/-")) {
jTextArea.append("+/- :" + answer + "=" + -answer + "\n");
}
if (e.getActionCommand().equals("1/X")) {
if (answer != 0) {
jTextArea.append("1/X" + answer + "=" + 1 / answer + "\n");
} else {
jTextArea.append("除數爲零\n");
}
}
if (e.getActionCommand().equals("Sqrt")) {
jTextArea.append("Sqrt:" + answer + "=" + Math.sqrt(answer) + "\n");
}
}
void calculate() {
LinkedList<Double> operater_Number = new LinkedList<Double>();
LinkedList<String> operater_Flag = new LinkedList<String>();
StringTokenizer fenxi_Number = new StringTokenizer(jTextField.getText(), "+-*/");
StringTokenizer fenxi_Flag = new StringTokenizer(jTextField.getText(), "0123456789.");
int count_Number = fenxi_Number.countTokens();
for (int i = 0; i < count_Number; i++) {
operater_Number.add(Double.parseDouble(fenxi_Number.nextToken()));
}
int count_Flag = fenxi_Flag.countTokens();
for (int i = 0; i < count_Flag; i++) {
operater_Flag.add(fenxi_Flag.nextToken());
}
while (operater_Flag.size() != 0 && operater_Number.size() > 1) {
for (int i = 0; i < operater_Flag.size(); i++) {
boolean exit = false;
if (operater_Flag.get(i).equals("*")) {
operater_Number.set(i, operater_Number.get(i) * operater_Number.get(i + 1));
exit = true;
}
if (operater_Flag.get(i).equals("/")) {
operater_Number.set(i, (operater_Number.get(i) / operater_Number.get(i + 1) * 1.0));
exit = true;
}
if (exit == true) {
operater_Flag.remove(i);
operater_Number.remove(i + 1);
i = i - 1;
}
}
for (int i = 0; i < operater_Flag.size(); i++) {
boolean exit = false;
if (operater_Flag.get(i).equals("+")) {
operater_Number.set(i, operater_Number.get(i) + operater_Number.get(i + 1));
exit = true;
}
if (operater_Flag.get(i).equals("-")) {
operater_Number.set(i, operater_Number.get(i) - operater_Number.get(i + 1));
exit = true;
}
if (exit == true) {
operater_Flag.remove(i);
operater_Number.remove(i + 1);
i = i - 1;
}
}
}
this.answer = operater_Number.get(0);
jTextArea.append(jTextField.getText() + "=" + operater_Number.get(0) + "\n");
jTextField.setText(null);
operater_Flag.clear();
operater_Number.clear();
}
@Override
public void setJTextArea(JTextArea jTextArea) {
// TODO Auto-generated method stub
this.jTextArea = jTextArea;
}
@Override
public void setJTextField(JTextField jTextField) {
// TODO Auto-generated method stub
this.jTextField = jTextField;
}
@Override
public void setJBTextbotton(JButton jButton[]) {
// TODO Auto-generated method stub
this.jButton = jButton;
}
}
ComputerListener.java
package calculator;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public interface ComputerListener extends ActionListener {
public void setJTextArea(JTextArea jTextArea);
public void setJTextField(JTextField jTextField);
public void setJBTextbotton(JButton jButton[]);
}
GridBagDemo.java【關於GridBag筆記】
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class GridBagDemo extends JFrame {
public static void main(String args[]) {
GridBagDemo demo = new GridBagDemo();
}
public GridBagDemo() {
init();
this.setSize(300, 300);
this.setVisible(true);
}
JButton j1;
JButton j2;
JButton j3;
JPanel j4;
JComboBox j5;
JTextField j6;
JButton j7;
JList j8;
JTextArea j9;
void init() {
// GridBagConstraints gridBagConstraints = new GridBagConstraints();
j1 = new JButton("打開");
j2 = new JButton("保存");
j3 = new JButton("另存爲");
j4 = new JPanel();
String[] str = { "java筆記", "C#筆記", "HTML5筆記" };
j5 = new JComboBox(str);
j6 = new JTextField();
j7 = new JButton("清空");
j8 = new JList(str);
j9 = new JTextArea();
j9.setBackground(Color.PINK);// 爲了看出效果,設置了顏色
GridBagLayout layout = new GridBagLayout();
this.setLayout(layout);
this.add(j1);// 把組件添加進jframe
this.add(j2);
this.add(j3);
this.add(j4);
this.add(j5);
this.add(j6);
this.add(j7);
this.add(j8);
this.add(j9);
GridBagConstraints s = new GridBagConstraints();// 定義一個GridBagConstraints,
// 是用來控制添加進的組件的顯示位置
s.fill = GridBagConstraints.BOTH;
// 該方法是爲了設置如果組件所在的區域比組件本身要大時的顯示情況
// NONE:不調整組件大小。
// HORIZONTAL:加寬組件,使它在水平方向上填滿其顯示區域,但是不改變高度。
// VERTICAL:加高組件,使它在垂直方向上填滿其顯示區域,但是不改變寬度。
// BOTH:使組件完全填滿其顯示區域。
s.gridwidth = 3;// 該方法是設置組件水平所佔用的格子數,如果爲0,就說明該組件是該行的最後一個
s.weightx = 0;// 該方法設置組件水平的拉伸幅度,如果爲0就說明不拉伸,不爲0就隨着窗口增大進行拉伸,0到1之間
s.weighty = 0;// 該方法設置組件垂直的拉伸幅度,如果爲0就說明不拉伸,不爲0就隨着窗口增大進行拉伸,0到1之間
layout.setConstraints(j1, s);// 設置組件
s.gridwidth = 1;
// s.insets = new Insets(5, 5, 5, 5);
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(j2, s);
s.gridwidth = 1;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(j3, s);
s.gridwidth = 0;// 該方法是設置組件水平所佔用的格子數,如果爲0,就說明該組件是該行的最後一個
s.weightx = 0;// 不能爲1,j4是佔了4個格,並且可以橫向拉伸,
// 但是如果爲1,後面行的列的格也會跟着拉伸,導致j7所在的列也可以拉伸
// 所以應該是跟着j6進行拉伸
s.weighty = 0;
layout.setConstraints(j4, s);
s.gridwidth = 2;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(j5, s);
;
s.gridwidth = 4;
s.weightx = 1;
s.weighty = 0;
layout.setConstraints(j6, s);
;
s.gridwidth = 0;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(j7, s);
;
s.gridwidth = 2;
s.weightx = 0;
s.weighty = 1;
layout.setConstraints(j8, s);
;
s.gridwidth = 5;
s.weightx = 0;
s.weighty = 1;
layout.setConstraints(j9, s);
}
}
6.總結感悟
錯誤分析:
a) 輸入一個數中多個小數點;
b) 分析器的StringTokenizer的是否錯誤;
c) 正則表達式的使用錯誤。
錯誤解決:
a) 以運算符爲分割,運算符後的數字之多隻有一個小數點;
b) 在分析器使用分析字符串中的標點符號時未排除”0”,最後在單步調試中發現錯誤;
c) “[±*/]” 該正則表達式可以匹配”.”,導致浪費大量的時間檢查在”.”的觸發事件上。
通過本次實驗學習到了以下幾點:
a) 該開始入手實驗時無從下手,一邊考慮如何佈局,一邊考慮如何輸出合法,一邊考慮如何實現計算,一心三用,沒有主次先後的編程觀念。浪費比較多的時間;而後有了步驟,先將組件間的佈局做好,在考慮輸入數據的合法,最後在合法的情況下實現計算;
b) 學習到了一種新的佈局方式GridBagLayout佈局,該佈局也是一種類似網格佈局,改進GridLayout佈局不能改變組件在網格中的大小的,組件間的間隔問題;
c) 本次實驗未使用 WindowBuilding插件,主要的原因時想檢驗以下自己在暑假看課本的成果,以及個人認爲在使用插件時容易將代碼弄亂。不過在佈局方面花費比較多的時間。但也熟悉了幾個佈局的特點,以及他們的常用方法;
d) 本次實驗最大的收穫就是熟悉掌握了一個類中實例的對象在利用構造方 法在各個類中的重複使用,以及複習接口的相關知識。