如何用Java的swing編寫簡單計算器
前言
本文用Java的swing來實現(xiàn)一個簡單計算器,主要內容為圖形用戶界面GUI的實現(xiàn)以及運算表達式核心算法的設計編寫。
程序運行環(huán)境為Windows10 ,編譯環(huán)境為IntelliJ IDEA Community Edition 2022.2.3
一、具體功能:
1、:輸入,輸出
輸入:允許輸入帶有括號的完整計算式(例 8*(4-95)+5÷2*e-pi)
輸出:輸出Double類型的結果
輸出:整個運算表達式并保存于歷史記錄中
2、:功能
基本的加,減,乘,除,四則運算
平方運算
開方運算
求余運算
最終界面如下圖:
除了常規(guī)的數字按鈕和運算符,還有兩個常數e,pi(π),清空鍵AC,括號運算符(),平方(x^x)和開方(sqrt)運算符,輸入顯示框以及歷史記錄文本框,文本框的垂直滾動條和水平滾動條。
二、主要思想:
1:中綴表達式轉為后綴表達式
準備:
①后綴表達式隊列:postQueue,用于存儲逆波蘭表達式(其實不用隊列排序直接輸出也行)
②操作符棧:opStack,對用戶輸入的操作符進行處理,用于存儲運算符
算法思想:
從左向右依次讀取算術表達式的元素X,分以下情況進行不同的處理:
(1)如果X是操作數,直接入隊
(2)如果X是運算符,再分以下情況:
a)如果棧為空,直接入棧。
b)如果X==”(“,直接入棧。
c)如果X==”)“,則將棧里的元素逐個出棧,并入隊到后綴表達式隊列中,直到第一個配對的”(”出棧。(注:“(”和“)”都不 入隊)
d)如果是其他操作符(+ - * /),則和棧頂元素進行比較優(yōu)先級。 如果棧頂元素的優(yōu)先級大于等于X,則出棧并把棧中彈出的元素入隊,直到棧頂元素的優(yōu)先級小于X或者棧為空。彈出完這些元素后,才將遇到的操作符壓入到棧中。
(3)最后將棧中剩余的操作符全部入隊。
示意圖:
2、計算后綴表達式
準備:
需要用到一個結果棧Res_Stack :用于存放計算的中間過程的值和最終結果
算法思想:
1、從左開始向右遍歷后綴表達式的元素。
2、如果取到的元素是操作數,直接入棧Res_Stack,如果是運算符,從棧中彈出2個數進行運算,然后把運算結果入棧
3、當遍歷完后綴表達式時,計算結果就保存在棧里了。
示意圖:
三、結果測試
分析:
1、可實現(xiàn)基本四則運算及平方、開方、求余運算。
2、運算表達式可顯示于輸入界面并保存于歷史記錄欄
3、輸入界面和歷史記錄欄皆可實現(xiàn)不斷字自動換行功能以及滾動條功能
4、不足之處:進行平方和開方運算時其保存在歷史記錄中的表達式會出現(xiàn)兩個等號及兩個結果。
四、完整源代碼
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.*; import java.util.stream.Collectors; public class Calculator extends JFrame implements ActionListener { Calculator() { init(); } /** * 定義按鈕 */ private JTextField textField1; private JTextArea textField2; private JButton buttonzuo;//( private JButton buttonyou;//) private JButton buttonC;//c private JButton buttonCE;//CE private JButton buttondele;//<- 刪除 private JButton buttonDiv;//÷ private JButton button7;//7 private JButton button8;//8 private JButton button9;//9 private JButton buttonAdd;//+ private JButton button4;//4 private JButton button5;//5 private JButton button6;//6 private JButton buttonSub;//- private JButton button1;//1 private JButton button2;//2 private JButton button3;//3 private JButton buttonMul;//x private JButton buttonequl;//= private JButton button0;//0 private JButton buttonPoint;//. public void init() { JFrame frame = new JFrame("The Calculator Of 崔登輝"); //普通窗口頂層容器 創(chuàng)建標題為“計算器”; frame.setLayout(null); //設置使用特定的布局管理器; //單選項按鈕 //按鍵的排版以及設計需要提前考慮整體的布局合理性,不可出現(xiàn)按鍵重疊;為了保證美觀又需要考慮排版整齊; //放置數字0 button0 = new JButton("0"); //注:在給按鍵命名時要根據按鍵的大小,否則按鍵上的標注無法完全顯示; button0.setBounds(100, 400, 110, 50); frame.add(button0); //放置數字1 button1 = new JButton("1"); button1.setBounds(40, 340, 50, 50); frame.add(button1); //放置數字2 button2 = new JButton("2"); button2.setBounds(100, 340, 50, 50); frame.add(button2); //放置數字3 button3 = new JButton("3"); button3.setBounds(160, 340, 50, 50); frame.add(button3); //放置數字4 button4 = new JButton("4"); button4.setBounds(40, 280, 50, 50); frame.add(button4); //放置數字5 button5 = new JButton("5"); button5.setBounds(100, 280, 50, 50); frame.add(button5); //放置數字6 button6 = new JButton("6"); button6.setBounds(160, 280, 50, 50); frame.add(button6); //放置數字7 button7 = new JButton("7"); button7.setBounds(40, 220, 50, 50); frame.add(button7); //放置數字8 button8 = new JButton("8"); button8.setBounds(100, 220, 50, 50); frame.add(button8); //放置數字9 button9 = new JButton("9"); button9.setBounds(160, 220, 50, 50); frame.add(button9); //放置 . buttonPoint = new JButton("."); //text:為自動生成的參數的解釋詞 buttonPoint.setBounds(40, 400, 50, 50); //自動補齊的參數解釋詞 frame.add(buttonPoint); //放置 + buttonAdd = new JButton("+"); buttonAdd.setBounds(220, 400, 50, 50); frame.add(buttonAdd); //放置 - buttonSub = new JButton("-"); buttonSub.setBounds(220, 340, 50, 50); frame.add(buttonSub); //放置 * buttonMul = new JButton("*"); buttonMul.setBounds(220, 280, 50, 50); frame.add(buttonMul); //放置 / buttonDiv = new JButton("/"); buttonDiv.setBounds(220, 220, 50, 50); frame.add(buttonDiv); //放置 = buttonequl = new JButton("="); buttonequl.setBounds(280, 340, 110, 110); frame.add(buttonequl); //退位鍵 buttondele = new JButton("B"); buttondele.setBounds(280, 220, 110, 110); frame.add(buttondele); //放置左括號( buttonzuo = new JButton("("); buttonzuo.setBounds(40, 160, 80, 50); frame.add(buttonzuo); //放置右括號) buttonyou = new JButton(")"); buttonyou.setBounds(130, 160, 80, 50); frame.add(buttonyou); //放置C 消除所有輸入 buttonC = new JButton("C"); buttonC.setBounds(220, 160, 80, 50); frame.add(buttonC); //放置CE 消除當前輸入 buttonCE = new JButton("CE"); buttonCE.setBounds(310, 160, 80, 50); frame.add(buttonCE); //添加表達式文本框 用以輸入計算公式 textField1 = new JTextField(); //文本框 textField1.setBounds(40, 20, 350, 60); frame.add(textField1); textField2 = new JTextArea(); textField2.setBounds(400, 20, 280, 430); frame.add(textField2); textField1.addActionListener(this); buttonzuo.addActionListener(this); buttonyou.addActionListener(this); buttonC.addActionListener(this); buttonCE.addActionListener(this); buttondele.addActionListener(this); buttonDiv.addActionListener(this); button7.addActionListener(this); button8.addActionListener(this); button9.addActionListener(this); buttonAdd.addActionListener(this); button4.addActionListener(this); button5.addActionListener(this); button6.addActionListener(this); buttonSub.addActionListener(this); button1.addActionListener(this); button2.addActionListener(this); button3.addActionListener(this); buttonMul.addActionListener(this); buttonequl.addActionListener(this); button0.addActionListener(this); buttonPoint.addActionListener(this); frame.setBounds(0, 0, 700, 520); //設置整個圖形窗口的大??;(通過窗口名調用) frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE),當點擊窗口的關閉按鈕時退出程序(沒有這一句,程序不會退出) frame.setVisible(true); } String str = null; int pointbook = 0; int equalbook = 0; int zuonum = 0; int younum = 0; int equnum = 0; public void actionPerformed(ActionEvent e) { if (equnum == 1) { textField1.setText("0"); equnum = 0; } //按0 if (e.getSource().equals(button0)) { str = textField1.getText(); if (str.length() > 16 || str.equals("0") || equalbook == 1) { } else { textField1.setText(str + "0"); } } //按1 if (e.getSource().equals(button1)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("1"); } else { textField1.setText(str + "1"); } } //當按鈕為2時 if (e.getSource().equals(button2)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("2"); } else { textField1.setText(str + "2"); } } //當按鈕為3時 if (e.getSource().equals(button3)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("3"); } else { textField1.setText(str + "3"); } } //當按鈕為4時 if (e.getSource().equals(button4)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("4"); } else { textField1.setText(str + "4"); } } //當按鈕為5時 if (e.getSource().equals(button5)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("5"); } else { textField1.setText(str + "5"); } } //當按鈕為6時 if (e.getSource().equals(button6)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("6"); } else { textField1.setText(str + "6"); } } //當按鈕為7時 if (e.getSource().equals(button7)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("7"); } else { textField1.setText(str + "7"); } } //當按鈕為8時 if (e.getSource().equals(button8)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("8"); } else { textField1.setText(str + "8"); } } //當按鈕為9時 if (e.getSource().equals(button9)) { str = textField1.getText(); if (str.length() > 16 || equalbook == 1) { } else if (str.equals("0") || str.equals("")) { textField1.setText("9"); } else { textField1.setText(str + "9"); } } //當按鈕為小數點時 if (e.getSource().equals(buttonPoint)) { str = textField1.getText(); if (str.length() > 15 || equalbook == 1) { //小數點位于操作數的最后一位不執(zhí)行操作; } if (pointbook == 0) { //一個操作數僅能有一個小數點,若已經有小數點則不再添加小數點; textField1.setText(str + "."); pointbook = 1; //小數點判斷位置1; } } //每次輸入都是一個數字+運算符,一起從數字文本框轉而輸入到表達式文本框中; //當按鈕為加號時 if (e.getSource().equals(buttonAdd)) { str = textField1.getText(); //獲取運算符前一個操作數; char ch1[] = str.toCharArray(); //把第一操作數連同+號 進行字符串轉字符數組的操作 賦予ch1; int length1 = str.length() - 1; //length1獲取除+號外的第一操作數的位數; if ((length1 == -1 || ch1[length1] != ')') && (str.equals("0") || str.equals("") || ch1[length1] == '.' || ch1[length1] == '+' || ch1[length1] == '-' || ch1[length1] == '*' || ch1[length1] == '/' || ch1[length1] == '(' || ch1[length1] == ')')) { //當數字為空或為0(操作無意義);或數字的最后一位是小數點(未輸入完畢或輸入出錯,等待) } else { textField1.setText(str + "+"); //合并現(xiàn)有表達式和新增表達式 // 這里解釋以下為什么s沒有提取到數字框里的符號,因為輸入符號時并沒有更新數字框,而是直接執(zhí)行一系列操作,數字框從未出現(xiàn)過運算符; } pointbook = 0; } //當按鈕為減號時 if (e.getSource().equals(buttonSub)) { str = textField1.getText(); char ch1[] = str.toCharArray(); int length1 = str.length() - 1; if ((length1 == -1 || ch1[length1] != ')') && (ch1[length1] == '.' || ch1[length1] == '+' || ch1[length1] == '-' || ch1[length1] == '*' || ch1[length1] == '/' || ch1[length1] == '(' || ch1[length1] == ')')) { } else { textField1.setText(str + "-"); } pointbook = 0; } //當按鈕為乘號時 if (e.getSource().equals(buttonMul)) { str = textField1.getText(); char ch1[] = str.toCharArray(); int length1 = str.length() - 1; if ((length1 == -1 || ch1[length1] != ')') && (str.equals("0") || str.equals("") || ch1[length1] == '.' || ch1[length1] == '+' || ch1[length1] == '-' || ch1[length1] == '*' || ch1[length1] == '/' || ch1[length1] == '(' || ch1[length1] == ')')) { } else { textField1.setText(str + "*"); } pointbook = 0; } //當按鈕為除號時 if (e.getSource().equals(buttonDiv)) { str = textField1.getText(); char ch1[] = str.toCharArray(); int length1 = str.length() - 1; if ((length1 == -1 || ch1[length1] != ')') && (str.equals("0") || str.equals("") || ch1[length1] == '.' || ch1[length1] == '+' || ch1[length1] == '-' || ch1[length1] == '*' || ch1[length1] == '/' || ch1[length1] == '(' || ch1[length1] == ')')) { } else { textField1.setText(str + "/"); } pointbook = 0; } //當按鈕為左括號時 if (e.getSource().equals(buttonzuo)) { str = textField1.getText(); char ch[] = str.toCharArray(); int length = str.length() - 1; if (length == -1 || ch[length] == '+' || ch[length] == '-' || ch[length] == '*' || ch[length] == '/') { //括號左邊是否有數或符號類別的判斷; textField1.setText(str + '('); //滿足條件則加入左括號; zuonum++; //左括號數加一標記; } if (length == -1 || ch[length] == '+' || ch[length] == '-' || ch[length] == '*' || ch[length] == '/') pointbook = 0; if (length == 0 || ch[length] == 0) { textField1.setText("("); zuonum++; } } //當按鈕為右括號時; if (e.getSource().equals(buttonyou)) { str = textField1.getText(); char ch[] = str.toCharArray(); int length = str.length() - 1; if (Character.isDigit(ch[length]) && zuonum > younum) { //只有前面是數字的時候且左括號的數量大于右括號的數量的時候才能加右括號; younum++; //右括號數加一標記; textField1.setText(str + ')'); } pointbook = 0; } //當按下C鍵時; if (e.getSource().equals(buttonC)) { textField1.setText("0"); //置當前數字框為0; zuonum = 0; //當一次計算完成之后,只有按CE按鈕才能進行新的計算,因為要清除所有標志位否則會影響下一次操作; younum = 0; pointbook = 0; equalbook = 0; textField2.setText(" "); } //當按鈕為CE時, if (e.getSource().equals(buttonCE)) { textField1.setText("0"); //清除當前數字框中內容; pointbook = 0; //更新小數點狀態(tài)為0; } //當按下B時, if (e.getSource().equals(buttondele)) { str = textField1.getText(); char []nums=str.toCharArray(); if (nums[str.length()-1]=='('){ zuonum--; } str = str.substring(0, str.length() - 1); textField1.setText(str); } //當按下=時, if (e.getSource().equals(buttonequl)) { str = textField1.getText(); if (zuonum != younum) { textField1.setText("關系式錯誤。"); } else { ans(str); } String s = str + "=" + textField1.getText(); textField2.setText(s + "\r\n" + textField2.getText()); //將表達式存放在歷史記錄里。 equnum = 1; } } /** * 提前將 符號的優(yōu)先級定義好 */ private static final Map<Character, Integer> basic = new HashMap<Character, Integer>(); static { basic.put('-', 1); basic.put('+', 1); basic.put('*', 2); basic.put('/', 2); basic.put('(', 0);//在運算中 ()的優(yōu)先級最高,但是此處因程序中需要 故設置為0 } public void ans(String str) { String a = toSuffix(str);//傳入 一串 算數公式 textField1.setText(dealEquation(a)); } /** * 將 中綴表達式 轉化為 后綴表達式 */ public String toSuffix(String infix) { List<String> queue = new ArrayList<String>(); //定義隊列 用于存儲 數字 以及最后的 后綴表達式 List<Character> stack = new ArrayList<Character>(); //定義棧 用于存儲 運算符 最后stack中會被 彈空 char[] charArr = infix.trim().toCharArray(); //字符數組 用于拆分數字或符號 String standard = "*/+-()"; //判定標準 將表達式中會出現(xiàn)的運算符寫出來 char ch = '&'; //在循環(huán)中用來保存 字符數組的當前循環(huán)變量的 這里僅僅是初始化一個值 沒有意義 int len = 0; //用于記錄字符長度 【例如100*2,則記錄的len為3 到時候截取字符串的前三位就是數字】 for (int i = 0; i < charArr.length; i++) { //開始迭代 ch = charArr[i]; //保存當前迭代變量 if (Character.isDigit(ch)) { //如果當前變量為 數字 len++; } else if (Character.isLetter(ch)) { //如果當前變量為 字母 len++; } else if (ch == '.') { //如果當前變量為 . 會出現(xiàn)在小數里面 len++; } else if (Character.isSpaceChar(ch)) { //如果當前變量為 空格 支持表達式中有空格出現(xiàn) if (len > 0) { //若為空格 代表 一段結束 ,就可以往隊列中 存入了 【例如100 * 2 100后面有空格 就可以將空格之前的存入隊列了】 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); //往 隊列存入 截取的 字符串 len = 0; //長度置空 } continue; //如果空格出現(xiàn),則一段結束 跳出本次循環(huán) } else if (standard.indexOf(ch) != -1) { //如果是上面標準中的 任意一個符號 if (len > 0) { //長度也有 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); //說明符號之前的可以截取下來做數字 len = 0; //長度置空 } if (ch == '(') { //如果是左括號 stack.add(ch); //將左括號 放入棧中 continue; //跳出本次循環(huán) 繼續(xù)找下一個位置 } if (!stack.isEmpty()) { //如果棧不為empty int size = stack.size() - 1; //獲取棧的大小-1 即代表棧最后一個元素的下標 boolean flag = false; //設置標志位 while (size >= 0 && ch == ')' && stack.get(size) != '(') { //若當前ch為右括號,則 棧里元素從棧頂一直彈出,直到彈出到 左括號 queue.add(String.valueOf(stack.remove(size))); //注意此處條件:ch并未入棧,所以并未插入隊列中;同樣直到找到左括號的時候,循環(huán)結束了,所以左括號也不會放入隊列中【也就是:后綴表達式中不會出現(xiàn)括號】 size--; //size-- 保證下標永遠在棧最后一個元素【棧中概念:指針永遠指在棧頂元素】 flag = true; //設置標志位為true 表明一直在?。ǎ┲械脑? } while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { //若取得不是()內的元素,并且當前棧頂元素的優(yōu)先級>=對比元素 那就出棧插入隊列 queue.add(String.valueOf(stack.remove(size))); //同樣 此處也是remove()方法,既能得到要獲取的元素,也能將棧中元素移除掉 size--; } } if (ch != ')') { //若當前元素不是右括號 stack.add(ch); //就要保證這個符號 入棧 } else { //否則就要出棧 棧內符號 stack.remove(stack.size() - 1); } } if (i == charArr.length - 1) { //如果已經走到了 中綴表達式的最后一位 if (len > 0) { //如果len>0 就截取數字 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len + 1, i + 1))); } int size = stack.size() - 1; //size表示棧內最后一個元素下標 while (size >= 0) { //一直將棧內 符號全部出棧 并且加入隊列中 【最終的后綴表達式是存放在隊列中的,而棧內最后會被彈空】 queue.add(String.valueOf(stack.remove(size))); size--; } } } return queue.stream().collect(Collectors.joining(",")); //將隊列中元素以,分割 返回字符串 } /** * 將 后綴表達式 進行 運算 計算出結果 * * @param equation * @return */ public String dealEquation(String equation) { String[] arr = equation.split(","); //根據, 拆分字符串 List<String> list = new ArrayList<String>(); //用于計算時 存儲運算過程的集合【例如list中當前放置 100 20 5 / 則取出20/5 最終將結果4存入list 此時list中結果為 100 4 】 for (int i = 0; i < arr.length; i++) { //此處就是上面說的運算過程, 因為list.remove的緣故,所以取出最后一個數個最后兩個數 都是size-2 int size = list.size(); switch (arr[i]) { case "+": double a = Double.parseDouble(list.remove(size - 2)) + Double.parseDouble(list.remove(size - 2)); list.add(String.valueOf(a)); break; case "-": double b = Double.parseDouble(list.remove(size - 2)) - Double.parseDouble(list.remove(size - 2)); list.add(String.valueOf(b)); break; case "*": double c = Double.parseDouble(list.remove(size - 2)) * Double.parseDouble(list.remove(size - 2)); list.add(String.valueOf(c)); break; case "/": double d = Double.parseDouble(list.remove(size - 2)) / Double.parseDouble(list.remove(size - 2)); list.add(String.valueOf(d)); break; default: list.add(arr[i]); break; //如果是數字 直接放進list中 } } return list.size() == 1 ? list.get(0) : "運算失敗"; //最終list中僅有一個結果,否則就是算錯了 } public static void main(String[] args) { Calculator calculator = new Calculator(); } }
總結
到此這篇關于如何用Java的swing編寫簡單計算器的文章就介紹到這了,更多相關Java簡單計算器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
spring boot整合redis實現(xiàn)RedisTemplate三分鐘快速入門
這篇文章主要介紹了spring boot整合redis實現(xiàn)RedisTemplate三分鐘快速入門,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12Spring Cloud Feign性能優(yōu)化代碼實例
這篇文章主要介紹了Spring Cloud Feign性能優(yōu)化代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-03-03Spring的UnsatisfiedDependencyException異常的解決
在使用Spring框架開發(fā)應用程序時,我們經常會遇到各種異常,本文主要介紹了Spring的UnsatisfiedDependencyException異常的解決,感興趣的可以了解一下2023-11-11微信js-sdk+JAVA實現(xiàn)“分享到朋友圈”和“發(fā)送給朋友”功能詳解
本文分享了微信js-sdk+JAVA實現(xiàn)“分享到朋友圈”和“發(fā)送給朋友”功能介紹,大家可以參考一下2018-03-03ExecutorService Callable Future多線程返回結果原理解析
這篇文章主要為大家介紹了ExecutorService Callable Future多線程返回結果,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09java、python、JavaScript以及jquery循環(huán)語句的區(qū)別
本篇文章主要介紹java、python、JavaScript以及jquery的循環(huán)語句的區(qū)別,這里整理了它們循環(huán)語句語法跟示例,以便大家閱讀,更好的區(qū)分它們的不同2016-07-07