“基於Java GUI實現一個應用”——這本是上學期12月20日Java課程的大作業,當時做完就想發博客來着,結果一直到現在才發。
這個大作業我做的是一個計算器,做的時候才發現比我開始預想的要複雜。計算器也不是那麼容易做的,哈哈,真的想想容易做着就懵逼。
希望能給同學們借鑑,一起學習吧,有問題也可以私我。
代碼過長,需要源代碼及可執行文件的可以百度網盤領取:
鏈接:https://pan.baidu.com/s/1KZr7PkqTpv922sCWyScs8g
提取碼:w434
效果圖:
主要算法:接收圖形化界面上用戶輸入的表達式,將整串字符串做切割傳入一個數組中,這個數組算是一箇中綴表達式的數組。對中綴表達式使用棧技術比較運算符優先級,限定特殊字符串(括號)轉成後綴表達式數組。括號運算符是存在中綴表達式數組中的,在轉成後綴表達式括號運算符就要全部刪除,後綴表達式不需要括號,優先級已經存在於先後順序。當得到後綴表達式後,同樣利用棧技術,存入取出棧元素來進行計算。
界面佈局:基於GUI圖形化界面,使用WindowBuilder可視化工具,絕對定位進行模塊佈局。界面使用到了按鈕,文本框,輸入框,可滾動文本域等組件,還設置了表框顏色,字體樣式等。
總結:本次大作業做的計算器算是第二次嘗試,之前也做過網頁版的計算器,但當時不知道中綴表達式、後綴表達式以及棧技術。可以說這幾個是完成計算器的核心方法。這次計算器花了3個晚上的時間完成了,花了2個晚上進行BUG測試,基本上現在是不存在BUG。而完成計算器最大的困難在於中綴表達式轉後綴表達式和用後綴表達式進行計算得出結果的這個兩個方法。這兩個方法也是計算器的核心代碼所在。電腦自帶的標準計算器是不帶括號運算符的,但有累加計算的功能。累加計算的效果不難,開始做的時候我也做出了累加計算,後來進行改進新增了括號運算去掉了累加計算。有括號運算,計算器的難度又是增大了。因爲在中綴表達式轉後綴表達式裏,我需要判斷括號內外的優先級,比較完後還不能把括號運算符傳入後綴表達式內,因爲後綴表達式不需要括號。與電腦自帶的標準計算器相比,標準計算器其實是有2塊顯示錶達式的部分,一部分是顯示輸入,一部分是總的表達式,而我這個只做了一個顯示錶達式的,所以在輸入運算符以及數值的時候是有一些侷限性的。比如:不能直接輸入負號,你必須輸入零減一個數值。爲了用戶輸入的標準性我做了很多輸入限制。比如:不能有2個及以上相連的運算符,數值的小數點不能點了又點,右括號必須與左括號個數相同等等,這些都是代碼邏輯裏寫了的,從而給用戶更好的體驗感,也爲防止傳入數據的有誤性。當然,如果用戶用加減乘除運算符結束表達式直接按等於,或是缺少了右括號也是沒事的,不會有影響。總體這次做計算器的收穫還是很大的。
所具有的類:
Calculator類:GUI圖形化界面實現類,實現了計算器的整體佈局,並且調用StackToCalculator類的返回內容。其中包含實現監聽功能的內部類ButtonHandler,以及初始化用的方法(doInit())。
StackToCalculator類:計算器的主要算法實現類。其中包括字符串轉數組方法(toArr(String text))、中綴表達式轉後綴表達式方法(ToSuffix(String[] textArray))、判斷是否爲數值的方法(isNum(char strNum)、isNum(String strNum))、運算符比較優先級的方法(ToCampare(String str1))以及最終使用後綴表達式進行棧計算的方法(ToCacultor(String Ctext))。
上代碼:
package work7;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextArea;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.JLabel;
/**
* @author YoungIT
* @version 2019年12月18日 下午11:12:14
* @tips 計算器
*/
public class Cacultor extends JFrame {
private JPanel contentPane;
private JTextArea textArea;
private JButton btnNewButton,btnNewButton_1,btnNewButton_2,btnNewButton_3,
btnNewButton_4,btnNewButton_5,btnNewButton_6,btnNewButton_7,button,button_1,
button_2,button_3,button_4,button_5,button_6,button_7,
button_8,button_9,button_10,button_11,button_12;
private String textA = "";
private String cString = "";
private JTextField textField;
private int count = 0;//"+-x/"
private int cleft = 0;//標記 "("
private int cright = 0;//標記 ")"
private int point = 0;//標記 "."
private int cnum = 0;//標記 數字
private int flag = 0;//1-數字,2-運算符,3-點,4-左括,5-右括
private int fsum = 0;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Cacultor frame = new Cacultor();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Cacultor() {
super("超智能計算器");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(700, 500, 620, 430);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(null);
setContentPane(contentPane);
btnNewButton = new JButton("C");
btnNewButton.setBounds(10, 78, 83, 44);
contentPane.add(btnNewButton);
btnNewButton_1 = new JButton(".");
btnNewButton_1.setBounds(92, 78, 83, 44);
contentPane.add(btnNewButton_1);
btnNewButton_3 = new JButton("BackSace");
btnNewButton_3.setBounds(174, 78, 200, 44);
contentPane.add(btnNewButton_3);
btnNewButton_4 = new JButton("7");
btnNewButton_4.setBounds(10, 129, 83, 44);
contentPane.add(btnNewButton_4);
btnNewButton_5 = new JButton("8");
btnNewButton_5.setBounds(92, 129, 83, 44);
contentPane.add(btnNewButton_5);
btnNewButton_6 = new JButton("9");
btnNewButton_6.setBounds(174, 129, 83, 44);
contentPane.add(btnNewButton_6);
btnNewButton_7 = new JButton("+");
btnNewButton_7.setBounds(256, 129, 118, 44);
contentPane.add(btnNewButton_7);
button = new JButton("4");
button.setBounds(10, 182, 83, 44);
contentPane.add(button);
button_1 = new JButton("5");
button_1.setBounds(92, 182, 83, 44);
contentPane.add(button_1);
button_2 = new JButton("6");
button_2.setBounds(174, 182, 83, 44);
contentPane.add(button_2);
button_3 = new JButton("1");
button_3.setBounds(10, 236, 83, 44);
contentPane.add(button_3);
button_4 = new JButton("2");
button_4.setBounds(92, 236, 83, 44);
contentPane.add(button_4);
button_5 = new JButton("3");
button_5.setBounds(174, 236, 83, 44);
contentPane.add(button_5);
button_6 = new JButton("(");
button_6.setBounds(10, 288, 83, 44);
contentPane.add(button_6);
button_7 = new JButton("0");
button_7.setBounds(92, 288, 83, 44);
contentPane.add(button_7);
button_8 = new JButton(")");
button_8.setBounds(174, 288, 83, 44);
contentPane.add(button_8);
button_9 = new JButton("-");
button_9.setBounds(256, 182, 118, 44);
contentPane.add(button_9);
button_10 = new JButton("x");
button_10.setBounds(256, 236, 118, 44);
contentPane.add(button_10);
button_11 = new JButton("/");
button_11.setBounds(256, 288, 118, 44);
contentPane.add(button_11);
button_12 = new JButton("=");
button_12.setBounds(10, 337, 364, 44);
contentPane.add(button_12);
textField = new JTextField();
textField.setBounds(10, 10, 364, 44);
textField.setEditable(false);
textField.setFont(new Font("華文彩雲",Font.BOLD, 18));
textField.setHorizontalAlignment(JTextField.RIGHT);
contentPane.add(textField);
textField.setColumns(10);
JLabel lblByYoungit = new JLabel("by: YoungIT");
lblByYoungit.setBounds(309, 56, 75, 22);
contentPane.add(lblByYoungit);
textArea = new JTextArea();
textArea.setBounds(380, 10, 194, 371);
textArea.setEditable(false);
textArea.setLineWrap(true);
textArea.setFont(new Font("華文彩雲",Font.BOLD, 18));
Color b = new Color(194,214,233);
Color c = new Color(238,238,238);
textArea.setBackground(c);
textArea.setBorder(BorderFactory.createMatteBorder(2,2,2,2,b));
JScrollPane scrollpane = new JScrollPane(textArea);
// scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollpane.setBounds(384, 10, 210, 371);
contentPane.add(scrollpane);
ButtonHandler handler = new ButtonHandler();
button.addActionListener(handler);
button_1.addActionListener(handler);
button_2.addActionListener(handler);
button_3.addActionListener(handler);
button_4.addActionListener(handler);
button_5.addActionListener(handler);
button_6.addActionListener(handler);
button_7.addActionListener(handler);
button_8.addActionListener(handler);
button_9.addActionListener(handler);
button_10.addActionListener(handler);
button_11.addActionListener(handler);
button_12.addActionListener(handler);
btnNewButton.addActionListener(handler);
btnNewButton_1.addActionListener(handler);
btnNewButton_3.addActionListener(handler);
btnNewButton_4.addActionListener(handler);
btnNewButton_5.addActionListener(handler);
btnNewButton_6.addActionListener(handler);
btnNewButton_7.addActionListener(handler);
}
public void doInit() {
textA = "";
textField.setText(textA);
count = 0;//"+-x/"
cleft = 0;//標記 "("
cright = 0;//標記 ")"
point = 0;//標記 "."
cnum = 0;//標記 數字
flag = 0;
fsum = 0;
}
private class ButtonHandler implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
String Ename = e.getActionCommand();
switch (Ename) {
case "C":
doInit();
break;
case "BackSace":
if(fsum==1) {
doInit();
}
try {
if(textA.length()>0) {
String laString = textA.substring(textA.length() - 1);
if(laString.equals(")")) {
cleft++;
}else if(laString.equals("0")) {
cnum = 0;
}
textA = textA.isEmpty()?"":textA.substring(0,textA.length() - 1);
textField.setText(textA);
char c = textA.charAt(textA.length()-1);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
flag = 1;break;
case '+':
case '-':
case 'x':
case '/':
flag = 2;break;
case '.':
flag = 3;break;
case '(':
flag = 4;break;
case ')':
flag = 5;
break;
default:
break;
}
}
}catch (Exception e2) {
System.err.println("不要再刪啦~已無內容!");
}
break;
case "0":
if(fsum==1) {
doInit();
}
if(flag == 2 || flag == 0){//1-數字,2-運算符,3-點,4-左括,5-右括
cnum = 1;
textA = textA + Ename;
textField.setText(textA);
flag = 1;
}else if(flag == 1 || flag == 3|| flag == 4) {
textA = textA + Ename;
textField.setText(textA);
flag = 1;
}
break;
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9"://右括) 後不能輸數字
if(fsum==1) {
doInit();
}
if(flag != 5&&cnum == 0){//1-數字,2-運算符,3-點,4-左括,5-右括
textA = textA + Ename;
textField.setText(textA);
flag = 1;
}
break;
case "+":
case "-":
case "x":
case "/"://不能輸入:空,(,.,運算符
if(fsum==1) {
doInit();
break;
}
if(flag == 1||flag == 5){//0-空,1-數字,2-運算符,3-點,4-左括,5-右括
textA = textA + Ename;
// count = 1;//+-x/
point = 0;
cnum = 0;
textField.setText(textA);
flag = 2;
}
break;
case "."://前面只能是數字
if(fsum==1) {
doInit();
break;
}
if(flag == 1&&point == 0) {
textA = textA + Ename;
point = 1;//標記.
textField.setText(textA);
cnum = 0;
flag = 3;
}
break;
case "("://不能輸入:(,),.,數字
if(fsum==1) {
doInit();
}
if(flag == 0 || flag == 2) {//空 運算符
textA = textA + Ename;
cleft++;
// cright = 0;
textField.setText(textA);
flag = 4;
}
System.out.println("cleft:"+cleft);
break;
case ")"://不能輸入:(,.,運算符,空
if(fsum==1) {
doInit();
break;
}
if(((flag == 1 || flag == 4) && cleft > 0)||(flag == 5 && cleft > 0)) {//數字 右括號
textA = textA + Ename;
// cright = 0;
cleft--;
textField.setText(textA);
flag = 5;
}
System.out.println("cleft2:"+cleft);
break;
case "=":
if(fsum==1) {
doInit();
break;
}
try {
System.out.println("****************************");
System.out.println("輸入的表達式:"+textA);
StackToCacultor stackToCacultor = new StackToCacultor();
String lastStr = String.valueOf(textA.charAt(textA.length()-1));
if(!stackToCacultor.isNum(lastStr)&&!lastStr.equals(")")) {//刪去最後位是運算符
textA = textA.isEmpty()?"":textA.substring(0, textA.length() - 1);
}
int i = 0,ckey = 0;
char c;
while (i<textA.length()) {//爲了補上")"
c = textA.charAt(i);
if(c=='(') {
ckey++;
}else if(c==')') {
ckey--;
}
i++;
}
if(ckey > 0) {
for(int j=0;j<ckey;j++) {
textA = textA+")";
}
}
System.out.println("傳入計算的表達式:"+textA);
cString += textA;
String text2 = String.valueOf(stackToCacultor.ToCacultor(textA));
textField.setText(text2);
cString += " = "+text2 + '\n'+"******************"+ '\n';
textArea.setText(cString);
textA = text2;
fsum = 1;
}catch (Exception e2) {
System.err.println("請輸入!");
}
break;
default:
break;
}
}
}
}
package work7;
import java.util.Stack;
import java.util.Vector;
/**
* @author YoungIT
* @version 2019年12月18日 下午1:01:18
* @tips 使用堆棧計算
*/
public class StackToCacultor{
private static String[] textArr = new String[50];
private static String[] textArr2 = new String[50];
private final static int sizeofSum = 2;//優先級
private final static int sizeofSub = 2;
private final static int sizeofMul = 3;
private final static int sizeofDiv = 3;
private final static int sizeofLbra = 1;
private final static int sizeofRbra = 0;
public StackToCacultor() {
for(int i = 0; i<textArr.length; i++) {
textArr[i] = null;
textArr2[i] = null;
}
}
//最終計算
public static double ToCacultor(String Ctext) {
int numkey = 0;
int strkey = 0;
String[] strArr = ToSuffix(toArr(Ctext));
Stack<String> stack = new Stack<String>();
double sum = 0;
try {
for(int i=0;i<strArr.length-1;i++) {
numkey = 0;
strkey = 0;
if(strArr[i]==null) {
while(!stack.isEmpty()) {
String top = stack.pop();
if(isNum(top)) {
sum = Double.parseDouble(top);//*********//
}
}
break;
} // 2x(3+2)
System.out.println("ToCacultor-後綴:"+strArr[i]);
if(stack.empty()) {
stack.push(strArr[i]);
}else {
for (String x : stack) {
if(isNum(x)) {
numkey++;
}else {
strkey++;
}
}
if(isNum(strArr[i])) {
if(numkey==1&&strkey==1) {
String str = stack.pop();
double num3 = Double.parseDouble(stack.pop());
double s2 = Double.parseDouble(strArr[i]);
double sum2 = 0;
switch (str) {
case "+":
sum2 = num3 + s2;
break;
case "-":
sum2 = num3 - s2;
break;
case "x":
sum2 = num3 * s2;
break;
case "/":
sum2 = num3 / s2;
break;
}
stack.push(String.valueOf(sum2));
}else {
stack.push(String.valueOf(strArr[i]));
}
}else {
if(numkey>=2) {
double num1 = Double.parseDouble(stack.pop());
double num2 = Double.parseDouble(stack.pop());
double s = 0;
switch (strArr[i]) {
case "+":
s = num2 + num1;
break;
case "-":
s = num2 - num1;
break;
case "x":
s = num2 * num1;
break;
case "/":
s = num2 / num1;
break;
}
stack.push(String.valueOf(s));
}else {
stack.push(String.valueOf(strArr[i]));
}
}
}
}
}catch (Exception e) {
System.err.println("計算出錯!請重啓~");
}
System.out.println("計算結果:"+sum);
return sum;
}
//字符轉數組
public static String[] toArr(String text) {
int i = 0,j = 0;
char c;
while (i<text.length()) {
c = text.charAt(i);
if(c=='('||c==')'||c =='+'||c =='-'||c =='x'||c =='/') {
textArr[j++] = String.valueOf(c);
i++;
}else {// 數字
String num = "";
while (true) {
if(i>=text.length()) {
break;
}
c = text.charAt(i);
if(c==')'||c =='+'||c =='-'||c =='x'||c =='/') {
break;
}
num += c;
i++;
}
textArr[j++] = num;
}
}
return textArr;
}
//中綴表達式 轉 後綴
public static String[] ToSuffix(String[] textArray) {
int k=0;
Stack stack = new Stack();
for(int i=0;i<textArray.length-1;i++) {
if(textArray[i]!=null) {
System.out.println("ToSuffix中綴:"+textArray[i]);
int priority = ToCampare(textArray[i]); //2x(3+2)
if(isNum(textArray[i])) {//讀取到數字
textArr2[k++] = textArray[i];
}else {
if(!stack.empty()) {
if(textArray[i].equals("(")) {
stack.push(textArray[i]);
continue;
}else if(textArray[i].equals(")")){
System.out.println(String.valueOf(stack.peek()));
while (!String.valueOf(stack.peek()).equals("(")) {
textArr2[k++] = String.valueOf(stack.pop());
}
stack.pop();
continue;
}else if(priority>ToCampare(String.valueOf(stack.peek()))) {//優先級大於 棧頂
stack.push(textArray[i]);
continue;
}else {
while (priority<=ToCampare(String.valueOf(stack.peek()))) {
textArr2[k++] = String.valueOf(stack.pop());
if(stack.isEmpty()) {
break;
}
}
stack.push(textArray[i]);
continue;
}
}else {
stack.push(textArray[i]);
}
}
}else {
while (!stack.empty()) {
textArr2[k++] = String.valueOf(stack.pop());
}
}
}//for
return textArr2;
}
//是否爲數1
public static boolean isNum(char strNum) {
if(strNum=='1'||strNum=='2'||strNum=='3'||strNum=='4'
||strNum=='5'||strNum=='6'||strNum=='7'
||strNum=='8'||strNum=='9'||strNum=='0') {
return true;
}else {
return false;
}
}
//是否爲數2
public static boolean isNum(String strNum) {
if(!strNum.equals("+")&&!strNum.equals("-")&&!strNum.equals("x")
&&!strNum.equals("/")&&!strNum.equals("(")&&!strNum.equals(")")) {
return true;
}else {
return false;
}
}
//運算符優先級比較 str1>str2 返回true
public static int ToCampare(String str1) {
int key = -1;
switch (str1) {
case "(":
key = 1;
break;
case ")":
key = 0;
break;
case "+":
case "-":
key = 2;
break;
case "x":
case "/":
key = 3;
break;
}
return key;
}
//test
public static void main(String[] args) {
// String[] strings = toArr("(1222.2x231+232)/123123.23+(323.2+323)");
// String[] strings = toArr("2x(3+2)");//10
// String[] strings = toArr("1+1");
// for(int i=0;i<strings.length-1;i++) {
// if(strings[i]!=null) {
// System.out.println(strings[i]);
// }
// }
// System.out.println(" ");
// ToSuffix(strings);
// for(int i=0;i<textArr2.length-1;i++) {
// if(textArr2[i]!=null) {
// System.out.println(textArr2[i]);
// }
// }
// System.out.println(ToCacultor("2x(3+2)"));
// System.out.println(ToCacultor("1+1"));
}
}
代碼過長,需要源代碼及可執行文件的可以百度網盤領取:
鏈接:https://pan.baidu.com/s/1KZr7PkqTpv922sCWyScs8g
提取碼:w434
虛心學習,一起進步~