import java.awt.Color;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class CalculatorFrame extends JFrame implements ActionListener // throws NullPointerException
{
private static final long serialVersionUID = -2769614160013503222L;
private JTextField tf = new JTextField(); // 创建文本框tf
private Calculator calculator = new Calculator();
public CalculatorFrame() throws HeadlessException {
JPanel pan = new JPanel(); // 创建一个面板对象pan
GridLayout grid = new GridLayout(5, 4); // 创建6行4列的页面布局
// 对面板pan和文本框tf的一些设置
pan.setLayout(grid);
tf.setBounds(35, 15, 250, 25);
pan.setBounds(35, 50, 250, 150);
tf.setBackground(Color.CYAN);
tf.setHorizontalAlignment(JTextField.RIGHT);
String[][] btnArray = { { "1", "2", "3", "+" }, { "4", "5", "6", "-" }, { "7", "8", "9", "*" },
{ "0", ".", "", "/" }, { "AC", "%", "←", "=" } };
for (int i = 0; i < btnArray.length; i++) {
for (int j = 0; j < btnArray[i].length; j++) {
JButton btn = new JButton(btnArray[i][j]);
// 编辑bp的监听事件源为本窗口
btn.addActionListener(this);
// 将按钮添加到面板pan中
pan.add(btn);
}
}
// 添加面板pan和文本框tf到窗口frm
this.add(tf);
this.add(pan);
// 关于窗口frm的一些设置
this.setTitle("计算器");
this.setLayout(null); // 取消窗口的布局管理
this.setSize(325, 250);
this.setResizable(false); // 设置窗口的大小为不可变
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) throws NullPointerException {
new CalculatorFrame();
}
@Override
public void actionPerformed(ActionEvent e) {
JButton but = (JButton) e.getSource();
String text = but.getText();
String content = tf.getText();
if ("←".equals(text)) {
if (content != null && content.length() >= 1) {
tf.setText(content.substring(0, content.length() - 1));
}
} else if ("=".equals(text)) {
Double value = calculator.calculator(content);
if (value != null)
tf.setText(String.valueOf(value));
} else if ("AC".equals(text)) {
tf.setText("");
} else {
tf.setText(content + text);
}
}
private class Calculator {
// 定义操作符的优先级别
private Map<String, Integer> operatorPriority = new HashMap<String, Integer>();
public Calculator() {
super();
// 设置操作符优先级,数越大优先级越高
operatorPriority.put("+", 1);
operatorPriority.put("-", 1);
operatorPriority.put("*", 2);
operatorPriority.put("/", 2);
operatorPriority.put("%", 2);
operatorPriority.put("(", 3);
operatorPriority.put(")", 3);
}
/**
* 计算算术表达式
*
* @param str
* 算术表达式
* @return 结果
*/
public Double calculator(String str)// 科学计算
{
if (str == null || "".equals(str))
return null;
List<String> numList = getStringList(str);// 拆分操作符与操作数
numList = getPostOrder(numList); // 中缀变后缀
Stack<Double> stack = new Stack<Double>();// 结果栈
for (int i = 0; i < numList.size(); i++) {
String temp = numList.get(i);
if (Character.isDigit(temp.charAt(0))) {// 如果是数字
stack.push(Double.valueOf(temp));
} else {
Double back = stack.pop();
Double front = stack.pop();
Double res = 0d;
switch (temp.charAt(0)) {
case '+':
res = front + back;
break;
case '-':
res = front - back;
break;
case '*':
res = front * back;
break;
case '/':
res = front / back;
break;
case '%':
res = front % back;
break;
}
stack.push(res);
}
}
return stack.pop();
}
/**
* 将中缀表达式转换到后缀表达式
*
* <pre>
* 平时所用的标准四则运算表达式,即"9+(3-1)*3+10/2"叫做中缀表达式。因为所有的运算符号都在两数字的中间,现在我们的问题就是中缀到后缀的转化;
* 中缀表达式“9+(3-1)*3+10/2”转化为后缀表达式“9 3 1-3*+ 10 2/+”
*
* 规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;
* 若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于找顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,
* 一直到最终输出后缀表达式为止。
* </pre>
*
* 参见链接:<a
* href="http://www.nowamagic.net/librarys/veda/detail/2307">http://www.nowamagic.net/librarys/veda/detail
* /2307</a>
*
* @param postOrder
* @return
*/
public List<String> getPostOrder(List<String> inOrderList) {
ArrayList<String> result = new ArrayList<String>();// 结果列表
Stack<String> stack = new Stack<String>();// 操作符栈
for (int i = 0; i < inOrderList.size(); i++) {
String str = inOrderList.get(i);
// 判断当前是不是数字
if (Character.isDigit(str.charAt(0))) {
result.add(inOrderList.get(i));// 是数字直接添加
} else {
// 如果是操作符
switch (str.charAt(0)) {
case '(':
stack.push(str);// 往操作符栈中添加
break;
case ')':
while (!stack.peek().equals("(")) {
result.add(stack.pop());
}
stack.pop();
break;
default:
// 其他操作符
while (!stack.isEmpty() && compare(stack.peek(), str) >= 0) {
result.add(stack.pop());
}
stack.push(inOrderList.get(i));
break;
}
}
}
while (!stack.isEmpty()) {
result.add(stack.pop());
}
return result;
}
/**
* 将字符串转换成由操作符和操作数组成的字符串数组
*
* @param str
* 算数运算表达式
* @return
*/
private List<String> getStringList(String str) {
// 数字临时变量
StringBuffer sb = new StringBuffer();
// 将字符串转成操作数与操作符数组
List<String> numList = new ArrayList<String>();
for (char c : str.toCharArray()) {
// 空白字符 继续循环
if (Character.isWhitespace(c)) {
continue;
}
// 如果是数字或者点号
if (Character.isDigit(c) || '.' == c) {
sb.append(c);
} else {
numList.add(sb.toString());// 将数字添加到列表中
sb.setLength(0);// 清空数字临时变量
numList.add(String.valueOf(c));// 将操作符添加到列表中
}
}
numList.add(sb.toString());
return numList;
}
/**
* 比较运算符等级 ,
*
* <pre>
* 如果operator1 > operator2 返回 正数,
* 如果operator1 < operator2 返回 负数,
* 如果operator1 = operator2 返回 零
* </pre>
*
* @param operator1
* 操作符
* @param operator2
* 操作符
* @return
*/
public int compare(String operator1, String operator2) {
return operatorPriority.get(operator1) - operatorPriority.get(operator2);
}
}
}