Java实现的计算器(带括号和错误输入提示)

来源:互联网 发布:python 金融量化分析 编辑:程序博客网 时间:2024/06/05 08:27

虽然接触Java有两个月了,还没有自己好好写过像样的程序都是照着教程抄写调试一些程序,这是我在网上一些简单Java计算器源码增加解析括号功能和防止输入错误功能,借助Android计算器源码更改的计算器程序。虽然基本没有自己发明的部分,但代码是自己调试看懂添加备注的,所以记在这里,以备后面查阅。后面准备自己写一个Android版的计算器程序作为练手,菜鸟一个,,继续加油。这个小程序对Java界面设计和堆栈有一定的训练效果。


经过几个晚上的调试,终于完美出锅了,可能还有bug,如果你发现了请告知我!话不多说,直接诶上代码



/** * Title:   Calculator计算器程序 * @author  豌豆先生 * @time    2015.5.13 * Mail   jitsiang@163.com * */import java.awt.BorderLayout;import java.awt.Color;import java.awt.FlowLayout;import java.awt.GridBagConstraints;import java.awt.GridBagLayout;import java.awt.GridLayout;import java.awt.Insets;import java.awt.RenderingHints.Key;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.text.DecimalFormat;import java.util.ArrayList;import java.util.StringTokenizer;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JTextField;import javax.swing.LayoutFocusTraversalPolicy;import org.omg.CORBA.PRIVATE_MEMBER;public class Calculator extends JFrame implements ActionListener {private ArrayList<String> list;private final String[] KEYS = { "(", ")", "^", "7", "8", "9", "4", "5","6", "1", "2", "3", "0", ".", "π" };private final String[] CLEAR = { "AC", "Backspace" };private final String[] SYMBOL = { "/", "*", "-", "+" ,"="};private JButton keys[] = new JButton[KEYS.length];private JButton clear[] = new JButton[CLEAR.length];private JButton symbol[] = new JButton[SYMBOL.length];public JTextField resultText = new JTextField("0");private boolean vbegin = true;// 控制输入,true为重新输入,false为接着输入private boolean equals_flag = true;// true为未输入=,false表示输入=private boolean isContinueInput = true;// true为正确,可以继续输入,false错误,输入锁定final int MAXLEN = 500;final double  PI = 3.141592657;public Calculator() {super();init();this.setBackground(Color.LIGHT_GRAY);this.setTitle("计算器:豌豆先生");this.setLocation(500, 300);this.setResizable(false);this.pack();}private void init() {resultText.setHorizontalAlignment(JTextField.RIGHT);resultText.setEditable(false);resultText.setBackground(Color.white);list = new ArrayList<String>();initLayout();//界面设置initActionEvent();//添加组件事件处理,button响应}public void initLayout() {JPanel calckeysPanel = new JPanel();calckeysPanel.setLayout(new GridLayout(5, 3, 3, 3));for (int i = 0; i < KEYS.length; i++) {keys[i] = new JButton(KEYS[i]);calckeysPanel.add(keys[i]);keys[i].setForeground(Color.blue);}for (int i = 0; i < SYMBOL.length; i++) {symbol[i] = new JButton(SYMBOL[i]);symbol[i].setForeground(Color.red);}for (int i = 0; i < CLEAR.length; i++) {clear[i] = new JButton(CLEAR[i]);clear[i].setForeground(Color.red);}JPanel text = new JPanel();text.setLayout(new BorderLayout());text.add("Center", resultText);JPanel panel1 = new JPanel();panel1.setLayout(new GridBagLayout());GridBagConstraints gbc= new GridBagConstraints();//定义一个GridBagConstraintsgbc.fill = GridBagConstraints.BOTH;gbc.insets = new Insets(3, 3, 3, 3);gbc.gridx = 0;gbc.gridy = 0;//gbc.gridwidth = 1;//gbc.gridheight = 1;panel1.add(symbol[0], gbc);//  “/号”gbc.gridx = 1;gbc.gridy = 0;//gbc.gridwidth = 1;//gbc.gridheight = 1;panel1.add(clear[0], gbc);//  "AC"gbc.gridx = 0;gbc.gridy = 1;//gbc.gridwidth = 1;//gbc.gridheight = 1;panel1.add(symbol[1], gbc);//"*"gbc.gridx = 1;gbc.gridy = 1;gbc.gridwidth = 1;gbc.gridheight = 2;panel1.add(clear[1], gbc);//“backspace”gbc.gridx = 0;gbc.gridy = 2;gbc.gridwidth = 1;gbc.gridheight = 1;panel1.add(symbol[2], gbc);//“-”gbc.gridx = 0;gbc.gridy = 3;gbc.ipady = 33;panel1.add(symbol[3], gbc);//"+"gbc.gridx = 1;gbc.gridy = 3;//gbc.ipadx = 10;//gbc.ipady = 33;panel1.add(symbol[4], gbc);//"="getContentPane().setLayout(new BorderLayout(3, 3));getContentPane().add("Center", calckeysPanel);getContentPane().add("East", panel1);getContentPane().add("North", text);}public void initActionEvent() {for (int i = 0; i < KEYS.length; i++) {keys[i].addActionListener(this);}for (int i = 0; i < CLEAR.length; i++) {clear[i].addActionListener(this);}for (int i = 0; i < SYMBOL.length; i++) {symbol[i].addActionListener(this);}}//组建发生操作时调用public void actionPerformed(ActionEvent e) {String label = e.getActionCommand();if (label.equals(CLEAR[1])) {handleBackspace();} else if (label.equals(CLEAR[0])) {list.clear();resultText.setText("0");vbegin = true;equals_flag = true;} else {handle(label);}}private void handleBackspace() {String text = resultText.getText();list.add(text);int i = text.length();if (i > 0 && list.size() > 0) {text = text.substring(0, i - 1);list.remove(list.size() - 1); // 移除栈顶的那个元素if (text.length() == 0) {list.clear();resultText.setText("0");vbegin = true;equals_flag = true;} else {resultText.setText(text);}}}public void handle(String key) {String text = resultText.getText();if (equals_flag == false) { //&& "π0123456789.()+-*/^".indexOf(key) != -1list.add(text);vbegin = false;// ?????????????}if (!list.isEmpty()) {TipChecker(list.get(list.size() - 1), key);} else {TipChecker("#", key);}if (isContinueInput && "π0123456789.()+-*/^".indexOf(key) != -1) {list.add(key);}// 若输入正确,则将输入信息显示到显示器上if (isContinueInput && "π0123456789.()+-*/^".indexOf(key) != -1) {if (equals_flag == false && ("+-*/^".indexOf(key) != -1)) {vbegin = false;equals_flag = true;printText(key);} else if (equals_flag == false&& ("π0123456789.()".indexOf(key) != -1)) {vbegin = true;equals_flag = true;printText(key);} else {printText(key);}} else if (isContinueInput && equals_flag && key.equals("=")) {isContinueInput = false;// 表明不可以继续输入equals_flag = false;// 表明已经输入=vbegin = true;// 重新输入标志设置trueprocess(resultText.getText()); // 整个程序的核心,计算表达式的值并显示list.clear();}isContinueInput = true;}private void printText(String key) {if (vbegin) {resultText.setText(key);// 清屏后输出// firstDigit = false;} else {resultText.setText(resultText.getText() + key);}vbegin = false;}/* * 检测函数,对str进行前后语法检测 为Tip的提示方式提供依据,与TipShow()配合使用 编号 字符 其后可以跟随的合法字符 1 ( * 数字|(|-|.|函数 2 ) 算符|)|  ^ 3 . 数字|算符|)|  ^ 4 数字 .|数字|算符|)|  ^ 5 算符 * 数字|(|.|函数 6   ^ ( |. | 数字 7 函数 数字|(|. *  * 小数点前后均可省略,表示0 数字第一位可以为0 */private void TipChecker(String tipcommand1, String tipcommand2) {// Tipcode1表示错误类型,Tipcode2表示名词解释类型int Tipcode1 = 0, Tipcode2 = 0;// 表示命令类型int tiptype1 = 0, tiptype2 = 0;// 括号数int bracket = 0;// “+-*/ ^”不能作为第一位if (tipcommand1.compareTo("#") == 0&& (tipcommand2.compareTo("/") == 0|| tipcommand2.compareTo("*") == 0|| tipcommand2.compareTo("+") == 0|| tipcommand2.compareTo(")") == 0 || tipcommand2.compareTo("^") == 0)) {Tipcode1 = -1;}// 定义存储字符串中最后一位的类型else if (tipcommand1.compareTo("#") != 0) {if (tipcommand1.compareTo("(") == 0) {tiptype1 = 1;} else if (tipcommand1.compareTo(")") == 0) {tiptype1 = 2;} else if (tipcommand1.compareTo(".") == 0) {tiptype1 = 3;} else if ("0123456789".indexOf(tipcommand1) != -1) {tiptype1 = 4;} else if ("+-*/".indexOf(tipcommand1) != -1) {tiptype1 = 5;} else if ("^".indexOf(tipcommand1) != -1) {tiptype1 = 6;}else if ("π".indexOf(tipcommand1) != -1){tiptype1 = 7;}// 定义欲输入的按键类型if (tipcommand2.compareTo("(") == 0) {tiptype2 = 1;} else if (tipcommand2.compareTo(")") == 0) {tiptype2 = 2;} else if (tipcommand2.compareTo(".") == 0) {tiptype2 = 3;} else if ("0123456789".indexOf(tipcommand2) != -1) {tiptype2 = 4;} else if ("+-*/".indexOf(tipcommand2) != -1) {tiptype2 = 5;} else if ("^".indexOf(tipcommand2) != -1) {tiptype2 = 6;}else if ("π".indexOf(tipcommand2) != -1){tiptype2 = 7;}switch (tiptype1) {case 1:// 左括号后面直接接右括号,“+*/”(负号“-”不算),或者" ^"if (tiptype2 == 2|| (tiptype2 == 5 && tipcommand2.compareTo("-") != 0)|| tiptype2 == 6)Tipcode1 = 1;break;case 2:// 右括号后面接左括号,数字,“+-*/^...π”if (tiptype2 == 1 || tiptype2 == 3 || tiptype2 == 4|| tiptype2 == 7)Tipcode1 = 2;break;case 3:// “.”后面接左括号,πif (tiptype2 == 1 || tiptype2 == 7)Tipcode1 = 3;// 连续输入两个“.”if (tiptype2 == 3)Tipcode1 = 8;break;case 4:// 数字后面直接接左括号和πif (tiptype2 == 1 || tiptype2 == 7)Tipcode1 = 4;break;case 5:// “+-*/”后面直接接右括号,“+-*/ ^”if (tiptype2 == 2 || tiptype2 == 5 || tiptype2 == 6)Tipcode1 = 5;break;case 6:// “ ^”后面直接接右括号,“+-*/ ^π”if (tiptype2 == 2 || tiptype2 == 5 || tiptype2 == 6 || tiptype2 == 7)Tipcode1 = 6;break;case 7://"π"之后只能为"+-*/^)"不能为"π(.0123456789"if (tiptype2 == 1 || tiptype2 == 3 || tiptype2 == 4 || tiptype2 == 7){Tipcode1 = 7;}break;}}// 检测小数点的重复性,Tipconde1=0,表明满足前面的规则if (Tipcode1 == 0 && tipcommand2.compareTo(".") == 0) {int tip_point = 0;for (int i = 0; i < list.size(); i++) {// 若之前出现一个小数点点,则小数点计数加1if (list.get(i).equals(".")) {tip_point++;}// 若出现以下几个运算符之一,小数点计数清零if (list.get(i).equals("^") || list.get(i).equals("/")|| list.get(i).equals("*") || list.get(i).equals("-")|| list.get(i).equals("+") || list.get(i).equals("(")|| list.get(i).equals(")")) {tip_point = 0;}}tip_point++;// 若小数点计数大于1,表明小数点重复了if (tip_point > 1) {Tipcode1 = 8;}}// 检测右括号是否匹配if (Tipcode1 == 0 && tipcommand2.compareTo(")") == 0) {int tip_right_bracket = 0;for (int i = 0; i < list.size(); i++) {// 如果出现一个左括号,则计数加1if (list.get(i).equals("(")) {tip_right_bracket++;}// 如果出现一个右括号,则计数减1if (list.get(i).equals(")")) {tip_right_bracket--;}}// 如果右括号计数=0,表明没有响应的左括号与当前右括号匹配if (tip_right_bracket == 0) {Tipcode1 = 10;}}// 检查输入=的合法性if (Tipcode1 == 0 && tipcommand2.compareTo("=") == 0) {// 括号匹配数int tip_bracket = 0;for (int i = 0; i < list.size(); i++) {if (list.get(i).equals("(")) {tip_bracket++;}if (list.get(i).equals(")")) {tip_bracket--;}}// 若大于0,表明左括号还有未匹配的if (tip_bracket > 0) {Tipcode1 = 9;bracket = tip_bracket;} else if (tip_bracket == 0) {// 若前一个字符是以下之一,表明=号不合法if ("+-*/".indexOf(tipcommand1) != -1) {Tipcode1 = 5;}}}if (Tipcode1 != 0) {isContinueInput = false;// 表明不可以继续输入}}/* * 计算表达式 从左向右扫描,数字入number栈,运算符入operator栈  * +-基本优先级为1, * ×÷基本优先级为2, * √^基本优先级为4  * 括号内层运算符比外层同级运算符优先级高4 * 当前运算符优先级高于栈顶压栈, * 低于栈顶弹出一个运算符与两个数进行运算 * 重复直到当前运算符大于栈顶 * 扫描完后对剩下的运算符与数字依次计算 */public void process(String str) {int weightPlus = 0, topOp = 0, topNum = 0, flag = 1, weightTemp = 0;// weightPlus为同一()下的基本优先级,weightTemp临时记录优先级的变化// topOp为weight[],operator[]的计数器;topNum为number[]的计数器// flag为正负数的计数器,1为正数,-1为负数int weight[]; // 保存operator栈中运算符的优先级,以topOp计数double number[]; // 保存数字,以topNum计数char ch, ch_gai, operator[];// operator[]保存运算符,以topOp计数String num;// 记录数字,str以+-*/() ! ^分段,+-*/() ^字符之间的字符串即为数字weight = new int[MAXLEN];number = new double[MAXLEN];operator = new char[MAXLEN];String expression = str.replace("π",String.valueOf(PI));//将字符串中的π用PI// 建议用split代替字符串分割StringTokenizer expToken = new StringTokenizer(expression, "+-*/()^");int i = 0;while (i < expression.length()) {ch = expression.charAt(i);// 判断正负数if (i == 0) {if (ch == '-')flag = -1;} else if (expression.charAt(i - 1) == '(' && ch == '-')flag = -1;// 取得数字,并将正负符号转移给数字,E是科学计数if (ch <= '9' && ch >= '0' || ch == '.' || ch == 'E') {num = expToken.nextToken();//分割后的StringTokenizer中的下一个索引数据ch_gai = ch;// 取得整个数字while (i < expression.length()&& (ch_gai <= '9' && ch_gai >= '0' || ch_gai == '.' || ch_gai == 'E')) {ch_gai = expression.charAt(i++);}// 将指针退回之前的位置,即每个数字的末尾位置if (i >= expression.length())i -= 1;else {i -= 2;}if (num.compareTo(".") == 0)number[topNum++] = 0;// 将正负符号转移给数字else {number[topNum++] = Double.parseDouble(num) * flag;flag = 1;}}// 计算运算符的优先级if (ch == '(')weightPlus += 4;if (ch == ')')weightPlus -= 4;if (ch == '-' && flag == 1 || ch == '+' || ch == '*' || ch == '/'|| ch == '^') {switch (ch) {// +-的优先级最低,为1case '+':case '-':weightTemp = 1 + weightPlus;break;// x/的优先级稍高,为2case '*':case '/':weightTemp = 2 + weightPlus;break;default:weightTemp = 4 + weightPlus;break;}// 如果当前优先级大于堆栈顶部元素,则直接入栈if (topOp == 0 || weight[topOp - 1] < weightTemp) {weight[topOp] = weightTemp;operator[topOp] = ch;topOp++;// 否则将堆栈中运算符逐个取出,直到当前堆栈顶部运算符的优先级小于当前运算符} else {while (topOp > 0 && weight[topOp - 1] >= weightTemp) {switch (operator[topOp - 1]) {// 取出数字数组的相应元素进行运算case '+':number[topNum - 2] += number[topNum - 1];break;case '-':number[topNum - 2] -= number[topNum - 1];break;case '*':number[topNum - 2] *= number[topNum - 1];break;// 判断除数为0的情况case '/':if (number[topNum - 1] == 0) {// showError(1, str_old);return;}number[topNum - 2] /= number[topNum - 1];break;case '^':number[topNum - 2] = Math.pow(number[topNum - 2],number[topNum - 1]);break;// 计算时进行角度弧度的判断及转换}// 继续取堆栈的下一个元素进行判断topNum--;topOp--;}// 将运算符入堆栈weight[topOp] = weightTemp;operator[topOp] = ch;topOp++;}}i++;}// 依次取出堆栈的运算符进行运算while (topOp > 0) {// +-x直接将数组的后两位数取出运算switch (operator[topOp - 1]) {case '+':number[topNum - 2] += number[topNum - 1];break;case '-':number[topNum - 2] -= number[topNum - 1];break;case '*':number[topNum - 2] *= number[topNum - 1];break;// 涉及到除法时要考虑除数不能为零的情况case '/':if (number[topNum - 1] == 0) {// showError(1, str_old);return;}number[topNum - 2] /= number[topNum - 1];break;case '^':number[topNum - 2] = Math.pow(number[topNum - 2],number[topNum - 1]);break;}// 取堆栈下一个元素计算topNum--;topOp--;}// 如果是数字太大,提示错误信息if (number[0] > 7.3E306) {// showError(3, str_old);return;}// 输出最终结果resultText.setText(String.valueOf(FP(number[0])));}public double FP(double n) {// NumberFormat format=NumberFormat.getInstance(); //创建一个格式化类f// format.setMaximumFractionDigits(18); //设置小数位的格式DecimalFormat format = new DecimalFormat("0.#############");return Double.parseDouble(format.format(n));}public static void main(String args[]) {Calculator calculator = new Calculator();calculator.setVisible(true);calculator.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}}





1 0
原创粉丝点击