用户云卷云舒 发表于 2024-10-23 14:38:49

使用ArkTs举行计算器的实现

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

在calcultorDemo.ets文件中

import {calculatorResult} from './calculatorResult'
import numberstackfrom './NumberStack'
import characterstack from './CharacterStack'
@Entry
@Component
struct 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(){
      calculatorResult({value:$value,result:this.result,opacityValue:$opacityValue,fontSizeValue:$fontSizeValue})
      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(()=>{
            this.value=this.value.slice(0,this.value.length-1)
            this.result=''
          })

          GridItem(){
            Text('C')
            .TextStyle()
          }
          .oneStyle()
          .onClick(()=>{
            this.value=''
            this.result=''
          })

          ForEach(this.numbers,item=>{
            GridItem(){
            Text(item)
                .TextStyle()
            }
            .onClick(()=>{
            if (this.value === '' && (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%')) {
                return
            }//判断点击的第一个字符是不是运算符,若是则返回
            if (this.value === '+' || this.value === '-' ||
            this.value === '×' || this.value === '÷' ||
            this.value === '%') {
                // 如果当前点击的是运算符,则替换最后一个运算符
                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)
}

   以上代码写出计算机的键盘部分,使用Grid组件举行键盘的分隔,以及对雷同功能的按钮举行ForEach循环渲染减少占有空间
https://i-blog.csdnimg.cn/direct/de1493127651447484f4958639b89405.png
在calculatorResult.ets中

举行键盘输入(TextInput)和输出(Text)的编写
@Component
export structcalculatorResult{
@Link value:string
@Prop result:string
@Link opacityValue:number
@Link fontSizeValue:number
build() {
      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)
      }
}
}
   经过以上两个文件的渲染后,计算机的大概形状显示出来,如图所示:
https://i-blog.csdnimg.cn/direct/6aac9e2bc1244661b778989a48e0778c.png
2、举行计算机的功能部分

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

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

   重要思路:
1、将中缀表达式转为后缀表达式;
2、对后缀表达式求值;
具体可参考:栈的应用-表达式求值
代码如下:
1、在calcultorDemo.ets中:
//检查括号是否多余,且若前括号多余则去掉多余的前括号
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
while (ch!='#'||characterstack.peek()!='#') {
    if(!Instring(ch)){//进行多位数的入栈
      let numStr = ch
      while (i + 1 < expression.length && !Instring(expression)) {
      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'
}
2、在CharacterStack.ets中举行字符栈的初始化,并举行导出;
//运算符栈
class CharacterStack{
private characters:string[]

constructor() {
    this.characters=[]
}
//入栈
push(item:string){
    this.characters.push(item)
}
//出栈
pop(){
    return this.characters.pop()
}
//返回栈顶元素
peek(){
    return this.characters
}
//判断栈是否为空
isEmpty(){
    return this.characters.length===0
}
//清空栈内元素
clear(){
    this.characters=[]
}
//获取栈内元素数量
size():number{
    return this.characters.length
}
}
const characterstack =new CharacterStack()
export defaultcharacterstack
3、在NumberStack.ets中举行数字栈的初始化,并举行导出;
//数字栈
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
}
//判断栈是否为空
isEmpty(){
    return this.numbers.length===0
}
//清空栈内元素
clear(){
    this.numbers=[]
}
//获取栈内元素数量
size():number{
    return this.numbers.length
}
}
const numberstack =new NumberStack()
export defaultnumberstack
已解决题目:
1、括号不对应,对前括号去掉,或直接报错;
2、重复输入符号的题目;
3、首相为符号的题目;
存在题目:
1、“3-”不可以输出正常的3;
https://i-blog.csdnimg.cn/direct/4bdea52d4cd84387aedfa2063f816e35.png
2、对负数不可举行计算;…(存在未发现题目)
3、完整代码(一个文件)

@Entry@Componentstruct calcultorDemo {@State value:string =''@State result:string=''@State opacityValue:number=0@State fontSizeValue:number=30numbers :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(()=>{
            this.value=this.value.slice(0,this.value.length-1)
            this.result=''
          })
          GridItem(){            Text('C')            .TextStyle()          }          .oneStyle()          .onClick(()=>{
            this.value=''
            this.result=''
          })
          ForEach(this.numbers,item=>{            GridItem(){            Text(item)                .TextStyle()            }            .onClick(()=>{            if (this.value === '' && (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%')) {                return            }//判断点击的第一个字符是不是运算符,如果则返回            if (this.value === '+' || this.value === '-' ||            this.value === '×' || this.value === '÷' ||            this.value === '%') {                // 如果当前点击的是运算符,则更换最后一个运算符                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}//判断栈是否为空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}//判断栈是否为空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 = expressionfor (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=0let ch=expressionwhile (ch!='#'||characterstack.peek()!='#') {    if(!Instring(ch)){//举行多位数的入栈      let numStr = ch      while (i + 1 < expression.length && !Instring(expression)) {      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企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 使用ArkTs举行计算器的实现