java-swing程式設計,實現計算器——支援四則運算
阿新 • • 發佈:2019-01-30
==== 2018年4月19日 17:56:20 更新 ===
專案地址在:https://github.com/qiao1406/java_calcultor/tree/dev
這兩個星期學習了swing模組的一些內容,學習了java的GUI程式設計,自己動手寫了一個計算器
首先是整個計算器的圖形框架類CalFrame類
package Calculator; import java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JTextField; public class CalFrame extends JFrame { //配色 private final static Color OP_COLOR = new Color(251, 150, 110); private final static Color NUM_COLOR = new Color(36, 147, 190); private final static Color EQUAL_COLOR = new Color(239, 187, 36); private final static Color CLR_COLOR = new Color(50, 252, 75); private final static Color DEL_COLOR = new Color(0, 152, 120); private final static Font FONT1 = new Font("黑體", Font.BOLD, 20); private final static Font FONT2 = new Font("微軟雅黑", Font.PLAIN, 20); private final static Font FONT3 = new Font("微軟雅黑", Font.PLAIN, 15); private JButton num0 = new JButton("0"); private JButton num1 = new JButton("1"); private JButton num2 = new JButton("2"); private JButton num3 = new JButton("3"); private JButton num4 = new JButton("4"); private JButton num5 = new JButton("5"); private JButton num6 = new JButton("6"); private JButton num7 = new JButton("7"); private JButton num8 = new JButton("8"); private JButton num9 = new JButton("9"); private JButton decimalPoint = new JButton("."); private JButton addButton = new JButton("+"); private JButton minusButton = new JButton("-"); private JButton mulButton = new JButton("X"); private JButton divButton = new JButton("÷"); private JButton equalButton = new JButton("="); private JButton leftBracket = new JButton("("); private JButton rightBracket = new JButton(")"); private JButton clearButton = new JButton("Clear"); private JButton deleteButton = new JButton("Del"); private JLabel equationLabel = new JLabel("算式"); private JLabel resultLabel = new JLabel("結果"); private JTextArea equation = new JTextArea(2,30); private JTextArea result = new JTextArea(1,30); private JPanel jp1 = new JPanel(); private JPanel jp2 = new JPanel(); public CalFrame () { equation.setEditable(false); result.setEditable(false); //顏色,字型設定 colorAndFontSettings(); //新增動作 actionSettings(); //設定各個組成部分的位置 positionSettings(); //其他設定 setLayout( new GridLayout(2,1)); add(jp1); add(jp2); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); setTitle("QiaoCalculator v2.3"); setSize(500, 400); setLocation(200, 200); setVisible(true); } public static void main ( String[] args ) { new CalFrame(); } private void colorAndFontSettings () { equationLabel.setFont(FONT2); resultLabel.setFont(FONT2); equation.setFont(FONT3); result.setFont(FONT3); num0.setBackground(NUM_COLOR); num1.setBackground(NUM_COLOR); num2.setBackground(NUM_COLOR); num3.setBackground(NUM_COLOR); num4.setBackground(NUM_COLOR); num5.setBackground(NUM_COLOR); num6.setBackground(NUM_COLOR); num7.setBackground(NUM_COLOR); num8.setBackground(NUM_COLOR); num9.setBackground(NUM_COLOR); decimalPoint.setBackground(NUM_COLOR); addButton.setBackground(OP_COLOR); addButton.setFont(FONT1); minusButton.setBackground(OP_COLOR); minusButton.setFont(FONT1); mulButton.setBackground(OP_COLOR); mulButton.setFont(FONT1); divButton.setBackground(OP_COLOR); divButton.setFont(FONT1); leftBracket.setBackground(OP_COLOR); leftBracket.setFont(FONT1); rightBracket.setBackground(OP_COLOR); rightBracket.setFont(FONT1); equalButton.setBackground(EQUAL_COLOR); equalButton.setFont(FONT1); clearButton.setBackground(CLR_COLOR); deleteButton.setBackground(DEL_COLOR); } private void actionSettings () { num0.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "0"); } }); num1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "1"); } }); num2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "2"); } }); num3.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "3"); } }); num4.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "4"); } }); num5.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "5"); } }); num6.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "6"); } }); num7.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "7"); } }); num8.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "8"); } }); num9.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "9"); } }); decimalPoint.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "."); } }); addButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "+"); } }); minusButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "-"); } }); mulButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "X"); } }); divButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "÷"); } }); leftBracket.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + "("); } }); rightBracket.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(equation.getText() + ")"); } }); equalButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String cmd = equation.getText(); Calculate cl = new Calculate(); String resultMsg = cl.calResult(cmd); if ( resultMsg.equals("算式格式錯誤") || resultMsg.equals("除數不能為0") ) { JOptionPane.showMessageDialog(null, resultMsg, "錯誤", JOptionPane.WARNING_MESSAGE); } else { result.setText(resultMsg); } } }); clearButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { equation.setText(""); result.setText(""); } }); deleteButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if( !( equation.getText().equals("")) ) { StringBuffer sb = new StringBuffer(); sb.append(equation.getText()); sb.delete(sb.length()-1 , sb.length()); equation.setText(sb.toString()); } } }); } private void positionSettings () { jp1.add(equationLabel); jp1.add(equation); jp1.add(resultLabel); jp1.add(result); equationLabel.setBounds(0, 0, 50, 30); equationLabel.setLocation(0, 0); equation.setBounds(50, 0, 150, 30); equation.setLocation(50, 0); resultLabel.setBounds(0, 30, 50, 30); resultLabel.setLocation(0, 30); result.setBounds(50, 30, 150, 30); result.setLocation(50, 30); jp2.setLayout(new GridLayout(4, 5)); // line-1 jp2.add(num7); jp2.add(num8); jp2.add(num9); jp2.add(addButton); jp2.add(leftBracket); // line-2 jp2.add(num4); jp2.add(num5); jp2.add(num6); jp2.add(minusButton); jp2.add(rightBracket); // line-3 jp2.add(num1); jp2.add(num2); jp2.add(num3); jp2.add(mulButton); jp2.add(clearButton); // line-4 jp2.add(num0); jp2.add(decimalPoint); jp2.add(equalButton); jp2.add(divButton); jp2.add(deleteButton); jp1.setLocation(0, 0); jp1.setVisible(true); jp2.setLocation(0, 100); jp2.setVisible(true); } }
然後就是處理算式的類Calculate類,在處理算式的時候利用了某網友提供的演算法,之後打算自己用字尾表示式和二叉樹結構來重構這部分程式碼
package Calculator; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import sun.security.krb5.internal.ccache.CCacheInputStream; public class Calculate { private Stack<Double> numStack = new Stack<Double>(); private Stack<Character> sybStack = new Stack<Character>(); public String calResult ( String equation ) { //替換乘除號 equation = equation.replace("X", "*"); equation = equation.replace("÷", "/"); //處理負號 equation = negativeNumTransfer(equation); if ( !checkFormat(equation) ) { return "算式格式錯誤"; } equation += "#"; StringBuffer tempNum = new StringBuffer(); StringBuffer exp = new StringBuffer().append(equation); while ( exp.length() != 0 ) { String temp = exp.substring(0,1); exp.delete(0, 1); if( isNum(temp) ) { // temp是數字 tempNum.append(temp); } else { // temp不是數字 if (!"".equals(tempNum.toString())) { // 當表示式的第一個符號為括號 double num = Double.parseDouble(tempNum.toString()); numStack.push(num); tempNum.delete(0, tempNum.length()); } // 用當前取得的運算子與棧頂運算子比較優先順序:若高於,則因為會先運算,放入棧頂;若等於,因為出現在後面, // 所以會後計算,所以棧頂元素出棧,取出運算元運算;若小於,則同理,取出棧頂元素運算,將結果入運算元棧。 // 判斷當前運算子與棧頂元素優先順序,取出元素,進行計算(因為優先順序可能小於棧頂元素,還小於第二個元素等等,需要用迴圈判斷) while ( !compare(temp.charAt(0)) && (!sybStack.empty()) ) { double a = numStack.pop(); double b = numStack.pop(); char ope = sybStack.pop(); // 進行簡單的計算 if( simpleCal(ope, a, b) == false ) { return "除數不能為0"; } } // 判斷當前運算子與棧頂元素優先順序, 如果高,或者低於平,計算完後,將當前操作符號,放入操作符棧 refreshSybStack(temp); } } return getResultStr(numStack.pop()); } private void refreshSybStack ( String temp) { if (temp.charAt(0) != '#') { sybStack.push(new Character(temp.charAt(0))); if (temp.charAt(0) == ')') {// 當棧頂為'(',而當前元素為')'時,則是括號內以算完,去掉括號 sybStack.pop(); sybStack.pop(); } } } private boolean simpleCal ( char ope, double a, double b ) { double result = 0; switch (ope) { case '+': result = b + a; numStack.push(result); break; case '-': result = b - a; numStack.push(result); break; case '*': result = b * a; numStack.push(result); break; case '/': if ( a == 0.0 ) { return false; } else { result = b / a; numStack.push(result); break; } } return true; } private String negativeNumTransfer( String equation ) { // 處理算式,將表示負數的部分進行改動,轉成calResult方法支援的 if( equation.length() <= 1 ) { return equation; } StringBuffer str = new StringBuffer().append(equation); for ( int i = 0; i < str.length()-1; ++i ) { if( !str.substring(i, i+1).equals("-") ) { continue; } if ( i == 0 ) { char temp = str.charAt(1); if( isNumChar(temp) || isDecimalPoint(temp) || isLeftBracket(temp) ) { str.insert(0, "0"); i++; } } else { char last = str.charAt(i-1); char next = str.charAt(i+1); if( isLeftBracket(last) && ( isNumChar(next) || isDecimalPoint(next) || isLeftBracket(next) ) ) { str.insert(i, "0"); i++; } } } return str.toString(); } private boolean checkFormat ( String equation ) { char[] c = equation.toCharArray(); int singleBracket = 0; for( int i = 0; i < c.length; ++i ) { if( isLeftBracket(c[i]) ) { singleBracket++; } if ( isRightBracket(c[i]) ) { singleBracket--; } if ( i == 0 ) { //第1個元素只能是[0-9]或者是左括號 if( !isLeftBracket(c[i]) && !isNumChar(c[i]) ) { return false; } } else if ( isNumChar(c[i]) || isDecimalPoint(c[i]) ) { //數字左邊不能是右括號 if ( isRightBracket(c[i-1]) ) { return false; } } else if( isLeftBracket(c[i]) ) { // 左括號的左邊不能是數字和右括號 if ( isNumChar(c[i-1]) || isDecimalPoint(c[i-1]) || isRightBracket(c[i-1]) ) { return false; } } else { // 右括號和四則運算子的左邊只能是數字或者右括號 if ( !isNumChar(c[i-1]) && !isRightBracket(c[i-1]) ) { return false; } } } return singleBracket == 0; } private static boolean isNum ( String temp ) { return temp.matches("[0-9]") || temp.equals("."); } private static boolean isLeftBracket ( char c ) { return c == '('; } private static boolean isRightBracket ( char c ) { return c == ')'; } private static boolean isDecimalPoint ( char c ) { return c == '.'; } private static boolean isNumChar ( char c ) { return ( c >= '0' && c <= '9' ); } private boolean compare (char str) { if ( sybStack.empty() ) { // 當為空時,顯然 當前優先順序最低,返回高 return true; } char last = (char) sybStack.lastElement(); // 如果棧頂為'('顯然,優先順序最低,')'不可能為棧頂。 if (last == '(') { return true; } switch (str) { case '#': return false;// 結束符 case '(': // '('優先順序最高,顯然返回true return true; case ')': // ')'優先順序最低, return false; case '*': { // '*/'優先順序只比'+-'高 if (last == '+' || last == '-') return true; else return false; } case '/': { if (last == '+' || last == '-') return true; else return false; } // '+-'為最低,一直返回false case '+': return false; case '-': return false; } return true; } private String getResultStr ( double result ) { StringBuffer s = new StringBuffer().append( result + "" ); if ( s.substring(s.length() - 2).equals(".0") ) { s.delete( s.length()-2 , s.length() ); } return s.toString(); } }
附:版本資訊日誌
版本v1.0[2016年8月16日 07:01:32]
1.實現了兩個數之間的四則運算
2.添加了對除法中除數為0的處理
版本v1.1[2016年8月17日 05:01:18]
優化介面
給按鈕添加了顏色
版本v1.2[2016年8月17日 05:02:05]
進一步優化介面
增加異常處理
新增v1分支
版本v2.0[2016年8月25日 06:05:21]
增加了對四則運算的支援
增加了括號和小數點,資料型別改成double
優化了介面,式子和結果分行顯示
版本v2.1[2016年8月25日 19:35:08]
增加了對式子格式的檢查方法checkFormat
增加了對double型別除法0的判斷
優化程式碼結構,將Calculate類的calResult方法模組化
版本v2.2[2016年8月26日 23:28:49]
增加了對負數的支援
改變了字型,使得介面更加友好
版本v2.3[2016年8月27日 19:25:19]
將異常結果用彈窗的形式來呈現
優化程式碼結構,將CalFrame類的構造方法的程式碼進行模組化