使用ArkTs举行计算器的实现

打印 上一主题 下一主题

主题 904|帖子 904|积分 2712

1、写出大抵的计算器构造

在calcultorDemo.ets文件中

  1. import {calculatorResult} from './calculatorResult'
  2. import numberstack  from './NumberStack'
  3. import characterstack from './CharacterStack'
  4. @Entry
  5. @Component
  6. struct calcultorDemo {
  7.   @State value:string =''
  8.    @State result:string=''
  9.   @State opacityValue:number=0
  10.   @State fontSizeValue:number=30
  11.   numbers :string[]=['(',')','÷','×','1','2','3','-','4','5','6','+','7','8','9']
  12.   numbers2:string[]=['%','0','.']
  13.   build() {
  14.     Column(){
  15.       calculatorResult({value:$value,result:this.result,opacityValue:$opacityValue,fontSizeValue:$fontSizeValue})
  16.       Column(){//计算机主体页面
  17.         Grid(){
  18.           GridItem(){
  19.             Text('MC')
  20.               .TextStyle()
  21.           }
  22.           .oneStyle()//MC(清零)工具
  23.           GridItem(){
  24.             Text('MR')
  25.               .TextStyle()
  26.           }
  27.           .oneStyle()
  28.           GridItem(){
  29.             Image($r('app.media.delete'))
  30.               .fillColor(Color.Blue)
  31.               .height(40)
  32.           }
  33.           .oneStyle()
  34.           .onClick(()=>{
  35.             this.value=this.value.slice(0,this.value.length-1)
  36.             this.result=''
  37.           })
  38.           GridItem(){
  39.             Text('C')
  40.               .TextStyle()
  41.           }
  42.           .oneStyle()
  43.           .onClick(()=>{
  44.             this.value=''
  45.             this.result=''
  46.           })
  47.           ForEach(this.numbers,item=>{
  48.             GridItem(){
  49.               Text(item)
  50.                 .TextStyle()
  51.             }
  52.             .onClick(()=>{
  53.               if (this.value === '' && (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%')) {
  54.                 return
  55.               }//判断点击的第一个字符是不是运算符,若是则返回
  56.               if (this.value[this.value.length - 1] === '+' || this.value[this.value.length - 1] === '-' ||
  57.               this.value[this.value.length - 1] === '×' || this.value[this.value.length - 1] === '÷' ||
  58.               this.value[this.value.length - 1] === '%') {
  59.                 // 如果当前点击的是运算符,则替换最后一个运算符
  60.                 if (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%') {
  61.                   this.value = this.value.slice(0, this.value.length - 1) + item
  62.                 } else {
  63.                   this.value += item
  64.                 }
  65.               } else {
  66.                 this.value = this.value.concat(item)
  67.               }
  68.             })
  69.             .oneStyle()
  70.           })
  71.           GridItem(){
  72.             Text('=')
  73.               .TextStyle()
  74.               .fontColor(Color.White)
  75.           }
  76.           .rowStart(5)
  77.           .rowEnd(6)
  78.           .borderRadius(40)
  79.           .backgroundColor(Color.Blue)
  80.           .onClick(()=>{
  81.             this.result=total(checkParentheses(this.value+'#').cleanedExpression)
  82.             this.opacityValue=1
  83.             this.fontSizeValue=50
  84.           })
  85.           ForEach(this.numbers2,item=>{
  86.             GridItem(){
  87.               Text(item)
  88.                 .TextStyle()
  89.             }
  90.             .onClick(()=>{this.value=this.value.concat(item)})
  91.             .oneStyle()
  92.           })
  93.         }
  94.         .width('100%')
  95.         .height(500)
  96.         .columnsTemplate('1fr 1fr 1fr 1fr')
  97.         .rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr')
  98.         .columnsGap(8)
  99.         .rowsGap(12)
  100.         .padding(12)
  101.         .backgroundColor('#fff6f0f0')
  102.         .borderRadius({topLeft:20,topRight:20})
  103.       }
  104.       .layoutWeight(1)
  105.       .justifyContent(FlexAlign.End)
  106.     }
  107.     .height('100%')
  108.   }
  109. }
  110. @Styles function oneStyle(){
  111.   .backgroundColor(Color.White)
  112.   .height(70)
  113.   .width(70)
  114.   .borderRadius(40)
  115.   .shadow({color:Color.Gray,radius:5})
  116. }
  117. @Extend(Text) function TextStyle() {
  118.   .fontSize(25)
  119.   .fontWeight(400)
  120. }
复制代码
  以上代码写出计算机的键盘部分,使用Grid组件举行键盘的分隔,以及对雷同功能的按钮举行ForEach循环渲染减少占有空间

  在calculatorResult.ets中

举行键盘输入(TextInput)和输出(Text)的编写
  1. @Component
  2. export struct  calculatorResult{
  3.   @Link value:string
  4.   @Prop result:string
  5.   @Link opacityValue:number
  6.   @Link fontSizeValue:number
  7.   build() {
  8.       Column(){
  9.         TextInput({text:this.value})
  10.           .height(80)
  11.           .margin({top:60})
  12.           .placeholderFont({size:60})
  13.           .fontSize(60)
  14.           .fontWeight(450)
  15.           .textAlign(TextAlign.End)
  16.           .backgroundColor(Color.White)
  17.         Text(this.result)
  18.           .opacity(this.opacityValue)
  19.           .width('100%')
  20.           .height(60)
  21.           .fontSize(this.fontSizeValue)
  22.           .fontWeight(450)
  23.           .textAlign(TextAlign.End)
  24.           .animation({duration:500})
  25.             // @ts-ignore
  26.           .textOverflow(TextOverflow.Clip)
  27.       }
  28.   }
  29. }
复制代码
  经过以上两个文件的渲染后,计算机的大概形状显示出来,如图所示:

  2、举行计算机的功能部分

给每个按钮分别添加点击变乱

1、对1,2,3,4,5,6,7,8,9,+, - , × ,÷添加存储表达式的点击变乱,定义 @State value:string =‘’ 在每次举行点击时,对所点击的内容做出判断,储存所点击的内容。
  1. .onClick(()=>{
  2.               if (this.value === '' && (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%')) {
  3.                 return
  4.               }//判断点击的第一个字符是不是运算符,若是则返回
  5.               if (this.value[this.value.length - 1] === '+' || this.value[this.value.length - 1] === '-' ||
  6.               this.value[this.value.length - 1] === '×' || this.value[this.value.length - 1] === '÷' ||
  7.               this.value[this.value.length - 1] === '%') {
  8.                 // 如果在上一个字符是运算符时,当前点击的是运算符,则替换最后一个运算符
  9.                 if (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%') {
  10.                   this.value = this.value.slice(0, this.value.length - 1) + item
  11.                 } else {
  12.                 //若当前点击不是运算符而是数字时,则继续输入表达式
  13.                   this.value += item
  14.                 }
  15.               } else {
  16.                 this.value = this.value.concat(item)
  17.               }
  18.             })
复制代码
2、对删除按钮:定义 @State result:string=''举行计算机结果的保存,方便后续渲染在Text组件中。
  1. .onClick(()=>{
  2.             this.value=this.value.slice(0,this.value.length-1)
  3.             this.result=''
  4.           })
复制代码
3、对于清零工具则将value和result都置为空
  1. .onClick(()=>{
  2.             this.value=''
  3.             this.result=''
  4.           })
复制代码
完成value的计算变乱,利用栈举行算术表达式的求值:

   重要思路:
1、将中缀表达式转为后缀表达式;
2、对后缀表达式求值;
具体可参考:栈的应用-表达式求值
  代码如下:
1、在calcultorDemo.ets中:
  1. //检查括号是否多余,且若前括号多余则去掉多余的前括号
  2. function checkParentheses(expression: string): { valid: boolean, cleanedExpression: string } {
  3.   let stack = []
  4.   let cleanedExpression = expression
  5. //判断表达式括号是否对应
  6.   for (let ch of expression) {
  7.     if (ch === '(') {
  8.       stack.push(ch)
  9.     } else if (ch === ')') {//后括号多余则直接返回错误
  10.       if (stack.length === 0) {
  11.         return { valid: false, cleanedExpression: expression }
  12.       }
  13.       stack.pop()
  14.     }
  15.   }
  16.   //若不对应,去掉多余的前括号
  17.   while (stack.length > 0) {
  18.     let index = cleanedExpression.indexOf('(')
  19.     if (index !== -1) {
  20.       cleanedExpression = cleanedExpression.slice(0, index) + cleanedExpression.slice(index + 1)
  21.     }
  22.     stack.pop()
  23.   }
  24.   console.log(cleanedExpression)
  25.   return { valid: stack.length === 0, cleanedExpression }
  26. }
  27. //对表达式求值
  28. function total(expression:string){
  29.   characterstack.push('#')
  30.   let i=0
  31.   let ch=expression[i]
  32.   while (ch!='#'||characterstack.peek()!='#') {
  33.     if(!Instring(ch)){//进行多位数的入栈
  34.       let numStr = ch
  35.       while (i + 1 < expression.length && !Instring(expression[i + 1])) {
  36.         ch = expression[++i]
  37.         numStr += ch
  38.       }
  39.       numberstack.push(numStr)
  40.       ch = expression[++i]
  41.     }
  42.     else{
  43.       switch (Precede(characterstack.peek(),ch)){
  44.         case '<':{
  45.           characterstack.push(ch);
  46.           ch=expression[++i]
  47.           break
  48.         }
  49.         case '>':{
  50.           let theta= characterstack.pop()
  51.           let b=numberstack.pop()
  52.           let a=numberstack.pop()
  53.           numberstack.push(Operate(a,theta,b))
  54.           break
  55.         }
  56.         case '=':{
  57.           characterstack.pop()
  58.           ch=expression[++i]
  59.           break
  60.         }
  61.       }
  62.     }
  63.   }
  64.   return numberstack.peek()
  65. }
  66. //判断ch是否为运算符
  67. function Instring(ch:string){
  68.   let num:string[]=['+','-','(',')','÷','×','#','%']
  69.   return num.includes(ch)
  70. }
  71. //判断运算符的优先级
  72. function Precede(thetal:string,thetal2:string):string{
  73.   if((thetal=='('&&thetal2==')')||(thetal=='#'&&thetal2=='#')){
  74.     return '='
  75.   }
  76.   else if(thetal=='('||thetal=='#'||thetal2=='('||(thetal=='+'||thetal=='-')&&(thetal2=='×'||thetal2=='÷'||thetal2=='%')){
  77.     return '<'
  78.   }
  79.   else return '>'
  80. }
  81. //计算两数的运算结果
  82. function Operate(first:string,theta:string,second:string):string{
  83.   switch (theta){
  84.     case '+':
  85.       return ((+first)+(+second)).toString()
  86.     case '-':
  87.       return ((+first)-(+second)).toString()
  88.     case '×':
  89.       return ((+first)*(+second)).toString()
  90.     case '÷':
  91.       return ((+first)/(+second)).toString()
  92.     case '%':
  93.       return ((+first)%(+second)).toString()
  94.   }
  95.   return 'NaN'
  96. }
复制代码
2、在CharacterStack.ets中举行字符栈的初始化,并举行导出;
  1. //运算符栈
  2. class CharacterStack{
  3.   private characters:string[]
  4.   constructor() {
  5.     this.characters=[]
  6.   }
  7.   //入栈
  8.   push(item:string){
  9.     this.characters.push(item)
  10.   }
  11.   //出栈
  12.   pop(){
  13.     return this.characters.pop()
  14.   }
  15.   //返回栈顶元素
  16.   peek(){
  17.     return this.characters[this.characters.length-1]
  18.   }
  19.   //判断栈是否为空
  20.   isEmpty(){
  21.     return this.characters.length===0
  22.   }
  23.   //清空栈内元素
  24.   clear(){
  25.     this.characters=[]
  26.   }
  27.   //获取栈内元素数量
  28.   size():number{
  29.     return this.characters.length
  30.   }
  31. }
  32. const characterstack =new CharacterStack()
  33. export default  characterstack
复制代码
3、在NumberStack.ets中举行数字栈的初始化,并举行导出;
  1. //数字栈
  2. export class NumberStack{
  3.   private numbers:string[]
  4.   constructor() {
  5.     this.numbers=[]
  6.   }
  7.   //入栈
  8.   push(item:string){
  9.     this.numbers.push(item)
  10.   }
  11.   //出栈
  12.   pop(){
  13.     return this.numbers.pop()
  14.   }
  15.   //返回栈顶元素
  16.   peek(){
  17.     return this.numbers[this.numbers.length-1]
  18.   }
  19.   //判断栈是否为空
  20.   isEmpty(){
  21.     return this.numbers.length===0
  22.   }
  23.   //清空栈内元素
  24.   clear(){
  25.     this.numbers=[]
  26.   }
  27.   //获取栈内元素数量
  28.   size():number{
  29.     return this.numbers.length
  30.   }
  31. }
  32. const numberstack =new NumberStack()
  33. export default  numberstack
复制代码
已解决题目:
1、括号不对应,对前括号去掉,或直接报错;
2、重复输入符号的题目;
3、首相为符号的题目;
存在题目:
1、“3-”不可以输出正常的3;

2、对负数不可举行计算;…(存在未发现题目)
3、完整代码(一个文件)

  1. @Entry@Componentstruct calcultorDemo {  @State value:string =''  @State result:string=''  @State opacityValue:number=0  @State fontSizeValue:number=30  numbers :string[]=['(',')','÷','×','1','2','3','-','4','5','6','+','7','8','9']  numbers2:string[]=['%','0','.']  build() {    Column(){      Column(){        TextInput({text:this.value})          .height(80)          .margin({top:60})          .placeholderFont({size:60})          .fontSize(60)          .fontWeight(450)          .textAlign(TextAlign.End)          .backgroundColor(Color.White)        Text(this.result)          .opacity(this.opacityValue)          .width('100%')          .height(60)          .fontSize(this.fontSizeValue)          .fontWeight(450)          .textAlign(TextAlign.End)          .animation({duration:500})            // @ts-ignore          .textOverflow(TextOverflow.Clip)      }      Column(){//计算机主体页面        Grid(){          GridItem(){            Text('MC')              .TextStyle()          }          .oneStyle()//MC(清零)工具          GridItem(){            Text('MR')              .TextStyle()          }          .oneStyle()          GridItem(){            Image($r('app.media.delete'))              .fillColor(Color.Blue)              .height(40)          }          .oneStyle()          .onClick(()=>{
  2.             this.value=this.value.slice(0,this.value.length-1)
  3.             this.result=''
  4.           })
  5.           GridItem(){            Text('C')              .TextStyle()          }          .oneStyle()          .onClick(()=>{
  6.             this.value=''
  7.             this.result=''
  8.           })
  9.           ForEach(this.numbers,item=>{            GridItem(){              Text(item)                .TextStyle()            }            .onClick(()=>{              if (this.value === '' && (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%')) {                return              }//判断点击的第一个字符是不是运算符,如果则返回              if (this.value[this.value.length - 1] === '+' || this.value[this.value.length - 1] === '-' ||              this.value[this.value.length - 1] === '×' || this.value[this.value.length - 1] === '÷' ||              this.value[this.value.length - 1] === '%') {                // 如果当前点击的是运算符,则更换最后一个运算符                if (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%') {                  this.value = this.value.slice(0, this.value.length - 1) + item                } else {                  this.value += item                }              } else {                this.value = this.value.concat(item)              }            })            .oneStyle()          })          GridItem(){            Text('=')              .TextStyle()              .fontColor(Color.White)          }          .rowStart(5)          .rowEnd(6)          .borderRadius(40)          .backgroundColor(Color.Blue)          .onClick(()=>{            this.result=total(checkParentheses(this.value+'#').cleanedExpression)            this.opacityValue=1            this.fontSizeValue=50          })          ForEach(this.numbers2,item=>{            GridItem(){              Text(item)                .TextStyle()            }            .onClick(()=>{this.value=this.value.concat(item)})            .oneStyle()          })        }        .width('100%')        .height(500)        .columnsTemplate('1fr 1fr 1fr 1fr')        .rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr')        .columnsGap(8)        .rowsGap(12)        .padding(12)        .backgroundColor('#fff6f0f0')        .borderRadius({topLeft:20,topRight:20})      }      .layoutWeight(1)      .justifyContent(FlexAlign.End)    }    .height('100%')  }}@Styles function oneStyle(){  .backgroundColor(Color.White)  .height(70)  .width(70)  .borderRadius(40)  .shadow({color:Color.Gray,radius:5})}@Extend(Text) function TextStyle() {  .fontSize(25)  .fontWeight(400)}//运算符栈class CharacterStack{  private characters:string[]  constructor() {    this.characters=[]  }  //入栈  push(item:string){    this.characters.push(item)  }  //出栈  pop(){    return this.characters.pop()  }  //返回栈顶元素  peek(){    return this.characters[this.characters.length-1]  }  //判断栈是否为空  isEmpty(){    return this.characters.length===0  }  //清空栈内元素  clear(){    this.characters=[]  }  //获取栈内元素数量  size():number{    return this.characters.length  }}const characterstack =new CharacterStack()//数字栈export class NumberStack{  private numbers:string[]  constructor() {    this.numbers=[]  }  //入栈  push(item:string){    this.numbers.push(item)  }  //出栈  pop(){    return this.numbers.pop()  }  //返回栈顶元素  peek(){    return this.numbers[this.numbers.length-1]  }  //判断栈是否为空  isEmpty(){    return this.numbers.length===0  }  //清空栈内元素  clear(){    this.numbers=[]  }  //获取栈内元素数量  size():number{    return this.numbers.length  }}const numberstack =new NumberStack()//检查括号是否多余,且若前括号多余则去掉多余的前括号function checkParentheses(expression: string): { valid: boolean, cleanedExpression: string } {  let stack = []  let cleanedExpression = expression  for (let ch of expression) {    if (ch === '(') {      stack.push(ch)    } else if (ch === ')') {      if (stack.length === 0) {        return { valid: false, cleanedExpression: expression }      }      stack.pop()    }  }  // 去掉多余的前括号  while (stack.length > 0) {    let index = cleanedExpression.indexOf('(')    if (index !== -1) {      cleanedExpression = cleanedExpression.slice(0, index) + cleanedExpression.slice(index + 1)    }    stack.pop()  }  console.log(cleanedExpression)  return { valid: stack.length === 0, cleanedExpression }}function total(expression:string){  characterstack.push('#')  let i=0  let ch=expression[i]  while (ch!='#'||characterstack.peek()!='#') {    if(!Instring(ch)){//举行多位数的入栈      let numStr = ch      while (i + 1 < expression.length && !Instring(expression[i + 1])) {        ch = expression[++i]        numStr += ch      }      numberstack.push(numStr)      ch = expression[++i]    }    else{      switch (Precede(characterstack.peek(),ch)){        case '<':{          characterstack.push(ch);          ch=expression[++i]          break        }        case '>':{          let theta= characterstack.pop()          let b=numberstack.pop()          let a=numberstack.pop()          numberstack.push(Operate(a,theta,b))          break        }        case '=':{          characterstack.pop()          ch=expression[++i]          break        }      }    }  }  return numberstack.peek()}//判断ch是否为运算符function Instring(ch:string){  let num:string[]=['+','-','(',')','÷','×','#','%']  return num.includes(ch)}//判断运算符的优先级function Precede(thetal:string,thetal2:string):string{  if((thetal=='('&&thetal2==')')||(thetal=='#'&&thetal2=='#')){    return '='  }  else if(thetal=='('||thetal=='#'||thetal2=='('||(thetal=='+'||thetal=='-')&&(thetal2=='×'||thetal2=='÷'||thetal2=='%')){    return '<'  }  else return '>'}//计算两数的运算结果function Operate(first:string,theta:string,second:string):string{  switch (theta){    case '+':      return ((+first)+(+second)).toString()    case '-':      return ((+first)-(+second)).toString()    case '×':      return ((+first)*(+second)).toString()    case '÷':      return ((+first)/(+second)).toString()    case '%':      return ((+first)%(+second)).toString()  }  return 'NaN'}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户云卷云舒

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表