import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class Calculater extends JFrame {
private static final long serialVersionUID = 1L;
private boolean flag = false; //每次点击'='之后其值更新为真,之后再次点击任何按键将清空文本框,并将其值更新为false
private boolean point = false;//point 为false 时无小数点,小数点生效
private JPanel contentPane; //主窗格
private JTextField txtUnder; //上层文本框,用于显示输入的表达式
private JTextField txtUpper; //下层文本框,用于显示当前的输入
private String strUpper = ""; //上层文本
private String strUnder = ""; //下层文本
private String x = "";
public static void main(String[] args) {
Calculater frame = new Calculater();
frame.setVisible(true);
//frame.setResizable(false); //不可更改窗口大小
}
public Calculater() {
setTitle("简易计算器");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 416, 620);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JPanel paneText = new JPanel(); //添加文本窗格
paneText.setBounds(0, 0, 400, 170);
contentPane.add(paneText);
paneText.setLayout(null);
txtUpper = new JTextField(strUpper); //添加上方文本框
txtUpper.setHorizontalAlignment(JTextField.RIGHT); //设置文本右对齐
txtUpper.setFont(new Font("Consolas", Font.PLAIN, 30));
txtUpper.setEditable(false);
txtUpper.setBounds(0, 0, 400, 65);
paneText.add(txtUpper);
txtUnder = new JTextField(strUnder); //添加下方文本框
txtUnder.setHorizontalAlignment(JTextField.RIGHT); //设置文本右对齐
txtUnder.setFont(new Font("Consolas", Font.PLAIN, 50));
txtUnder.setEditable(false);
txtUnder.setBounds(0, 65, 400, 105);
paneText.add(txtUnder);
JPanel PaneButton = new JPanel(); //添加按键窗格
PaneButton.setBounds(0, 170, 400, 412);
contentPane.add(PaneButton);
PaneButton.setLayout(new GridLayout(6, 4, 0, 0));
String[] btn = {"(",")","历史","记录","%","CE","Del","*", //设置按键文字
"7","8","9","/","4","5","6","+",
"1","2","3","-","±","0",".","="};
for(int i=0;i<btn.length;i++) { //添加按键
Button button = new Button(btn[i]);
button.setFont(new Font("Consolas", Font.PLAIN, 25));
button.addActionListener(new btnActionListener()); //添加监听器
//button.addKeyListener(new btnKeyListener());
PaneButton.add(button);
}
}
class btnActionListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
//如果按下‘=’则flag设为真,清空上下文本框,再设置flag为假。
if(flag) {
strUnder = "";
strUpper = "";
flag = false;
}
/**
* point
每个运算数只能有一个小数点。在下一次使用加减乘除和括号前小数点都失效
*/
char a = cmd.charAt(0);
if(point && cmd.length()==1 && (a<'0'||a>'9') && a!='.') { //当point为真(使用过小数点了)并且a 为非小数点的运算符
// (并利用长度为1来限制CE和Del还有“历史记录”这几个按钮)时将point置为假。
point = false;
}
/**清空键,将上下文本框清空,等待下次输入。*/
if(cmd.equals("CE")) {
strUpper = "";
strUnder = "";
}
/**删除键,将下方文本框中的最后一个字符(若存在)*/
//删掉,但无法删除上方文本框的字符。
else if (cmd.equals("Del")) {
if(strUnder.length()>0) {
strUnder = strUnder.substring(0,strUnder.length()-1);
}
}
/**基本运算符*/
else if(cmd.equals("+")||cmd.equals("-")||cmd.equals("*")||cmd.equals("/")) {//如果按了运算符
char s = ' ';
if(!strUnder.isEmpty()) { //获取下方文本框最后字符
s = strUnder.charAt(strUnder.length()-1);
}
if(strUpper.isEmpty()&&strUnder.isEmpty()) {} //上下均空时运算符按键失效
else if(!strUnder.isEmpty()&&(s=='+'||s=='-'||s=='*'||s=='/')) { //当已经输入一个运算符时,再次输入视为运算符更新
strUnder = strUnder.substring(0,strUnder.length()-1)+cmd;
}
else if (!strUnder.isEmpty()&&strUnder.charAt(strUnder.length()-1)=='.'){}
else if (!strUnder.isEmpty()&&strUnder.charAt(strUnder.length()-1)=='('){}
else if(!strUnder.isEmpty()&&strUnder.charAt(0)!='(') {
strUpper += strUnder;
strUnder = cmd;
}
else {//下空上不空(右括号情况)以及开头左括号情况时在下括号添加运算符
strUnder += cmd;
}
}
/**左括号按键*/
else if(cmd.equals("(")) {
if ((!strUnder.isEmpty())&&(strUnder.charAt(strUnder.length()-1)<='9')&&(strUnder.charAt(strUnder.length()-1)>'0')){//如果数字后按左括号
//则会自动在左括号前加乘号
strUpper = strUnder+"*";
strUnder = cmd;
}
else if ((!strUnder.isEmpty())&&strUnder.charAt(strUnder.length()-1)=='.'){}//小数点后不能直接加左括号
else{
strUpper += strUnder;
strUnder = cmd;
}
}
/**右括号按键,将下方文本框内容上移*/
else if(cmd.equals(")")) {
if (strUnder.charAt(0)!='('){}//如果没有左括号,右括号失效
else if (strUnder.charAt(strUnder.length()-1)>'9'||strUnder.charAt(strUnder.length()-1)<'0'){}
//如果前一个字符是运算符
else {
strUpper = strUpper + strUnder + ")";
strUnder = "";}
}
/**百分号按键,当下层问空时百分号键失效
*
*/
else if (cmd.equals("%")) {}
/**正负号按键,在下方文本框中的文本前加上“(-”
* */
else if (cmd.equals("±")) {
strUnder = strUnder + "(-";
}
/**历史记录按键*/
else if (cmd.equals("历史")||cmd.equals("记录")){
JDialog frame = new JDialog();
frame.setBounds(100,100,600,600);
JTextArea jt = new JTextArea();
JScrollPane scrollPane = new JScrollPane(jt);
frame.getContentPane().add(scrollPane);
jt.setText(x);
jt.setFont(new Font("Consolas", Font.PLAIN, 30));
frame.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
frame.setVisible(true);
}
/**小数点按键。若point为真,按键失效。否则,下方文本框添加
小数点并point的值赋为真,开始生效。另外,若按下小数点时
表达式为空或前一位非数字,则自动在小数点前添加数字0。*/
else if(cmd.equals(".")) {
if(point) {return;}
else if(strUnder.isEmpty()&&!strUpper.isEmpty()) {}//下层为空上层非空时小数点按键失效。(避免右括号之后输入数字)
else if(strUnder.isEmpty()) {//若下层为空则自动添0
strUnder += "0.";
point = true;
}
else {
char t = strUnder.charAt(strUnder.length()-1);//记录最后一个字符
if(t<'0'||t>'9') {//若为操作符,则自动添0
strUpper += strUnder;
strUnder = "0.";
}
else strUnder += ".";
point = true;
}
}
/**等于号按键,按下即触发计算表达式,并将flag赋为真,下次点
击任何按键将清空上下文本框。*/
else if (cmd.equals("=")) {
if(strUnder.isEmpty()&&strUpper.isEmpty()) {
return;
}
flag = true;
strUpper += strUnder;
strUnder = CalculatorUtil.calc(strUpper);//计算结果
x = x+"\r\n" +strUpper+"="+strUnder;
if (strUnder.isEmpty()||strUpper.isEmpty()){
x = x;
}
}
/**数字按键*/
else {
if(strUnder.isEmpty()&&!strUpper.isEmpty()) {}//下层为空上层非空时数字键失效(按下右括号的情况,右括号后面不能马上接数字)
else if(strUnder.isEmpty()) {
strUnder += cmd;
}
else {
char t = strUnder.charAt(strUnder.length()-1);//其他情况时获取下文本框最后一个字符
if((t=='+'||t=='-'||t=='*'||t=='/') && (strUnder.charAt(0)!='(')) {//如果最后一个字符是运算符,且开头没有左括号
strUpper += strUnder;//则将其上移
strUnder = cmd;//下文本框更新为运算符
}
else {
strUnder += cmd;
}
}
}
txtUpper.setText(strUpper); //更新上方文本框的文本
if(strUpper.length()>23) {
txtUpper.setFont(new Font("Consolas", Font.PLAIN, 690/strUpper.length()));
}
else {
txtUpper.setFont(new Font("Consolas", Font.PLAIN, 30));
}
txtUnder.setText(strUnder); //更新下方文本框的文本
if(strUnder.length()>15) {
txtUnder.setFont(new Font("Consolas", Font.PLAIN, 700/strUnder.length()));
}
else {
txtUnder.setFont(new Font("Consolas", Font.PLAIN, 50));
}
}
}
package Calculator;//@Calculate.java
import java.util.Stack;
import java.util.StringTokenizer;
public class CalculatorUtil {
public static String calc(String str) {
if (checkString(str) == false) { //检查括号匹配
return "error";
}
str = getcalc(str); //进行计算(此时仅包含基本运算符和小括号)
if(str.equals("error")||str.equals("Devide 0")) {
return str;
}
java.text.DecimalFormat format = new java.text.DecimalFormat("#,###.######");//数值格式化
return format.format(Double.parseDouble(str));
}
/**
检查左右小括号的匹配
*/
private static boolean checkString(String str) {
// 检查括号括号匹配
Stack<Character> sta = new Stack<Character>();
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '(') {//找到左括号就入栈
sta.push(str.charAt(i));
} else if (str.charAt(i) == ')') {//如果找到右括号
if (sta.empty() || sta.peek() != '(') {//判断如果栈空或者没有左括号,说明右括号多了
return false;
} else {
sta.pop();//左括号出栈
}
}
}
if (sta.size() > 0)//遍历完后还有左括号没有出栈,说明左括号多了
return false;
return true;
}
/**
并将负号做处理以便计算。
*/
private static String Preprocess(String str) {
for (int i = 0; i < str.length()-1; i++) {
if (str.charAt(i) == '(' && str.charAt(i + 1) == '-') { //将“(-”转化为“(0-”
str = str.substring(0, i + 1) + "0" + str.substring(i + 1, str.length());
}
}
return str;
}
private static String getcalc(String str) {
if (str.isEmpty()) {
return str;
}
/**
* 将中缀表达式转换为后缀表达式,并在运算数与运算符之间
* 添加分隔符‘$’,最后进行后缀表达式的计算。中缀表达式
* 储存在str中,后缀表达式储存在s中。
*/
Stack<Character> sta = new Stack<Character>();
String s = "$";
int i = 0;
if (str.charAt(0) == '(') {
sta.push('(');
i++;
}
boolean flag = false;
for (; i < str.length(); i++) {
if (str.charAt(i) == '+' && (i == 0 || (str.charAt(i - 1) < '0' && str.charAt(i - 1) != ')')))
i++;
if (str.charAt(i) == '-') {
flag = true;
i++;
}
while (i < (int) str.length() && ((str.charAt(i) >= '0' && str.charAt(i) <= '9') || str.charAt(i) == '.' || str.charAt(i)=='E')) {
if (flag) {
s += "-$";
flag = false;
}
s += str.charAt(i);
i++;
}
s += "$";
if (i < (int) str.length()) {
if (sta.empty() || str.charAt(i) == '(')
sta.push(str.charAt(i));
else if (str.charAt(i) == '+' || str.charAt(i) == '-') {
while (sta.size() > 0 && sta.peek() != '(') {
s += sta.pop() + "$";
}
sta.push(str.charAt(i));
} else if (str.charAt(i) == '*' || str.charAt(i) == '/') {
while (sta.size() > 0 && (sta.peek() == '*' || sta.peek() == '/')) {
s += sta.pop() + "$";
}
sta.push(str.charAt(i));
} else {
while (sta.size() > 0 && sta.peek() != '(') {
s += sta.pop() + "$";
}
sta.pop();
}
}
}
while (sta.size() > 0) {
s += sta.pop() + "$";
}
/**进行后缀表达式的计算
*/
Stack<Double> stack = new Stack<Double>();
StringTokenizer token = new StringTokenizer(s, "$", false);
while (token.hasMoreTokens()) {
String t = token.nextToken();
if((t.equals("+")||t.equals("-")||t.equals("*")||t.equals("/"))&&stack.size()<2) {
return "error";
}
if (t.equals("+")) {
stack.push(stack.pop() + stack.pop());
} else if (t.equals("-")) {
double a = stack.pop();
stack.push(stack.pop() - a);
} else if (t.equals("*")) {
stack.push(stack.pop() * stack.pop());
} else if (t.equals("/")) {
double a = stack.pop();
if(Math.abs(a-0)<1E-6) {
return "Devide 0";
}
stack.push(stack.pop() / a);
} else {
stack.push(Double.parseDouble(t));
}
}
double c = stack.pop();
if(sta.size()>0) {
return "error";
}
return String.valueOf(c);
}
}