鸿蒙应用开发---计算器
- 计算器
- 效果图
- 设计思路
- 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;
}