“基于Java GUI实现一个应用”——这本是上学期12月20日Java课程的大作业,当时做完就想发博客来着,结果一直到现在才发。
这个大作业我做的是一个计算器,做的时候才发现比我开始预想的要复杂。计算器也不是那么容易做的,哈哈,真的想想容易做着就懵逼。
希望能给同学们借鉴,一起学习吧,有问题也可以私我。
代码过长,需要源代码及可执行文件的可以下方百度网盘领取:
效果图:
主要算法:接收图形化界面上用户输入的表达式,将整串字符串做切割传入一个数组中,这个数组算是一个中缀表达式的数组。对中缀表达式使用栈技术比较运算符优先级,限定特殊字符串(括号)转成后缀表达式数组。括号运算符是存在中缀表达式数组中的,在转成后缀表达式括号运算符就要全部删除,后缀表达式不需要括号,优先级已经存在于先后顺序。当得到后缀表达式后,同样利用栈技术,存入取出栈元素来进行计算。
界面布局:基于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/1VTJ5m86qY7PU5UZOlYd18A
提取码:Fi3s
虚心学习,一起进步~