運行結果:
基礎的四則運算:
可能會出現的問題以及解決方法:
?問題1:出現多個操作符。
例子:1++++++2
解決方法:
在用戶點擊操作符之后,去檢查之前的最后一位,如果最后一位也是操作符的話,就進行替代操作。
問題2:小數點問題。
例子:0......1? 以及 .2
解決方法:
對于0.....1的問題,用的是一個全局變量 addPoint,當它為true的時候才可以進行添加小數點操作。
當點擊 π 或者是 小數點之后 就要把 addPoint 置為false,也即表示不能再去添加小數點了。
當點擊操作符或者是C(清空)之后就要把 addPoint 置為false,也即表示可以再去添加小數點了。
問題3:非法操作。
例子:
1:除0
2:階乘溢出
3:負數開根號
4:logx, 其中x <= 0
5:(0.123)!
6:(-3)!
解決方法:
對每個運算進行提前監控,如果出現違規操作要把用戶的除了C(清空)按鈕外全部禁掉,然后做出違規提示,參考Win11自帶計算器。但是感覺更加規范的是 可以自定義異常 然后去對應到每一個的異常處理問題。
問題4:負數的復雜性
例子:-3 對這個實現起來還是比較麻煩的
解決方法:
對這個不進行特殊判斷,還是點擊 "-" 之后看看它的前面有沒有數字,如果沒有的話,也去補上0, 這個0是默認的。
新增括號功能:
對括號進行了顯示,以及可以進行括號運算。
在界面顯示出右括號和左括號的數量,而且右括號的數量數不能多于左括號的,參照win11自帶計算器。
可能出現的問題以及解決方法:
問題1:出現 (+)。
也即是括號里面只有操作符。
解決的方法:
1:當點擊運算符的時候,檢查它的前面是不是 "(", 如果是的話就去自動去補0。
2:當點擊 "(" 的時候,去檢查它的前面是不是 操作符,如果是的話就去自動補0 。
問題2:出現(0)(0)這樣的情況。
解決方法:
當用戶點擊 "(" 的時候去校驗當前已經存在的字符串的最后一位,如果它不是操作符的話,就去指定去補上一個操作符,我在這里默認的是 "x"。
問題3:出現0 + (-3) + 5 這樣的情況。
解決方法:
當用戶點擊操作符的時候,就去檢測當前已經存在的最后一個字符是不是數字,如果不是數字的話,就去補上一個默認的0,但是還會出現這樣的情況0 + (0 - 3) 0 + 3,它把0補到了這里了,這里再去加一個特殊的判斷,如果最后一個是 ")" 就不去加上這個默認的0。但是改為之后又出現了這樣的情況:0+(0)------------,解決的方法當這個最后一個字符是 "(" 的時候再去增加默認的0。??
聲明:
因為作者是一個考研dog,so 沒有足夠的時間去寫這個,只能晚上10回去之后加班寫,或者在其他老師課上寫,因此間隔時間比較大,而且邏輯比較亂,希望大家多多包涵。?
計劃:
1:后期可以去增加一個 按鍵聲音的功能,也即是你點擊一個按鈕之后,就會產生特定的生硬,當然聲音是作者自己那美妙的聲音。(已經實現,用的是在線生成的ai女聲)。
2:增加登錄操作,把每個人的計算的操作給記錄下來,可以查看自己歷史計算記錄。
java代碼:
package com.findyou.myapplication;import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.view.SoundEffectConstants;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;import java.math.BigInteger;
import java.util.HashMap;
import java.util.Objects;
import java.util.Stack;public class Test_jsq extends AppCompatActivity implements View.OnClickListener {private TextView tv_result, show_kh; // 獲取文本框的內容 為了進行設置// 第一個操作數// 第二個操作數// 運算符private String operator = "";// 結果private String result = "";// 顯示的文本內容 剛開始的時候要顯示的是 0private String showText = "0"; // 3+2private Boolean addPoint = true;private boolean denominatorIsZero = false; // 分母是否為0private final String ISZERO = "分母不可為0!";private final String FACTORIALERROR = "小數和分數沒有階乘,階乘只在自然數中進行";private final String OVERFLOW = "溢出";private final String NAGATIVE_HAS_NO_FACTORIAL = "負數沒有階乘";private final String NAGATIVE_HAS_NO_SQRT = "根號下要大于等于0";private final String LN_NEED_GREATER_THAN_ZERO = "ln里面需要大于0";private final String LON_NEED_GREATER_THAN_ZERO = "log里面需要大于0";// 新增加的 左右括號的顯示操作 初始化的括號的數量都顯示為 0private int leftParenthesis = 0, rightParenthesis = 0;// 以下是增加的聲音的功能// 定義一個全局的變量 看看用戶想不想去播放音效private Boolean play = true; // 表示的是 可以去播放音效private int currentId; // 為了記錄當前點擊了那個聲音了,是為了方便后面的暫停SoundPool sp; // 聲明SoundPool的引用HashMap<String, Integer> hm; // 聲明HashMap來存放聲音文件@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_calculator);initSoundPool(); // 初始化聲音池的方法// 獲取tv_result ctrl + alt + f 變為全局變量tv_result = findViewById(R.id.tv_result);show_kh = findViewById(R.id.show_kh); // 對括號的截取和顯示Button btn_cancel = findViewById(R.id.btn_cancel);btn_cancel.setOnClickListener(this);Button btn_sy = findViewById(R.id.sy);btn_sy.setOnClickListener(this);// 給每個按鈕設置監聽findViewById(R.id.btn_cancel).setOnClickListener(this);findViewById(R.id.btn_divide) .setOnClickListener(this);//“除法"按鈕findViewById(R.id.btn_multiply).setOnClickListener(this); // "乘法"按鈕findViewById(R.id.btn_clear) .setOnClickListener(this);findViewById(R.id.btn_seven).setOnClickListener(this); // 數字7findViewById(R.id.btn_eight).setOnClickListener(this); // 數字8findViewById(R.id.btn_nine).setOnClickListener(this); // 數字9findViewById(R.id.btn_plus) .setOnClickListener(this) ;findViewById(R.id.btn_four).setOnClickListener(this); // 數字4findViewById(R.id.btn_five).setOnClickListener(this); // 數字5findViewById(R.id.btn_six) .setOnClickListener(this); // 數字6findViewById(R.id.btn_minus).setOnClickListener(this);// "減法"按鈕findViewById(R.id.btn_one).setOnClickListener(this); // 數字1findViewById(R.id.btn_two).setOnClickListener(this); // 數字2findViewById(R.id.btn_three).setOnClickListener(this); // 數字3findViewById(R.id.btn_reciprocal).setOnClickListener(this);// 求倒數按鈕findViewById(R.id.btn_zero).setOnClickListener(this); // 數字0findViewById(R.id.btn_dot).setOnClickListener(this);// “小數點"按鈕findViewById(R.id.btn_equal).setOnClickListener(this);// "等號"按鈕findViewById(R.id.btn_sqrt) .setOnClickListener(this) ;// 開根號按鈕findViewById(R.id.btn_PI).setOnClickListener(this); // π按鈕的監聽findViewById(R.id.btn_factorial).setOnClickListener(this); // 階乘按鈕的監聽findViewById(R.id.btn_e).setOnClickListener(this); // e 按鈕的監聽findViewById(R.id.btn_abs).setOnClickListener(this); // 絕對值 按鈕的監聽// 新增加的功能findViewById(R.id.btn_left_kh).setOnClickListener(this); // 對左括號 按鈕進行監聽findViewById(R.id.btn_right_kh).setOnClickListener(this); // 對右括號 按鈕進行監聽findViewById(R.id.btn_log).setOnClickListener(this); // 對 log 按鈕 進行監聽findViewById(R.id.btn_ln).setOnClickListener(this); // 對 ln 按鈕進行監聽}// 變為公用的@Overridepublic void onClick(View v) {if(v.getId() == R.id.sy) {if(play) { // 要去關閉聲音了findViewById(R.id.sy).setBackground(ContextCompat.getDrawable(this, R.drawable.close));play = false;} else {findViewById(R.id.sy).setBackground(ContextCompat.getDrawable(this, R.drawable.open));play = true;}return;}// 測試 是否能正常顯示在界面 很好奇 為什么這個 測試的 沒有 ban 掉// tv_result.setText(((TextView) v).getText().toString());String inputText;// 如果是開根號的按鈕if (v.getId() == R.id.btn_sqrt) {inputText = "√";} else {inputText = ((TextView) v).getText().toString();}if(sp != null && currentId != 0) {sp.stop(currentId); // 立馬停止當前正在播放的聲音}if(play && !inputText.equals("=")) {// 點擊之后 開始在這里播放音樂playSound(inputText);}int t = v.getId();// 點擊了清空按鈕if (t == R.id.btn_clear) {// 清空的時候 要去恢復按鈕illegal(true);// 注意二者順序clear();// 也要去清空括號clearKh();} else if(t == R.id.btn_cancel) { // 后退按鈕// 注意 后退 是 不能 去進行 后退 操作符號 的showText = Backoff(showText);if(Objects.equals(showText, "")) {showText = "0"; // 最后一個都被清空了}// 刷新文本refreshText(showText);} else if(t == R.id.btn_plus || t == R.id.btn_minus || t == R.id.btn_multiply || t == R.id.btn_divide){ // 點擊了 加 減 乘 除// 如果操作符的前面是小數點的話 就要把小數點給省略掉 0.1 - 0. + ---> 0.1 - 0 +addPoint = true; // 把小數點可以更新了operator = inputText;char temp = showText.charAt(showText.length() - 1);// 每當進行 加減操作的時候 先去看看它的最后一個是不是有效的 不是有效的話 要去主動去增加一個 0 無論是小數點還是普通的加減// 增加的 這一個 可能出現了問題了// if(!checkIsNum(showText.charAt(showText.length() - 1)) && temp != '(' && temp != ')') {
// showText = showText + "0";
// }// 這里防止出現這樣的情況: (+0)的情況
// if(checkIskh(temp)) {
// showText = showText + "0";
// }// 檢查前面的最后一項是不是數字 如果不是數字的話 就去補上一個默認的0if(!checkIsNum(temp) && temp != ')' && !checkIsOp(temp)) {showText += "0";}// 查看當前這個字符串的最后一個 也是操作符的話 就把它給覆蓋掉if(checkIsOp(temp)) {// 就把當前的字符串的最后一個給替換掉showText = showText.substring(0, showText.length() - 1) + operator;refreshText(showText);} else {// 這里解決的是 0.-3 這樣的問題 解決的方法是把 小數點給去掉if(showText.charAt(showText.length() - 1) == '.') {showText = showText.substring(0, showText.length() - 1);}refreshText(showText + operator);}// 等號 的操作} else if(t == R.id.btn_equal) { // 等號按鈕// 進行規格化String ret = Normalized(js(showText));refreshText(ret);// 計算的結果要去循環的去播放出來playRet(ret);// 前提是沒有小數點的話 再去恢復if(!ret.contains(".")) {// 等號的話 也要去恢復小數點的操作addPoint = true;}clearKh();// 然后去清空掉
// showText = "0";//1 + 0123.0 √} else if(t == R.id.btn_sqrt) { // 開根號js3(1); // 1 表示的是開根號的操作} else if(t == R.id.btn_reciprocal) { // 求倒數js3(2);} else if(t == R.id.btn_PI) { // 點擊了 π 的 操作js3(4);} else if(t == R.id.btn_factorial) { // 點擊了階乘的操作js3(3);} else if(t == R.id.btn_abs) {js3(5); // 點擊了絕對值的操作} else if(t == R.id.btn_e) { // 點擊的是 e 的 操作js3(6);} else if(t == R.id.btn_ln) { // 點擊的是 ln 的操作js3(7);} else if(t == R.id.btn_log) { // 點擊的是 log 的操作js3(8);}else if(t == R.id.btn_left_kh) {leftParenthesis ++ ;// 刷新 界面的括號顯示數字 并且把 括號給拼接上去// 這里也要特判一下 可能存在 這樣的情況 比如: (0)() 要把它變成 (0)x(0) 這樣的情況char pre = showText.charAt(showText.length() - 1);if(pre == ')') {showText += 'x';}// 這里需要去校驗一種情況是 1( 要把它變為 1 + (這樣的形式if(checkIsNum(pre)) {showText += "+";}refreshText(showText + inputText);} else if(t == R.id.btn_right_kh) { // 點擊了右括號// 為了讓他們進行匹配 也即是 存在 對應的左括號的時候才進行匹配if(rightParenthesis < leftParenthesis) {rightParenthesis ++ ;// 刷新 界面的右括號顯示數字 并且把括號給拼接上去// 這里要單獨去檢驗一下 可能是 () 這樣的情況是不允許的 要去在左括號的后面去拼接一個 0char pre = showText.charAt(showText.length() - 1);if(pre == '(') {showText += "0";}// 這里也要去防止 (0+)這樣的情況if(checkIsOp(pre)) {showText += "0"; // 去給它去補上 0}refreshText(showText + inputText);}}else {// 點擊了 數字 和 小數點// 這里要去監控 如果之前點擊了小數點 這里的話 就不能再去進行拼接了if(inputText.equals(".")) {// 這里可能會出現很多的 小數點 例如: 0.000.if(!addPoint || getLastNumber(showText).contains(".")) { // 表示不可以去添加小數點refreshText(showText); // 保持原來的return ;} else {// 這里要去判斷一下 小數點的前方是否為操作符 如果是的話 就自動拼接一個 0char pre = showText.charAt(showText.length() - 1);if(checkIsOp(pre) || checkIskh(pre)) {showText = showText + "0";}refreshText(showText + inputText); // 保持原來的addPoint = false;return;}}char pre = showText.charAt(showText.length() - 1);// 如果前面不是數字的話 要去自動補上加號if(pre == ')') {showText += "+";}refreshText(showText + inputText); // 拼接}}/*** 播放音樂的* @param inputText*/private void playSound(String inputText) {// 在這里Debug一下// Toast.makeText(this, "點擊了" + inputText, Toast.LENGTH_SHORT).show();playSoundMain(inputText, 0); // 默認都是單循環的}/*** 主要的聲音播放方法* @param sound map里面的key* @param loop 表示循環的次數*/private void playSoundMain(String sound, int loop) {if (sp == null || hm.get(sound) == null) {Toast.makeText(this, "音頻資源未加載或無效", Toast.LENGTH_SHORT).show();return;}// 獲取AudioManager引用AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);// 獲取當前音量float streamVolumeCurrent = am.getStreamVolume(AudioManager.STREAM_MUSIC);// 獲取系統最大音量float streamVolumeMax = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);// 計算得到播放音量float volume = streamVolumeCurrent / (float) streamVolumeMax;// 調用SoundPool的play方法來播放聲音文件currentId = sp.play(hm.get(sound), volume, volume, 1, loop, 1.0f);}/*** 計算的是 開根號 倒數 階乘 π e* @param num 約定好的標志* 1:開根號* 2:倒數* 3:階乘* 4:π* 5:絕對值* 6:e* 7:ln*/private void js3(int num) {String snum = getLastNumber(showText);String newNumber = "";if(num == 1) { // 開根號if(Double.parseDouble(snum) < 0) {abnormal(NAGATIVE_HAS_NO_SQRT);return;}newNumber = String.valueOf(Math.sqrt(Double.parseDouble(snum)));} else if(num == 2) { // 倒數的操作// 先去檢查分母是不是為0的if(Double.parseDouble(snum) - 0.0 == 0) {abnormal(ISZERO); // 分母不可為 0return ;}addPoint = false; // 不能再去增加小數點了// 開始邏輯上的計算newNumber = String.valueOf(1.0 / Double.parseDouble(snum));} else if(num == 3) { // 階乘// 注意:小數和分數沒有階乘 階乘法只在自然數中進行if(!addPoint || showText.contains(".")) {// 表示當前是增加了小數的 是不能去進行階乘的運算的abnormal(FACTORIALERROR);return; // 這個return 是為了防止 其他信息 的覆蓋} else { // 表示當前是沒有小數的 是可以進行階乘的if(Integer.parseInt(snum) > 100) {abnormal(OVERFLOW); // 階乘太大會導致溢出return ;} else if(Integer.parseInt(snum) < 0 ) {abnormal(NAGATIVE_HAS_NO_FACTORIAL); // 負數沒有階乘return;}newNumber = factorial(Integer.parseInt(snum));}} else if(num == 4) { //πaddPoint = false; // 注意 點擊了PI 之后也要去限制小數點的newNumber = String.valueOf(Math.PI);} else if(num == 5) { // 絕對值的操作// 感覺這個絕對值 有點雞肋if(Double.parseDouble(snum) < 0 ) {newNumber = snum.substring(1); // 把前面的符號給截取掉} else {// 但是這個新的 還要去規范一下 不能把前置 0 給顯示newNumber = cancelZero(snum); // 不進行截取}} else if(num == 6) { // e 2.71828newNumber = String.valueOf(Math.E);} else if(num == 7) { // ln 的操作if(Double.parseDouble(snum) <= 0) {abnormal(LN_NEED_GREATER_THAN_ZERO);return ;}newNumber = String.valueOf(Math.log(Double.parseDouble(snum)));} else if(num == 8) { // log 的操作if(Double.parseDouble(snum) <= 0) {abnormal(LON_NEED_GREATER_THAN_ZERO);return ;}newNumber = String.valueOf(Math.log10(Double.parseDouble(snum)));}// 我需要找到最后這個的位置// over: 獲得這個的num的位置 然后進行替換 把老的替換為新的// 我需要去找到 最后一個操作符的位置int pos = getLastOperatorPose(showText);// 開始進行替代 注意的是 這里的 substring 第二個參數表示的最后的位置 注意是 前閉后開的showText = showText.substring(0, pos + 1);char temp = showText.charAt(showText.length() - 1);// 如果最后一個不是運算符的話 就在去拼接一下加號 這個加號是默認的if(!checkIsOp(temp)) {showText += "+";}// 再去拼接新的showText = showText + newNumber;// 然后再去在界面進行顯示出來refreshText(showText);}/*** 清空括號 也即是下面這種情況* 1: 按下C的時候* 2: 等號的時候*/private void clearKh() {leftParenthesis = 0;rightParenthesis = 0;// 清空之后要去刷新 數量refreshText(showText);}/*** 對結果進行規格化* @param text 傳過來 需要規格化的數據* 例如: 00001 那么要返回的就是 1* @return*/private String cancelZero(String text) { // 取消前置無效0 以及后置無效0int j = 0;// 要對 test 進行校驗一個// 有哪些情況呢?// 1: 00008// 2: 0000.1for(int i = 0; i < text.length() - 1; i ++ ) {if(text.charAt(i) == '0' && (!checkIsOp(text.charAt(i + 1)) && text.charAt(i + 1) != '.' || text.charAt(i + 1) == ')' || text.charAt(i + 1) == '(')) {j = i + 1;} else {break;}}text = text.substring(j); // 從這里開始截取 并包括當前這個return text;}/*** 獲取 num 的 階乘的* @param num 想要獲取的 階乘的 num* @return*/private String factorial(int num) {// 為了解決階乘太大 用的是 BigIntegerBigInteger result = BigInteger.ONE; // 初始化為 1for (int i = 1; i <= num; i++) {result = result.multiply(BigInteger.valueOf(i)); // 逐步相乘}return String.valueOf(result); // 最后再去轉換為 string類型的 給進行輸出顯示}/*** 根據text 拋出指定的異常*/private void abnormal(String show) {// 要去禁用按鈕illegal(false);tv_result.setText(show);; // 并把錯誤的信息給顯示到文本框里面}/*** 后退按鈕的操作* @param t 出來的邏輯字符串* @return 返回的是 后退的字符串*/private String Backoff(String t) {for(int i = t.length() - 1; i >= 0; i -- ) {if(checkIsNum(t.charAt(i))) {// 需要注意的是 如果退的是 小數點的話 要求進行恢復if(t.charAt(i) == '.') {// 恢復 可以增加 小數點 的操作addPoint = true;}// 我就去后退一位return t.substring(0, i);} else {// 否則的話 就直接去回去的break;}}return t;}/*** 獲得最后一個操作符的位置* @param showText 傳來的字符串* @return 返回的是 最后一個操作符的位置* 例如: 1+2 返回的是1*/private int getLastOperatorPose(String showText) {int pos = -1;if(showText.charAt(0) == '-') {return pos;}for(int i = showText.length() - 1; i >= 0; i -- ) {if(checkIsOp(showText.charAt(i)) || checkIskh(showText.charAt(i))) { // 如果檢查發現是 操作符的話 就去返回它的下標 是包括它的return i;}}// 這個表示的是沒有操作符的return pos;}/*** 輸出結果的規格化* @param js* @return 返回的是 規格化之后的結果*/private String Normalized(double js) {// 是可以去進行規格化的if(js - (int)(js) == 0) {return String.valueOf((int)(js));} else {return String.valueOf(js);}}/*** 清空 并進行 初始化* 新增 對 小數點 的恢復*/private void clear() {// 清空的時候 注意把 小數點的功能也給進行恢復addPoint = true;refreshOperate("");refreshText("0"); // 0即表示為不存在 其實也是存在}// 刷新運算結果private void refreshOperate(String new_result) {result = new_result;operator = "";}/** 刷新 文本 的操作* 再去加上 輸出的校驗* */private void refreshText(String text) {String khNum = "左括號的數量: " + leftParenthesis + " 右括號的數量: " + rightParenthesis;// 這里在刷新的時候 也要把 括號的數量給顯示出來show_kh.setText(khNum);// 在刷新之前 對結果進行規格化一下 去除前置0的 那些沒有效的數據 但是要對小數進行特判text = cancelZero(text);showText = text; // 默認一直在拼接if(denominatorIsZero) { // 分母是否為0showText = ISZERO;}tv_result.setText(showText);// 對 等號 按鈕的監控if(leftParenthesis == rightParenthesis) {findViewById(R.id.btn_equal).setEnabled(true);} else {findViewById(R.id.btn_equal).setEnabled(false);}}/*** 主要的計算功能* @param s 傳過來的 字符串 要去計算的字符串 這里面沒有等號* @return*/private double js(String s) {// 第一個的 負數 是比較特殊的 要進行特判// 前面直接加上一個 0s = "0" + s;// 這里需要做一個判斷// 可能是-3 這樣的 但是返回的 也是-3 不要在進行計算下去了 這是一個獨特的
// if(s.charAt(0) == '-') {
// s = "0" + s;
// } else if(Objects.equals(operator, "")) {
// return Double.parseDouble(s);
// }// 用到java里面的桟的算法// 存取的是 數字Stack<Double> number = new Stack<>();// 存取的是 操作符Stack<Character> op = new Stack<>();String t = "";for(int i = 0; i < s.length(); i ++ ) {char temp = s.charAt(i);// 如果當前這個 temp 是 運算符的話if(checkIsOp(temp) || temp == '(' || temp == ')') { // 如果當前這個是 運算符// 這樣的話 就需要把 字符串給轉換為 Double// 注意 放進去的前提是不為空的 把他放到 桟里面if(!t.isEmpty()) {number.push(Double.valueOf(t));}t = "";// 然后 看看 當前的字符是什么類型的if(temp == '+' || temp == '-') {while(!op.isEmpty()) {// 拿到桟頂元素char operator = op.peek();if(operator == '(') { // 左括號的優先級是 最低 的break;}op.pop();// 然后再從 整數桟里面 去拿出來兩個數 讓其進行計算// TODO: 這兩步數 是容易造成 error的 這點需要去著重的去關注double t1 = number.peek();number.pop();double t2 = number.peek();number.pop();// 注意的是 后 操作 前 的double ret = js2(t2, t1, operator);number.push(ret);}// 到這里的時候 就表示 op里面是空的了op.push(temp);} else if(temp == 'x' || temp == '÷') {// 當時 乘法或者是 除法的時候 要去校驗 它的下面是不是比它低的// 或者可以寫成 前提是不為空 然后 op.peek() == 'x' || op.peek() == '?'while(!op.isEmpty() && op.peek() != '+' && op.peek() != '-' && op.peek() != '(') {// 拿到桟頂元素char operator = op.peek();op.pop();// 然后再從 整數桟里面 去拿出來兩個數 讓其進行計算// TODO: 這兩步數 是容易造成 error的 這點需要去著重的去關注double t1 = number.peek();number.pop();double t2 = number.peek();number.pop();double ret = js2(t2, t1, temp);number.push(ret);}// 到這里的時候 是可以去當進去的op.push(temp);} else if(temp == ')') { // 這里對右括號單獨進行限制// 只要還沒遇到 左括號 就一直去把里面運算符的給彈出來 而且彈出來的時候 也把數字給彈出來兩個 然后和這個彈出來的運算符進行計算while(!op.isEmpty()) {char operator = op.peek();op.pop();if(operator == '(') {break; // 就匹配成功了}// 否則的話 就取出來兩個數字 然后把這個操作符 讓這兩個數進行運算的結果 放到存取數的桟里面// TODO: 但是這個的前提是存在的double t1 = number.peek();number.pop();double t2 = number.peek();number.pop();double ret = js2(t2, t1, operator);number.push(ret);}} else if(temp == '(') { // 左括號的話 直接 push 進去op.push(temp);}} else if(checkIsNum(temp)){ // 說明是 數字 或者是小數點t = t + temp;}}// Debug 了半天才發現是這里出現了問題 我也是服了if(!t.isEmpty()) {// 注意在 類型轉換的時候 看看是不是為空的 因為空的話 是不能去進行轉換的number.push(Double.valueOf(t));}// 開始計算while (number.size() > 1) {// 這里 沒有運算符 也是很致命的if(op.isEmpty()) {break;}double t1 = number.peek();number.pop();double t2 = number.peek();number.pop();number.push(js2(t2, t1, op.peek()));op.pop();}operator = "";return number.peek();}/*** 計算 + - * / 的* @param t1* @param t2* @param temp* @return*/private double js2(double t1, double t2, char temp) {if(temp == '+') {return t1 + t2;}if(temp == '-') {return t1 - t2;}if(temp == 'x') {return t1 * t2;}if(temp == '÷') {// 出現了 分母為0if(t2 == 0 ) {abnormal(ISZERO); // 分母不可為0 && 限制按鈕的點擊}return t1 / t2;}return 0.0; // 這個是假的}/*** 檢查 是不是操作符* @param t* @return*/private Boolean checkIsOp(Character t) {return t == '+' || t == '-' || t == '÷' || t == 'x';}/*** 檢查是不是 數字 這里把小數點也認為是數字了* @param t* @return*/private Boolean checkIsNum(Character t) {return (t >= '0' && t <= '9') || t == '.';}/*** 獲得字符串 最后 一個 數字* @param s* @return*/private String getLastNumber(String s) {String ret = "";if(s.charAt(0) == '-') { // 表示的是負數ret = s;} else {for(int i = s.length() - 1; i >= 0; i -- ) {if(checkIsNum(s.charAt(i))) {ret = s.charAt(i) + ret;} else {break;}}ret = "0" + ret;}// 這個去解決的是 1233 + 也即是最后一個不是數字if(ret.contains(".")) { // 這個的目的是為了 防止 出現小數點之后 沒有出現數字的情況 比如: 123.ret = ret + "0";}return ret;}/*** 去檢查這個 t 是不是括號 因為要為括號進行特殊的操作* @param t* @return*/private boolean checkIskh(char t) {return t == '(' || t == ')';}// 封掉所有的按鈕 單獨剩下一個 清空的按鈕 要去做出適當的提示// 表示的是 不合法 把全部的按鈕全都給禁用了 除了 Cprivate void illegal(boolean value) {denominatorIsZero = !value;findViewById(R.id.btn_cancel).setEnabled(value);findViewById(R.id.btn_divide).setEnabled(value);findViewById(R.id.btn_multiply).setEnabled(value);findViewById(R.id.btn_clear).setEnabled(true); // 這個是特殊的findViewById(R.id.btn_seven).setEnabled(value);findViewById(R.id.btn_eight).setEnabled(value);findViewById(R.id.btn_nine).setEnabled(value);findViewById(R.id.btn_plus).setEnabled(value);findViewById(R.id.btn_four).setEnabled(value);findViewById(R.id.btn_five).setEnabled(value);findViewById(R.id.btn_six).setEnabled(value);findViewById(R.id.btn_minus).setEnabled(value);findViewById(R.id.btn_one).setEnabled(value);findViewById(R.id.btn_two).setEnabled(value);findViewById(R.id.btn_three).setEnabled(value);findViewById(R.id.btn_reciprocal).setEnabled(value);findViewById(R.id.btn_zero).setEnabled(value);findViewById(R.id.btn_dot).setEnabled(value);findViewById(R.id.btn_equal).setEnabled(value);findViewById(R.id.btn_sqrt).setEnabled(value);// 新增的 限制按鈕findViewById(R.id.btn_PI).setEnabled(value);findViewById(R.id.btn_factorial).setEnabled(value);findViewById(R.id.btn_e).setEnabled(value);findViewById(R.id.btn_abs).setEnabled(value);// 新增的 限制按鈕findViewById(R.id.btn_log).setEnabled(value);findViewById(R.id.btn_ln).setEnabled(value);findViewById(R.id.btn_left_kh).setEnabled(value);findViewById(R.id.btn_right_kh).setEnabled(value); // 對右括號 按鈕進行監聽}/*** 播放最后的運算結果* @param ret*/private void playRet(String ret) {// 先去播放一個等號playSound("=");// 這里是循環播放的答案for(int i = 0; i < ret.length(); i ++ ) {// 播放playSound(ret.charAt(i) + "");}}/*** 聲音池的 初始化 init*/private void initSoundPool() {// 初始化聲音池sp = new SoundPool.Builder().setMaxStreams(4).setAudioAttributes(new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).setUsage(AudioAttributes.USAGE_MEDIA).build()).build();hm = new HashMap<String, Integer>(); // 創建HashMap對象// 加載聲音文件,并且設置為1號聲音放入hm中// 數字的聲音hm.put("1", sp.load(this, R.raw.one, 1));hm.put("2", sp.load(this,R.raw.two, 1));hm.put("3", sp.load(this,R.raw.three, 1));hm.put("4", sp.load(this,R.raw.four, 1));hm.put("5", sp.load(this,R.raw.five, 1));hm.put("6", sp.load(this,R.raw.six, 1));hm.put("7", sp.load(this,R.raw.seven, 1));hm.put("8", sp.load(this,R.raw.eight, 1));hm.put("9", sp.load(this,R.raw.nine, 1));hm.put("0", sp.load(this,R.raw.zero, 1));// 小數點的聲音hm.put(".", sp.load(this,R.raw.point, 1));// 操作符的聲音hm.put("=", sp.load(this,R.raw.equal, 1));hm.put("+", sp.load(this,R.raw.add, 1));hm.put("x", sp.load(this,R.raw.mut, 1));hm.put("÷", sp.load(this,R.raw.chu, 1));hm.put("-", sp.load(this,R.raw.jian, 1));hm.put("C", sp.load(this,R.raw.c, 1));hm.put("(", sp.load(this,R.raw.leftkh, 1));hm.put(")", sp.load(this,R.raw.rightkh, 1));// 運算操作hm.put("n!", sp.load(this,R.raw.jc, 1));hm.put("?", sp.load(this,R.raw.ht, 1));hm.put("π", sp.load(this,R.raw.pai, 1));hm.put("e", sp.load(this,R.raw.e, 1));hm.put("|x|", sp.load(this,R.raw.abs, 1));hm.put("1/x", sp.load(this,R.raw.ds, 1));hm.put("√", sp.load(this,R.raw.sqrt, 1));}
}
xml(界面)代碼:?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="#EEEEEE"android:padding="5dp"><ScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><!--顯示簡單 計算器 字樣--><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/simple_calculator"android:gravity="center"android:textColor="@color/black"android:textSize="20sp"/><TextViewandroid:id="@+id/show_kh"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="左括號數量為: 0 右括號數量為: 0"android:gravity="center"android:textColor="@color/black"android:textSize="20sp"/><!-- 計算機 文本的顯示--><TextViewandroid:id="@+id/tv_result"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/white"android:text="0"android:textColor="@color/black"android:lines="3"android:gravity="right|bottom"android:textSize="25sp"/><GridLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:columnCount="4"android:rowCount="7"><!--后退一個--><Buttonandroid:id="@+id/btn_cancel"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/cancel"android:textColor="@color/black"/><!--除法--><Buttonandroid:id="@+id/btn_divide"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/divide"android:textColor="@color/black"/><!--乘法--><Buttonandroid:id="@+id/btn_multiply"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/multiply"android:textColor="@color/black"/><!--清零操作--><Buttonandroid:id="@+id/btn_clear"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/clear"android:textColor="@color/black"/><!--新增的操作--><Buttonandroid:id="@+id/btn_PI"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/PI"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_e"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/e"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_abs"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/abs"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_factorial"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/factorial"android:textColor="@color/black"/><!--這里又是新增加的 比如 左括號 右括號 --><Buttonandroid:id="@+id/btn_log"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/log"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_ln"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="ln"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_left_kh"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/left_kh"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_right_kh"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/right_kh"android:textColor="@color/black"/><!--下面是第二行--><Buttonandroid:id="@+id/btn_seven"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/seven"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_eight"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/eight"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_nine"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/nine"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_plus"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/plus"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_four"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/four"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_five"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/five"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_six"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/six"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_minus"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/minus"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_one"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/one"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_two"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/two"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_three"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/three"android:textColor="@color/black"/><!--這里顯示的根號的圖片--><Buttonandroid:id="@+id/btn_sqrt"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/sqrt"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_reciprocal"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/reciprocal"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_zero"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/zero"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_dot"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/dot"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_equal"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/equal"android:textColor="@color/black"/></GridLayout></LinearLayout></ScrollView></LinearLayout>
strings.xml里面的代碼:
<resources><string name="app_name">黃淮計算器</string><string name="action_settings">Settings</string><!-- Strings used for fragments for navigation --><string name="first_fragment_label">First Fragment</string><string name="second_fragment_label">Second Fragment</string><string name="next">Next</string><string name="previous">Previous</string><string name="hello_word">hello_word</string><string name="text_for_color">textForColor</string><string name="lorem_ipsum"></string><string name="findyou">FindYou</string><string name="this_is_findyou">This is FindYou</string><string name="this_is_activity_main_2">除了奮斗 別無選擇</string><!--計算器的定義--><string name="simple_calculator">黃淮計算器</string><string name="cancel">?</string><string name="divide">÷</string><string name="multiply">x</string><string name="clear">C</string><string name="seven">7</string><string name="eight">8</string><string name="nine">9</string><string name="plus">+</string><string name="four">4</string><string name="five">5</string><string name="six">6</string><string name="minus">-</string><string name="one">1</string><string name="two">2</string><string name="three">3</string><string name="reciprocal">1/x</string><string name="zero">0</string><string name="dot">.</string><string name="sqrt">√</string><string name="equal">=</string><string name="check_sex">請選擇你的性別</string><string name="PI">π</string><string name="e">e</string><string name="abs">|x|</string><string name="factorial">n!</string><string name="log">log</string><string name="left_kh">(</string><string name="right_kh">)</string></resources>
如果這對你有幫助的話,記得start一下哦,你的star對我很重要!!!
gitee地址:
FindYou/移動開發