鸿蒙应用开发---计算器
- 计算器
- 效果图
- 设计思路
- UI设计
- 按钮功能分析
- 滑动退格实现原理思路
- 滑动退格源代码
- 圆形按钮源代码(包含按钮动画)
- 圆形按钮预览图
- 椭圆按钮源代码
- 椭圆按钮预览图
- 计算逻辑的实现
- 中缀表达式转后缀表达式
- 代码部分(获得运算符优先级函数 && 中缀表达式转后缀表达式函数)
- 判断该字符是数字部分还是操作符部分
- 后缀表达式计算结果
- 代码部分(后缀表达式计算结果)
- 总结及心得
- 完整代码(多个子组件和父组件都写在里面,复制后不可直接使用,需要拆分以下 && 父组件中满足if条件后的代码不具有参考价值!!!)
计算器
效果图
首先,先给大家看一下计算器的效果图
- 第一个是计算器的UI设计
- 第二个是科学计算器的页面布局(科学计算器的相关功能还没有实现)
- 第三个是退格设计:在计算式预览组件中滑动手指即可(左滑或者右滑)
设计思路
UI设计
这个UI设计模仿的是苹果手机计算器风格,不能说很像但是还是挺像的,一眼看去可以发现主要有两种风格的按钮:一种是圆形按钮,另一种是数字‘0’所在的椭圆按钮,所以以此出发,我们可以构造两个子组件来完成按钮的设计,最后将他们使用Row组件和Column组件按照顺序排布即可
按钮功能分析
- 点击后可以将这个按钮对应的字符添加到计算式字符串中(详见下面代码的OnClick事件)
- 点击时透明度发生变化以实现点击动效(详见下面代码的OnTouch事件)
- 在计算式的Row组件中手指滑动实现退格(退位)操作(详见下面代码的On)
- 外观和谐美观
滑动退格实现原理思路
- 定义一个起始坐标(sta_x)、波尔类型的标记(flag==false)以及手指滑动过程中x坐标的偏移量(distance_x)
- 获得手指按下时的x坐标作为起始坐标(sta_x),并将flag改为true代表手指开始接触屏幕
- 手指滑动计算distance_x偏移量,如果偏移量大于某个值并且flag是true时就删除计算式字符串的最后一位,即实现退格操作,同时并把flag再次置为false使得如果不松手的话无论手指怎么滑动都只能进行一次退格。
- 手指离开时flag置为true,方便进行下一次滑动退格。
滑动退格源代码
Row() { Text(`${this.cal}`) .fontSize(24) .fontColor(Color.White) }.height(70) .width('100%') .justifyContent(FlexAlign.End) .padding({ right: 35 }) //通过onTouch事件来实现滑动退格 .onTouch((Event:TouchEvent)=>{ if(Event.type==TouchType.Down){ //获得手指按下时的x坐标作为起始坐标 this.sta_x = Event.touches[0].x this.Delete_bool = true; } if(Event.type==TouchType.Up){ this.Delete_bool = true } if(Event.type==TouchType.Move){ //移动过程中计算x轴上移动的距离 this.distance_x = Math.abs(this.sta_x - Event.touches[0].x) //如果距离超过20就进行退格操作 if(this.distance_x>20&&this.Delete_bool == true){ this.cal = this.cal.slice(0,-1); this.Delete_bool = false; } } })
复制
圆形按钮源代码(包含按钮动画)
@Component export struct Button1{ //计算式 @Link cal:string //计算结果 @Link result:string|undefined|number //是否已经按下等号的标记 @Consume flag:boolean //按钮透明度设置 @Link button_opacity_son:number //1为测试数据 num:string = '1' //按钮颜色 buttonColor:number = 0x333333 //文本颜色 textColor:number = Color.White //文本大小 textSize:number = 28 build() { Column(){ Text(`${this.num}`) .fontColor(this.textColor) .fontWeight(FontWeight.Medium) .fontSize(this.textSize) }.justifyContent(FlexAlign.Center) //按下按钮时,按钮的透明度改变 .onTouch((Event:TouchEvent)=>{ if(Event.type==TouchType.Down){ this.button_opacity_son = 0.5 } if(Event.type==TouchType.Up){ this.button_opacity_son = 1; } }) .width(80) .height(80) .opacity(this.button_opacity_son) .alignItems(HorizontalAlign.Center) .backgroundColor(this.buttonColor) .borderRadius(40) .onClick(()=>{ //’AC‘功能的实现 if(this.num=='AC'){ this.flag = true; this.cal=''; this.result = '0'; return } else if(this.num=='='){ //如果第一次按下等号就显示等号 if(this.flag == true) { this.flag = false; let EndExpression =SwitchMiddleToEnd(this.cal); EndExpression.print_queue() this.result = calculate_achieve(EndExpression); } //否则不显示等号 else { let EndExpression = SwitchMiddleToEnd(this.cal); EndExpression.print_queue() this.result = calculate_achieve(EndExpression); this.result = String(roundToDecimal(this.result)); } } //将按钮所对应的字符加到计算式后 else { this.cal += this.num; } }) } }
复制
圆形按钮预览图
椭圆按钮源代码
和圆形按钮构造基本相同,只是宽度不同,注释看上面的圆形按钮注释即可
@Component export struct Button2{ @Link cal:string @Link button_opacity_son:number num:string = '0' buttonColor:number = 0x333333 textColor:number = Color.White textSize:number = 28 build() { Column(){ Text(`${this.num}`) .fontColor(this.textColor) .fontWeight(FontWeight.Medium) .fontSize(this.textSize) }.justifyContent(FlexAlign.Center) .onTouch((Event:TouchEvent)=>{ if(Event.type==TouchType.Down){ this.button_opacity_son = 0.5 } if(Event.type==TouchType.Up){ this.button_opacity_son = 1; } }) .width(170) .opacity(this.button_opacity_son) .height(80) .alignItems(HorizontalAlign.Center) .backgroundColor(this.buttonColor) .borderRadius(40) .onClick(()=>{ this.cal+=this.num; }) } }
复制
椭圆按钮预览图
计算逻辑的实现
我们先来看看,对于“9 + (3 - 1) × 3 + 10 ÷ 2”,这种表达式叫做中缀表达式,就是我们平时数学上遇到的算式,如果要用后缀表示法应该是这个样子“9 3 1 - 3 × 10 2 ÷ +”,叫后缀表达式的原因在于所有的符号都是在要运算数字的后面出现。显然这里没有了括号,对于从来没有接触过后缀表达式的同学来讲,这样的表述是很难受的,不过人不喜欢,机器却是很喜欢的,比如我们“聪明的计算机”。
因此我们现在应该干什么事呢?没错,现在需要将我们熟悉的数学算式改为计算机喜欢的式子(即:中缀表达式转化为后缀表达式),然后再根据数据结构中的栈和队列来实现这个运算逻辑,最后将结果显示在我们的屏幕上即可。
总结主要有以下几步:
- 中缀表达式转换为后缀表达式
- 利用栈完成对后缀表达式的计算并获得结果
- 最后将计算结果显示出来
中缀表达式转后缀表达式
- 规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
- 做法:我们这里分别构造了一个队列和一个栈,栈根据以上规则进行获得后缀表达式,而队列用来存储后缀表达式,最后将这个存储着后缀表达式的队列返回。关于栈和队列的构建可以看下面两个博客:
- Typescript实现栈
- Typescript实现队列
代码部分(获得运算符优先级函数 && 中缀表达式转后缀表达式函数)
//获得运算符优先级等级的函数 function getPrecedence(item:string):number{ switch(item){ case '%':return 3 case '×':return 2 case '÷':return 2 case '+':return 1 case '-':return 1 default:return 0 } } //中缀表达式转后缀表达式函数 export function SwitchMiddleToEnd(cal:string){ let queue = new queue_my(); let first_fu:boolean = true let switchStack = new CharacterStack(); let i =0; while(i<cal.length){ //如果遍历到数字直接入队 if(isNumber(cal[i])){ let numberstring = ''; while(isNumber(cal[i])){ numberstring+=cal[i]; i++ } queue.enqueue(numberstring); // console.log(`${numberstring}入队`); i-- } //如果遇到第一个位置是左括号加-号 else if(cal[0]=='('&&cal[1]=='-'&&first_fu){ switchStack.push(cal[0]); let numberstring = '-' first_fu = false; i = 2 while(isNumber(cal[i])){ numberstring+=cal[i] i++ } queue.enqueue(numberstring) i-- // console.log(`${numberstring}入队`); // console.log(`此时遍历到了:${cal[i]}`) } else if(cal[0]=='-'&&isNumber(cal[1])&&first_fu){ let numberstring = '-'; first_fu = false; i=1; while(isNumber(cal[i])){ numberstring+=cal[i]; i++ } queue.enqueue(numberstring); // console.log(`${numberstring}入队`); i--; } //如果连按几次同一个操作符 else if(!isNumber(cal[i])&&!isNumber(cal[i+1])&&cal[i]==cal[i+1]){ i++; } //带括号的负数在中间的时候 else if(cal[i]=='('&&cal[i+1]=='-'&&isNumber(cal[i+2])){ let numberstring = '-'; i = i+2; while(isNumber(cal[i])){ numberstring+=cal[i]; ++i } queue.enqueue(numberstring) // console.log(`${numberstring}已经入队`) } //如果栈中为空或者遇到左括号直接入栈 else if(switchStack.isEmpty()||cal[i]=='('){ // if(cal[i]=='(') console.log('遇到了左括号') switchStack.push(cal[i]); } //栈顶操作符优先级小于当前操作符优先级 else if(cal[i]!=')'&&getPrecedence(switchStack.peek())<getPrecedence(cal[i])){ switchStack.push(cal[i]); } //栈顶操作符优先级大于当前操作符优先级 else if(cal[i]!=')'&&getPrecedence(switchStack.peek())>=getPrecedence(cal[i])){ //栈顶元素出栈并且加到队列中去 while(getPrecedence(cal[i])<=getPrecedence(switchStack.peek())) {queue.enqueue(String(switchStack.pop())) if(switchStack.isEmpty()){break} } switchStack.push(cal[i]); } //如果遇到了右括号 else if(cal[i]==')') { // console.log('遇到了右括号') while (switchStack.peek() != '(') { let temp: string = String(switchStack.pop()); queue.enqueue(temp); } //遇到左括号时直接将左括号弹出 switchStack.pop() // console.log('左括号出栈') } i++; } //最后将剩余的操作符全部放到队列中 while(!switchStack.isEmpty()) { queue.enqueue(String(switchStack.pop())) } return queue; }
复制
判断该字符是数字部分还是操作符部分
这里用了两个函数:
- 判断这个字符是不是数字部分:
function isNumber(item:string):boolean{ if(item=='0'||item=='1'||item=='2'||item=='3'||item=='4'||item=='5'||item=='6'|| item=='7'||item=='8'||item=='9'||item=='.'){ return true; } else return false; }
复制
- 判断这个字符是不是操作符
function isCharacter(item:string):boolean{ if(item=='+'||item=='-'||item=='÷'||item=='×'||item=='('||item==')'){ return true; } else return false;
复制
后缀表达式计算结果
- 规则:从左到右遍历表达式的每个数字和符号,遇到是数字就入栈,遇到是符号,就将处于栈顶的两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
代码部分(后缀表达式计算结果)
//后缀表达式计算函数 export function calculate_achieve(que:queue_my):string{ let numberstack = new NumberStack(); let i =0; let sum=que.size() while(i<sum){ //如果遇到数字直接入栈并删除该元素 if(!isCharacter(que.peek())){ console.log(`${que.peek()}已经入栈`) numberstack.push(que.peek()); que.dequeue() i++; } //如果遇到了操作符 else{ let num_up = numberstack.pop(); let num_down = numberstack.pop(); if(que.peek()=='+'){ numberstack.push(String(Number(num_down)+Number(num_up))) // console.log(`${String(Number(num_down)+Number(num_up))}入栈`) } else if(que.peek()=='-'){ numberstack.push(String(Number(num_down)-Number(num_up))) // console.log(`${String(Number(num_down)-Number(num_up))}入栈`) } //遇到‘3’时会出现精度问题,故这里解决的是精度问题 else if(que.peek()=='×'){ if(num_up=='3'||num_up=='6'||num_up=='9') { numberstack.push(String((Number(num_down)*(Number(num_up)*10000))/10000)) } else{ numberstack.push(String((Number(num_down) * Number(num_up) * 100) / 100)) } // console.log(`${String(Number(num_down)*Number(num_up))}入栈`) } else if(que.peek()=='÷'){ if(num_up=='0') numberstack.push('不能除以0') else { numberstack.push(String(Number(num_down) / Number(num_up))) } // console.log(`${String(Number(num_down)/Number(num_up))}入栈`) } que.dequeue(); i++; } } return String(numberstack.pop()); }
复制
总结及心得
到了这里,基本上这个计算器的主要组成部分已经大功告成了,在这次做这个计算器的时候遇到了不少困难,由于没有系统学习数据结构的知识,导致完成计算逻辑时不知道从何下手,查阅了大量资料后才明白了其中的道理,最后完成了这个仍然存在一些瑕疵的计算器。
虽然过程难了一点,不过好在结果是好的,所以我觉得当我们在学习计算机知识的时候切记一定不要急躁,要看清每一个细节,打牢每一个基础,这里引用初中政治老师常说的一句话:“基础不牢,地动山摇”,现在回头看这句话说的真的很对,无论哪个行业或者哪个学科都不是一蹴而就的,而是日积月累的,一个个细小的知识点(基础)才能构成稳固的知识体系。
下面是我做的计算器的全部代码分享给大家(注:科学计算器里面功能没有实现!!!),如果有什么改进的好想法可以发在评论区呢~
完整代码(多个子组件和父组件都写在里面,复制后不可直接使用,需要拆分以下 && 父组件中满足if条件后的代码不具有参考价值!!!)
import { Button1 } from '../model/Button1' import { Button1_second } from '../model/Button1_second' import { Button2_second } from '../model/Button2_second' import { Button2 } from '../model/Button2' import {CharacterStack} from '../model/CharacterStack' import {NumberStack} from '../model/NumberStack' import {queue_my} from '../model/Queue' //科学计算器中‘0’按钮子组件】 export struct Button2_second{ @Link cal:string @Link button_opacity_son:number num:string = '0' buttonColor:number = 0x333333 textColor:number = Color.White textSize:number = 28 build() { Column(){ Text(`${this.num}`) .fontColor(this.textColor) .fontWeight(FontWeight.Medium) .fontSize(this.textSize) }.justifyContent(FlexAlign.Center) .onTouch((Event:TouchEvent)=>{ if(Event.type==TouchType.Down){ this.button_opacity_son = 0.5 } if(Event.type==TouchType.Up){ this.button_opacity_son = 1; } }) .width(130) .opacity(this.button_opacity_son) .height(60) .alignItems(HorizontalAlign.Center) .backgroundColor(this.buttonColor) .borderRadius(40) .onClick(()=>{ this.cal+=this.num; }) } } //计算器主界面‘0’按钮子组件 export struct Button2{ @Link cal:string @Link button_opacity_son:number num:string = '0' buttonColor:number = 0x333333 textColor:number = Color.White textSize:number = 28 build() { Column(){ Text(`${this.num}`) .fontColor(this.textColor) .fontWeight(FontWeight.Medium) .fontSize(this.textSize) }.justifyContent(FlexAlign.Center) .onTouch((Event:TouchEvent)=>{ if(Event.type==TouchType.Down){ this.button_opacity_son = 0.5 } if(Event.type==TouchType.Up){ this.button_opacity_son = 1; } }) .width(170) .opacity(this.button_opacity_son) .height(80) .alignItems(HorizontalAlign.Center) .backgroundColor(this.buttonColor) .borderRadius(40) .onClick(()=>{ this.cal+=this.num; }) } } //科学计算器圆形按钮子组件 import {calculate_achieve} from '../pages/Index' import {SwitchMiddleToEnd} from '../pages/Index' import {roundToDecimal} from '../pages/Index' @Component export struct Button1_second{ @Link cal:string @Link result:string|undefined|number @Consume flag:boolean @Link button_opacity_son:number num:string = '1' buttonColor:number = 0x333333 textColor:number = Color.White textSize:number = 24 build() { Column(){ Text(`${this.num}`) .fontColor(this.textColor) .fontWeight(FontWeight.Medium) .fontSize(this.textSize) }.justifyContent(FlexAlign.Center) .onTouch((Event:TouchEvent)=>{ if(Event.type==TouchType.Down){ this.button_opacity_son = 0.5 } if(Event.type==TouchType.Up){ this.button_opacity_son = 1; } }) .width(60) .height(60) .opacity(this.button_opacity_son) .alignItems(HorizontalAlign.Center) .backgroundColor(this.buttonColor) .borderRadius(30) .onClick(()=>{ if(this.num=='AC'){ this.flag = true; this.cal=''; this.result = '0'; return } else if(this.num=='='){ if(this.flag == true) { this.flag = false; let EndExpression =SwitchMiddleToEnd(this.cal); EndExpression.print_queue() this.result = calculate_achieve(EndExpression); } else { let EndExpression = SwitchMiddleToEnd(this.cal); EndExpression.print_queue() this.result = calculate_achieve(EndExpression); this.result = String(roundToDecimal(this.result)); } } else { this.cal += this.num; } }) } } //计算器主界面圆形按钮子组件 import {calculate_achieve} from '../pages/Index' import {SwitchMiddleToEnd} from '../pages/Index' export struct Button1{ //计算式 @Link cal:string //计算结果 @Link result:string|undefined|number //是否已经按下等号的标记 @Consume flag:boolean //按钮透明度设置 @Link button_opacity_son:number //1为测试数据 num:string = '1' //按钮颜色 buttonColor:number = 0x333333 //文本颜色 textColor:number = Color.White //文本大小 textSize:number = 28 build() { Column(){ Text(`${this.num}`) .fontColor(this.textColor) .fontWeight(FontWeight.Medium) .fontSize(this.textSize) }.justifyContent(FlexAlign.Center) //按下按钮时,按钮的透明度改变 .onTouch((Event:TouchEvent)=>{ if(Event.type==TouchType.Down){ this.button_opacity_son = 0.5 } if(Event.type==TouchType.Up){ this.button_opacity_son = 1; } }) .width(80) .height(80) .opacity(this.button_opacity_son) .alignItems(HorizontalAlign.Center) .backgroundColor(this.buttonColor) .borderRadius(40) .onClick(()=>{ //’AC‘功能的实现 if(this.num=='AC'){ this.flag = true; this.cal=''; this.result = '0'; return } else if(this.num=='='){ //如果第一次按下等号就显示等号 if(this.flag == true) { this.flag = false; let EndExpression =SwitchMiddleToEnd(this.cal); EndExpression.print_queue() this.result = calculate_achieve(EndExpression); } //否则不显示等号 else { let EndExpression = SwitchMiddleToEnd(this.cal); EndExpression.print_queue() this.result = calculate_achieve(EndExpression); this.result = String(roundToDecimal(this.result)); } } //将按钮所对应的字符加到计算式后 else { this.cal += this.num; } }) } } //数字栈 export class NumberStack{ numberstack:string[]; constructor() { this.numberstack = []; } push(item:string){ this.numberstack.push(item); } pop(){ return this.numberstack.pop() } peek(){ return this.numberstack[this.numberstack.length-1] } isEmpty(){ return this.numberstack.length ? false : true } clear(){ this.numberstack = []; } } //操作符栈 export class CharacterStack{ characterstack:string[]; constructor() { this.characterstack = []; } push(item:string){ this.characterstack.push(item); } pop(){ return this.characterstack.pop() } length(){ return this.characterstack.length; } peek(){ return this.characterstack[this.characterstack.length-1] } isEmpty(){ return this.characterstack.length ? false : true } clear(){ this.characterstack = []; } } export class queue_my{ items:string[] constructor(){ this.items = []; } enqueue(item:string){ this.items.push(item); } //删除第一个元素并且返回被删除的元素 dequeue(){ return this.items.shift(); } //返回队列中的第一个元素 peek(){ return this.items[0]; } //判断队列是否为空 isEmpty(){ return this.items.length ? false : true; } //返回队列大小 size(){ return this.items.length; } //打印队列中的元素 print_queue(){ for(let i =0;i<this.items.length;i++){ console.log(this.items[i]); } } } //父组件(入口) import { Button1 } from '../model/Button1' import { Button1_second } from '../model/Button1_second' import { Button2_second } from '../model/Button2_second' import { Button2 } from '../model/Button2' import {CharacterStack} from '../model/CharacterStack' import {NumberStack} from '../model/NumberStack' import {queue_my} from '../model/Queue' @Entry @Component struct Index { @State cal:string = ''; @State result:string|undefined|number = ''; @Provide flag:boolean = true; @State rotate_icon:number = 0; sta_x = 0; distance_x = 0; @State UIstate:boolean = false; @State Delete_bool:boolean = false; @State button_opacity_0:number = 1 @State button_opacity_1:number = 1 @State button_opacity_2:number = 1 @State button_opacity_3:number = 1 @State button_opacity_4:number = 1 @State button_opacity_5:number = 1 @State button_opacity_6:number = 1 @State button_opacity_7:number = 1 @State button_opacity_8:number = 1 @State button_opacity_9:number = 1 @State button_opacity_10:number = 1 @State button_opacity_11:number = 1 @State button_opacity_12:number = 1 @State button_opacity_13:number = 1 @State button_opacity_14:number = 1 @State button_opacity_15:number = 1 @State button_opacity_16:number = 1 @State button_opacity_17:number = 1 @State button_opacity_18:number = 1 @State button_opacity_19:number = 1 @State button_opacity_20:number = 1 @State button_opacity_21:number = 1 @State button_opacity_22:number = 1 @State button_opacity_23:number = 1 @State button_opacity_24:number = 1 build() { Column({space:10}) { Row() { Image($r('app.media.change')) .width(40) .height(40) .rotate({angle:this.rotate_icon}) .animation({ duration:300 }) .onClick(()=>{ this.rotate_icon = this.rotate_icon+180; this.UIstate = !this.UIstate; }) }.width('100%') .justifyContent(FlexAlign.End) .margin({top:10,right:15}) Blank() Column() { Text(`${this.result}`) .fontSize(60) .fontColor(Color.White) } .alignItems(HorizontalAlign.End) .justifyContent(FlexAlign.End) .padding({ right: 30 }) .width('100%') .height(100) Row() { Text(`${this.cal}`) .fontSize(24) .fontColor(Color.White) }.height(70) .width('100%') .justifyContent(FlexAlign.End) .padding({ right: 35 }) .onTouch((Event:TouchEvent)=>{ if(Event.type==TouchType.Down){ this.sta_x = Event.touches[0].x this.Delete_bool = true; } if(Event.type==TouchType.Up){ this.Delete_bool = true } if(Event.type==TouchType.Move){ this.distance_x = Math.abs(this.sta_x - Event.touches[0].x) // console.log(`x轴的距离为:${this.distance_x}`) // console.log(`bool值为:${this.Delete_bool}`) if(this.distance_x>20&&this.Delete_bool == true){ this.cal = this.cal.slice(0,-1); this.Delete_bool = false; } } }) //******************************************************* //******************************************************* //下面满足if条件代码为科学器部分,不建议参考,有大瑕疵!!!!!! //else条件中的代码为计算器主界面代码,值得参考!!! //******************************************************* //******************************************************* if (this.UIstate == true) { Row({ space: 10 }) { Button1_second({ cal: $cal, button_opacity_son: $button_opacity_0, result: $result, num: 'lg', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_0, result: $result, num: 'ln', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_0, result: $result, num: 'sin', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_0, result: $result, num: 'cos', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_0, result: $result, num: 'tan', textColor: Color.Black, buttonColor: 0xA5A5A5 }) } Row({ space: 10 }) { Button1_second({ cal: $cal, button_opacity_son: $button_opacity_0, result: $result, num: 'AC', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_1, result: $result, num: '(', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_2, result: $result, num: ')', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_3, result: $result, num: '÷', buttonColor: 0xFF9F0B }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_4, result: $result, num: '%', textSize: 22, buttonColor: 0xFF9F0B }) } Row({ space: 10 }) { Button1_second({ cal: $cal, button_opacity_son: $button_opacity_4, result: $result, num: '7' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_5, result: $result, num: '8' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_6, result: $result, num: '9' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_7, result: $result, num: '×', textSize: 30, buttonColor: 0xFF9F0B }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_7, result: $result, num: 'x!', textSize: 24, buttonColor: 0xFF9F0B }) } Row({ space: 10 }) { Button1_second({ cal: $cal, button_opacity_son: $button_opacity_8, result: $result, num: '4' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_9, result: $result, num: '5' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_10, result: $result, num: '6' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_11, result: $result, num: '-', textSize: 30, buttonColor: 0xFF9F0B }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_11, result: $result, num: '1/x', textSize: 20, buttonColor: 0xFF9F0B }) } Row({ space: 10 }) { Button1_second({ cal: $cal, button_opacity_son: $button_opacity_12, result: $result, num: '1' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_13, result: $result, num: '2' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_14, result: $result, num: '3' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_15, result: $result, num: '+', textSize: 30, buttonColor: 0xFF9F0B }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_15, result: $result, num: 'π', textSize: 24, buttonColor: 0xFF9F0B }) } Row({ space: 10 }) { Button2_second({ cal: $cal, button_opacity_son: $button_opacity_16 }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_17, result: $result, num: '.' }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_18, result: $result, num: '=', textSize: 30, buttonColor: 0xFF9F0B }) Button1_second({ cal: $cal, button_opacity_son: $button_opacity_18, result: $result, num: '=', textSize: 30, buttonColor: 0xFF9F0B }) }.margin({ bottom: 20 }) } //以上if中的代码不可参考!!! //以下代码可参考!!! else { Row({ space: 10 }) { Button1({ cal: $cal, button_opacity_son: $button_opacity_0, result: $result, num: 'AC', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1({ cal: $cal, button_opacity_son: $button_opacity_1, result: $result, num: '(', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1({ cal: $cal, button_opacity_son: $button_opacity_2, result: $result, num: ')', textColor: Color.Black, buttonColor: 0xA5A5A5 }) Button1({ cal: $cal, button_opacity_son: $button_opacity_3, result: $result, num: '÷', buttonColor: 0xFF9F0B }) } Row({ space: 10 }) { Button1({ cal: $cal, button_opacity_son: $button_opacity_4, result: $result, num: '7' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_5, result: $result, num: '8' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_6, result: $result, num: '9' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_7, result: $result, num: '×', textSize: 30, buttonColor: 0xFF9F0B }) } Row({ space: 10 }) { Button1({ cal: $cal, button_opacity_son: $button_opacity_8, result: $result, num: '4' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_9, result: $result, num: '5' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_10, result: $result, num: '6' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_11, result: $result, num: '-', textSize: 30, buttonColor: 0xFF9F0B }) } Row({ space: 10 }) { Button1({ cal: $cal, button_opacity_son: $button_opacity_12, result: $result, num: '1' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_13, result: $result, num: '2' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_14, result: $result, num: '3' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_15, result: $result, num: '+', textSize: 30, buttonColor: 0xFF9F0B }) } Row({ space: 10 }) { Button2({ cal: $cal, button_opacity_son: $button_opacity_16 }) Button1({ cal: $cal, button_opacity_son: $button_opacity_17, result: $result, num: '.' }) Button1({ cal: $cal, button_opacity_son: $button_opacity_18, result: $result, num: '=', textSize: 30, buttonColor: 0xFF9F0B }) } .margin({ bottom: 20 }) } } .width('100%') .height('100%') .backgroundColor(Color.Black) } } //获得优先级等级的函数 function getPrecedence(item:string):number{ switch(item){ case '%':return 3 case '×':return 2 case '÷':return 2 case '+': // console.log('读取到了+号') return 1 case '-':return 1 default:return 0 } } //中缀表达式转后缀表达式函数 export function SwitchMiddleToEnd(cal:string){ let queue = new queue_my(); let first_fu:boolean = true let switchStack = new CharacterStack(); let i =0; while(i<cal.length){ //如果遍历到数字直接入队 if(isNumber(cal[i])){ let numberstring = ''; while(isNumber(cal[i])){ numberstring+=cal[i]; i++ } queue.enqueue(numberstring); console.log(`${numberstring}入队`); i-- } //如果遇到第一个位置是左括号加-号 else if(cal[0]=='('&&cal[1]=='-'&&first_fu){ switchStack.push(cal[0]); let numberstring = '-' first_fu = false; i = 2 while(isNumber(cal[i])){ numberstring+=cal[i] i++ } queue.enqueue(numberstring) i-- console.log(`${numberstring}入队`); console.log(`此时遍历到了:${cal[i]}`) } else if(cal[0]=='-'&&isNumber(cal[1])&&first_fu){ let numberstring = '-'; first_fu = false; i=1; while(isNumber(cal[i])){ numberstring+=cal[i]; i++ } queue.enqueue(numberstring); console.log(`${numberstring}入队`); i--; } //如果连按几次同一个操作符 else if(!isNumber(cal[i])&&!isNumber(cal[i+1])&&cal[i]==cal[i+1]){ i++; } //带括号的负数在中间的时候 else if(cal[i]=='('&&cal[i+1]=='-'&&isNumber(cal[i+2])){ let numberstring = '-'; i = i+2; while(isNumber(cal[i])){ numberstring+=cal[i]; ++i } queue.enqueue(numberstring) console.log(`${numberstring}已经入队`) } //如果栈中为空或者遇到左括号直接入栈 else if(switchStack.isEmpty()||cal[i]=='('){ if(cal[i]=='(') console.log('遇到了左括号') switchStack.push(cal[i]); } //栈顶操作符优先级小于当前操作符优先级 else if(cal[i]!=')'&&getPrecedence(switchStack.peek())<getPrecedence(cal[i])){ switchStack.push(cal[i]); } //栈顶操作符优先级大于当前操作符优先级 else if(cal[i]!=')'&&getPrecedence(switchStack.peek())>=getPrecedence(cal[i])){ //栈顶元素出栈并且加到队列中去 while(getPrecedence(cal[i])<=getPrecedence(switchStack.peek())) {queue.enqueue(String(switchStack.pop())) if(switchStack.isEmpty()){break} } switchStack.push(cal[i]); } //如果遇到了右括号 else if(cal[i]==')') { // console.log('遇到了右括号') while (switchStack.peek() != '(') { let temp: string = String(switchStack.pop()); queue.enqueue(temp); } //遇到左括号时直接将左括号弹出 switchStack.pop() // console.log('左括号出栈') } i++; } //最后将剩余的操作符全部放到队列中 while(!switchStack.isEmpty()) { queue.enqueue(String(switchStack.pop())) } return queue; } //后缀表达式计算函数 export function calculate_achieve(que:queue_my):string{ let numberstack = new NumberStack(); let i =0; let sum=que.size() while(i<sum){ //如果遇到数字直接入栈并删除该元素 if(!isCharacter(que.peek())){ console.log(`${que.peek()}已经入栈`) numberstack.push(que.peek()); que.dequeue() i++; } //如果遇到了操作符 else{ let num_up = numberstack.pop(); let num_down = numberstack.pop(); if(que.peek()=='+'){ numberstack.push(String(Number(num_down)+Number(num_up))) // console.log(`${String(Number(num_down)+Number(num_up))}入栈`) } else if(que.peek()=='-'){ numberstack.push(String(Number(num_down)-Number(num_up))) // console.log(`${String(Number(num_down)-Number(num_up))}入栈`) } else if(que.peek()=='×'){ if(num_up=='3'||num_up=='6'||num_up=='9') { numberstack.push(String((Number(num_down)*(Number(num_up)*10000))/10000)) } else{ numberstack.push(String((Number(num_down) * Number(num_up) * 100) / 100)) } // console.log(`${String(Number(num_down)*Number(num_up))}入栈`) } else if(que.peek()=='÷'){ if(num_up=='0') numberstack.push('不能除以0') else { numberstack.push(String(Number(num_down) / Number(num_up))) } // console.log(`${String(Number(num_down)/Number(num_up))}入栈`) } que.dequeue(); i++; } } return String(numberstack.pop()); } //判断这个字符是不是数字 function isNumber(item:string):boolean{ if(item=='0'||item=='1'||item=='2'||item=='3'||item=='4'||item=='5'||item=='6'|| item=='7'||item=='8'||item=='9'||item=='.'){ return true; } else return false; } //判断这个字符是不是操作符 function isCharacter(item:string):boolean{ if(item=='+'||item=='-'||item=='÷'||item=='×'||item=='('||item==')'){ return true; } else return false; }
复制