Android学习之计算器app(java + 详细注释 + 源码)

运行结果:

基础的四则运算:

可能会出现的问题以及解决方法:

 问题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/移动开发

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/76485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GMap.NET + WPF:构建高性能 ADS-B 航空器追踪平台

ADS-B 简介 ADS - B&#xff08;Automatic Dependent Surveillance - Broadcast&#xff0c;广播式自动相关监视&#xff09;是一种先进的航空监视技术。它依靠飞机上的机载设备&#xff0c;自动收集诸如飞机的位置、高度、速度、航向等关键数据&#xff0c;并周期性地以广播的…

关于testng.xml无法找到类的问题

问题&#xff1a;testng.xml添加测试类的时候飘红 解决办法&#xff1a; 1.试图通过自动生成testng.xml插件去解决&#xff0c;感觉也不是这个问题&#xff0c;没有尝试&#xff1b; 2.以为是创建包的方式不对&#xff0c;重新删除后新建--还是找不到 想新建类的时候发现从m…

数据在内存中存储(C语言)

文章目录 前言一、整数在内存中的存储1.1 计算机存储数据的基本单位示例代码 1.2 无符号整数的存储1.3 有符号整数的存储&#xff08;补码&#xff09;示例代码 二、大小端字节序和字节序判断2.1 什么是大小端&#xff1f;示例代码 2.2 为什么会有大小端&#xff1f;2.3 字节序…

Python爬虫第2节-网页基础和爬虫基本原理

目录 一、网页基础 1.1 网页的组成 1.2 网页的结构 1.3 节点树及节点间的关系 1.4 选择器 二、爬虫的基本原理 2.1 爬虫概述 2.2 能抓怎样的数据 2.3 JavaScript 渲染页面 一、网页基础 使用浏览器访问网站时&#xff0c;我们会看到各式各样的页面。你是否思考过&…

python-leetcode 64.在排序数组中查找元素的第一个和最后一个位置

题目&#xff1a; 给一个按照非递减顺序排列的整数数组nums,和一个目标值target,请找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值target,返回[-1,-1] 方法一&#xff1a;二分查找 直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次…

分享一些新版GPT-4o使用方式!能多模态生图!

目前GPT-4o的整体测评&#xff0c;真的很惊艳。 不知道又有多少人因为OpenAI的这次更新而失业&#xff0c;当然只要AI用得好&#xff0c;会有更多人因之而受益&#xff01;很多人表示不知道怎么用&#xff0c;对于门外汉来说&#xff0c;4o似乎有点高端。 今天就给大家介绍几…

软件工程面试题(二十四)

1、连接池的原理 j2ee 服务器启动时会建立一定数量的池连接,并一直维持不少于此数量的池连接。当客户端程序需要连接时,吃驱动程序会返回一个未使用的池连接并将其标记为忙。如果当前 没有空闲连接,池驱动就建立一定新的 连接 2、用javascript编写脚本小程序,实现点击全选…

Android:Dialog的使用详解

Android中Dialog的使用详解 Dialog&#xff08;对话框&#xff09;是Android中常用的UI组件&#xff0c;用于临时显示重要信息或获取用户输入。 1. 基本Dialog类型 1.1 AlertDialog&#xff08;警告对话框&#xff09; 最常用的对话框类型&#xff0c;可以设置标题、消息、…

arinc818 fpga单色图像传输ip

arinc818协议支持的常用线速率如下图 随着图像分辨率的提高&#xff0c;单lane的速率无法满足特定需求&#xff0c;一种方式是通过多个LANE交叉的去传输图像&#xff0c;另外一种是通过降低图像的带宽&#xff0c;即通过只传单色图像达到对应的效果 程序架构如下图所示&#x…

透视投影(Perspective projection)与等距圆柱投影(Equirectangular projection)

一、透视投影 1.方法概述 Perspective projection&#xff08;透视投影&#xff09;是一种模拟人眼观察三维空间物体时的视觉效果的投影方法。它通过模拟观察者从一个特定视点观察三维场景的方式来创建二维图像。在透视投影中&#xff0c;远处的物体看起来比近处的物体小&…

三.微服务架构中的精妙设计:服务注册/服务发现-Eureka

一.使用注册中心背景 1.1服务远程调用问题 服务之间远程调⽤时, 我们的URL是写死的 String url "http://127.0.0.1:9090/product/" orderInfo.getProductId(); 缺点&#xff1a; 当更换机器, 或者新增机器时, 这个URL就需要跟着变更, 就需要去通知所有的相关服…

FPGA实现4K MIPI视频解码H265压缩网络推流输出,基于IMX317+VCU架构,支持4K60帧,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 MIPI 编解码方案我这里已有的视频图像编解码方案 3、详细设计方案设计框图FPGA开发板IMX317摄像头MIPI D-PHYMIPI CSI-2 RX Subsystem图像预处理Sensor …

Ollama+open-webui搭建私有本地大模型详细教程

Ollamaopen-webui搭建私有本地大模型详细教程 1. 什么是 Ollama&#xff1f; 1.1. Ollama 简介 ​ Ollama 是一个轻量级的 AI 模型运行时&#xff0c;专注于简化 AI 模型的部署和使用。它支持多种预训练模型&#xff08;如 Llama、Vicuna、Dolly 等&#xff09;&#xff0c;…

解决Centos7集成IDEA报git版本太低问题

Centos 7 服务器上默认安装的 Git 是 1.8.3.1 版本的 与最新的IDEA已无法匹配&#xff0c;需要更新 首先&#xff0c;卸载老版本 sudo yum -y remove git sudo yum -y remove git-*添加 End Point 到 CentOS 7 仓库 sudo yum -y install https://packages.endpointdev.com/r…

Qt常用宏定义判断大全

Qt 提供了一系列预定义宏用于判断 Qt 版本、操作系统平台、编译器特性等。这些宏在跨平台开发中非常有用。 1. Qt 版本判断宏 // 检查Qt版本 #if QT_VERSION > QT_VERSION_CHECK(5, 15, 0)// Qt 5.15.0及以上版本特有代码 #endif// 常用版本判断 #if QT_VERSION > QT_V…

实战 | 餐厅点餐小程序技术解析:SpringBoot + UniApp 高效开发指南

&#x1f5a5;️ 一、系统架构概览 1.1 技术选型 为了确保开发效率和系统稳定性&#xff0c;我们采用以下技术栈&#xff1a; 模块技术选型后台服务SpringBoot MyBatis-Plus MySQL用户端&#xff08;点餐小程序&#xff09;UniApp&#xff08;Vue 语法&#xff09;师傅端&…

实现在Unity3D中仿真汽车,而且还能使用ros2控制

文章目录 前言&#xff08;Introduction&#xff09;搭建开发环境&#xff08;Setup Development Environment&#xff09;在window中安装Unity&#xff08;Install Unity in window&#xff09;创建Docker容器&#xff0c;并安装相关软件&#xff08;Create Docker containers…

华为配置篇-BGP实验

BGP 一、简述二、常用命令总结三、实验 一、简述 IBGP 水平分割&#xff1a;从一个 IBGP 对等体学到的路由&#xff0c;不会再通告给其他的 IBGP 对等体。在一个 AS 内部&#xff0c;路由器之间通过 IBGP 交换路由信息。如果没有水平分割机制&#xff0c;当多个路由器之间形成…

Python视频标签工具详解:基于wxPython和FFmpeg的实现

在当今数字媒体时代&#xff0c;视频内容的管理和标记变得越来越重要。无论是研究人员需要对实验视频进行时间点标记&#xff0c;教育工作者需要对教学视频添加注释&#xff0c;还是个人用户希望对家庭视频进行分类整理&#xff0c;一个高效的视频标签工具都是不可或缺的。本文…

国产三维CAD「皇冠CAD」在汽车零部件领域建模教程:刹车片

本教程深度融合三维皇冠CAD&#xff08;CrownCAD&#xff09;的MBD&#xff08;Model-Based Definition&#xff09;设计理念&#xff0c;通过参数化建模、智能约束管理、动态装配验证等功能&#xff0c;实现数据驱动设计&#xff0c;精准解决了汽车制动系统中精密制动组件的设…