## 项目概述
1.能通过设计的按钮控件输入并实现算术表达式,表达式在文本框中显示,运算结果输出显示;保存和浏览历史运算记录;
2.能够检验算术表达式的合法性;
3.能够实现混合运算的求解,算术表达式中包括加、减、乘、除、括号等运算符;
4.要求交互界面友好,程序健壮。
5.开发工具为:Java/swing/awt
## 项目设计
1.界面设计:参考于手机自带计算器
2.详细设计:界面最上面是一个文本框,用于显示表达式和计算结果。界面的中部是数字按钮,旁边是运算符,按钮中设置监听器,使得按钮内容显示到文本框。
## 关键算法分析
【1】 算法功能:实现四则运算功能
【2】 算法基本思想 :双栈算法优先级
【3】 算法空间、时间复杂度分析
【4】 代码逻辑(可用伪代码描述)
2021.12.7
在做这个项目的过程中,因为之前没有接触过GUI的开发,这对于我来说是一个困难之一。在查阅了不少资料后,大致的框架界面得到实现。具体界面如下图:
** 2021.12.8**
界面完成了,接着就是表达式的算法了。我用的是中缀表达式转换成后缀表达式的算法,用后缀表达式求文本框中表达式的值,算法思想:
从左向右依次读取算术表达式的元素X,分以下情况进行不同的处理:
(1)如果X是操作数,直接入队
(2)如果X是运算符,再分以下情况:
a)如果栈为空,直接入栈。
b)如果X==”(“,直接入栈。
c)如果X==”)“,则将栈里的元素逐个出栈,并入队到后缀表达式队列中,直到第一个配对的”(”出栈。(注:“(”和“)”都不 入队)
d)如果是其他操作符(+ - * /),则和栈顶元素进行比较优先级。 如果栈顶元素的优先级大于等于X,则出栈并把栈中弹出的元素入队,直到栈顶元素的优先级小于X或者栈为空。弹出完这些元素后,才将遇到的操作符压入到栈中。
(3)最后将栈中剩余的操作符全部入队。
后缀表达式求解:
首先准备一个栈Res_Stack.
1、从左开始向右遍历后缀表达式的元素。
2、如果取到的元素是操作数,直接入栈Res_Stack,如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈
3、当遍历完后缀表达式时,计算结果就保存在栈里了。
在代码实现的过程中,由于我对栈的用法不够熟悉,出现了许多错误,有些表达式能得到答案,有些却不能,在多次修改之后,发现原来是我的限制条件没考虑清楚,才没把算法写对。最后总算实现了大致的算法。
具体算法如下
Solution类用于计算
import java.util.Stack;
public class Solution {
public static char precede(char a,char b){
if((a=='='&&b=='=')||(a=='(')&&b==')')
return '=';
else
if(a=='('||b=='('||a=='='||((a=='+'||a=='-')&&(b=='*'||b=='/')))
return '<';
else
return '>';
}
public static double Operate(double a,char b,double c) //操作
{
if(b=='+')
return a+c;
else if(b=='-')
return a-c;
else if(b=='*')
return a*c;
else
return a/c;
}
public static double Calculate(String string) {
Stack<Character> ops = new Stack<>();
Stack<Double> vals = new Stack<>();
// Scanner in = new Scanner(System.in);
String test = string;
char[] array = test.toCharArray();
ops.push('=');
for (int i = 0; array[i] != '=' || ops.peek() != '='; ) {
char[] chars = new char[100];
int t = 0;
if (array[i] >= '0' && array[i] <= '9' || array[i] == '.') {
while (array[i] >= '0' && array[i] <= '9' || array[i] == '.') {
chars[t] = array[i];
t++;
i++;
}
vals.push(Double.parseDouble(new String(chars)));
chars = null;
} else {
switch (precede(ops.peek(), array[i])) {
case '<':
ops.push(array[i]);
i++;
break;
case '>':
double m = vals.pop();
double n = vals.pop();
char s = ops.pop();
vals.push(Operate(n, s, m));
break;
case '=':
ops.pop();
i++;
break;
}
}
}
double result = vals.peek();
return result;
}
}
计算器架构类如下:
import java.awt.Color;
import java.awt.Component;
import java.awt.Frame;
import java.awt.LayoutManager;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
public class Calculator extends Frame {
private static final long serialVersionUID = 3662951318647610410L;
public Calculator() {
}
public static void main(String[] args) {
Frame window = new Frame("Calculator");
window.setSize(380, 337);
window.setResizable(false);
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
window.setLocation(width / 2 - 200, height / 2 - 150);
window.setLayout((LayoutManager)null);
final JTextField text = new JTextField();
text.setHorizontalAlignment(2);
text.setEditable(true);
text.setBounds(10, 40, 366, 50);
window.add(text);
text.setForeground(Color.BLUE);
text.setBackground(Color.lightGray);
text.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
ScriptEngineManager calsem = new ScriptEngineManager();
ScriptEngine cal = calsem.getEngineByName("calculate");
try {
int textlength = text.getText().length();
if (textlength == 0) {
JOptionPane.showMessageDialog((Component)null, "您没有任何输入,请重新输入!");
text.requestFocusInWindow();
} else {
String result = cal.eval(text.getText()).toString();
text.setText(text.getText() + "=" + result);
text.requestFocus();
}
} catch (ScriptException var6) {
JOptionPane.showMessageDialog((Component)null, "表达式错误,请重新输入!");
text.setText("");
text.requestFocus();
}
}
});
JButton b0 = new JButton("0");
b0.setBounds(10, 283, 72, 50);
b0.setBackground(Color.CYAN);
window.add(b0);
b0.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "0");
text.requestFocus();
}
});
JButton b1 = new JButton("1");
b1.setBounds(10, 233, 72, 50);
b1.setBackground(Color.CYAN);
window.add(b1);
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "1");
text.requestFocus();
}
});
JButton b2 = new JButton("2");
b2.setBounds(82, 233, 72, 50);
b2.setBackground(Color.CYAN);
window.add(b2);
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "2");
text.requestFocus();
}
});
JButton b3 = new JButton("3");
b3.setBounds(154, 233, 72, 50);
b3.setBackground(Color.CYAN);
window.add(b3);
b3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "3");
text.requestFocus();
}
});
JButton b4 = new JButton("4");
b4.setBounds(10, 183, 72, 50);
b4.setBackground(Color.CYAN);
window.add(b4);
b4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "4");
text.requestFocus();
}
});
JButton b5 = new JButton("5");
b5.setBounds(82, 183, 72, 50);
b5.setBackground(Color.CYAN);
window.add(b5);
b5.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "5");
text.requestFocus();
}
});
JButton b6 = new JButton("6");
b6.setBounds(154, 183, 72, 50);
b6.setBackground(Color.CYAN);
window.add(b6);
b6.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "6");
text.requestFocus();
}
});
JButton b7 = new JButton("7");
b7.setBounds(10, 135, 72, 50);
b7.setBackground(Color.CYAN);
window.add(b7);
b7.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "7");
text.requestFocus();
}
});
JButton b8 = new JButton("8");
b8.setBounds(82, 135, 72, 50);
b8.setBackground(Color.CYAN);
window.add(b8);
b8.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "8");
text.requestFocus();
}
});
JButton b9 = new JButton("9");
b9.setBounds(154, 135, 72, 50);
b9.setBackground(Color.CYAN);
window.add(b9);
b9.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "9");
text.requestFocus();
}
});
JButton Add = new JButton("+");
Add.setBounds(226, 135, 72, 50);
Add.setBackground(Color.orange);
window.add(Add);
Add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "+");
text.requestFocus();
}
});
JButton Sub = new JButton("-");
Sub.setBounds(298, 135, 80, 50);
Sub.setBackground(Color.orange);
window.add(Sub);
Sub.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "-");
text.requestFocus();
}
});
JButton Multi = new JButton("*");
Multi.setBounds(226, 183, 72, 50);
Multi.setBackground(Color.orange);
window.add(Multi);
Multi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int leng1 = text.getText().length();
if (leng1 >= 1) {
text.setText(text.getText() + "*");
text.requestFocus();
} else {
JOptionPane.showMessageDialog((Component)null, "输入的第一个字符不能为乘号哦");
text.requestFocus();
}
}
});
JButton Div = new JButton("/");
Div.setBounds(298, 183, 80, 50);
Div.setBackground(Color.orange);
window.add(Div);
Div.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int leng2 = text.getText().length();
if (leng2 >= 1) {
text.setText(text.getText() + "/");
text.requestFocus();
} else {
JOptionPane.showMessageDialog((Component)null,"输入的第一个不能是除号哦" );
text.requestFocus();
}
}
});
JButton equal = new JButton("=");
equal.setBounds(226, 283, 153, 50);
equal.setBackground(Color.pink);
window.add(equal);
equal.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine se = sem.getEngineByName("calculate");
// try {
int leng3 = text.getText().length();
if (leng3 == 0) {
JOptionPane.showMessageDialog((Component)null, "Sorry,您没有任何输入哎");
text.requestFocus();
} else {
text.setText(text.getText() + "=");
String result=text.getText();
//String result=Solution.Calculate(text.getText());
// String result = se.eval(text.getText()).toString();
double result1=Solution.Calculate(result);
text.setText(text.getText() + result1);
text.requestFocus();
}
/** } catch (ScriptException var6) {
JOptionPane.showMessageDialog((Component)null, "表达式错啦,请重新输一下呗");
text.setText("");
text.requestFocus();
}**/
}
});
JButton point = new JButton(".");
point.setBounds(226, 233, 72, 50);
point.setBackground(Color.orange);
window.add(point);
point.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int leng4 = text.getText().length();
if (leng4 > 0) {
text.setText(text.getText() + ".");
text.requestFocus();
} else {
JOptionPane.showMessageDialog((Component)null, "输入的第一个字符不能为小数点哦");
text.requestFocus();
}
}
});
JButton left = new JButton("(");
left.setBounds(82, 283, 72, 50);
left.setBackground(Color.CYAN);
window.add(left);
left.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText(text.getText() + "(");
text.requestFocus();
}
});
JButton right = new JButton(")");
right.setBounds(154, 283, 72, 50);
right.setBackground(Color.CYAN);
window.add(right);
right.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int leng5 = text.getText().length();
if (leng5 > 0) {
text.setText(text.getText() + ")");
text.requestFocus();
} else {
JOptionPane.showMessageDialog((Component)null, "输入的第一个字符不能为右括号哦");
text.requestFocus();
}
}
});
JButton ce = new JButton("CE");
ce.setBounds(10, 90, 180, 45);
//ce.setBackground(Color.MAGENTA);
window.add(ce);
ce.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int leng6 = text.getText().length();
if (leng6 > 0) {
text.setText("");
text.requestFocus();
} else {
JOptionPane.showMessageDialog((Component)null, "已经清屏了哦");
text.requestFocus();
}
}
});
JButton back = new JButton("←Backspace");
back.setBounds(190, 90, 186, 45);
window.add(back);
back.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int leng7 = text.getText().length();
String message = text.getText();
if (leng7 == 0) {
JOptionPane.showMessageDialog((Component)null, "Sorry,什么都木有了,不用再退格了嘛");
text.requestFocus();
} else {
text.setText(message.substring(0, leng7 - 1));
text.requestFocus();
}
}
});
JButton complementation = new JButton("%");
complementation.setBounds(298, 233, 80, 50);
complementation.setBackground(Color.orange);
window.add(complementation);
complementation.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int leng8 = text.getText().length();
if (leng8 > 0) {
text.setText(text.getText() + "%");
text.requestFocus();
} else {
JOptionPane.showMessageDialog((Component)null, "输入的第一个字符已为求余数啦,不用了嘛");
text.requestFocus();
}
}
});
window.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
window.show();
}
}
个人总结
在实现这个项目的过程中,遇到了许多困难,算法也有很多不够完善的地方,也查阅了许多资料,有一些地方也没能弄明白。在代码实现过程中,由于对GUI界面的不够了解,所以完成得不是很好,界面有点丑了,算法也写得不够好,已经很努力去完成了,如果时间允许,我应该可以做得更完善也能添加更多功能。