使用ArkTs进行计算器的实现

了了一。 2024-10-22 11:33:01 阅读 78

使用ArkTs进行计算器的实现,基于deveco-studio3.1.1,新版未尝试

1、写出大致的计算器构造在calcultorDemo.ets文件中在calculatorResult.ets中

2、进行计算机的功能部分给每个按钮分别添加点击事件完成value的计算事件,利用栈进行算术表达式的求值:

3、完整代码(一个文件)

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

在calcultorDemo.ets文件中

<code>import {calculatorResult} from './calculatorResult'

import numberstack from './NumberStack'

import characterstack from './CharacterStack'

@Entry

@Component

struct calcultorDemo {

@State value:string =''

@State result:string=''code>

@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=''code>

})

GridItem(){

Text('C')

.TextStyle()

}

.oneStyle()

.onClick(()=>{

this.value=''code>

this.result=''code>

})

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)

}

以上代码写出计算机的键盘部分,使用Grid组件进行键盘的分隔,以及对相同功能的按钮进行ForEach循环渲染减少占有空间

在这里插入图片描述

在calculatorResult.ets中

进行键盘输入(TextInput)和输出(Text)的编写

<code>@Component

export struct calculatorResult{

@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)

}

}

}

经过以上两个文件的渲染后,计算机的大概形状显示出来,如图所示:

在这里插入图片描述

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

给每个按钮分别添加点击事件

1、对1,2,3,4,5,6,7,8,9,+, - , × ,÷添加存储表达式的点击事件,定义 @State value:string =‘’ 在每次进行点击时,对所点击的内容做出判断,储存所点击的内容。

<code>.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)

}

})

2、对删除按钮:定义 @State result:string=''进行计算机结果的保存,方便后续渲染在Text组件中。

<code>.onClick(()=>{

this.value=this.value.slice(0,this.value.length-1)

this.result=''code>

})

3、对于清零工具则将value和result都置为空

.onClick(()=>{

this.value=''code>

this.result=''code>

})

完成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[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'

}

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[this.characters.length-1]

}

//判断栈是否为空

isEmpty(){

return this.characters.length===0

}

//清空栈内元素

clear(){

this.characters=[]

}

//获取栈内元素数量

size():number{

return this.characters.length

}

}

const characterstack =new CharacterStack()

export default characterstack

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[this.numbers.length-1]

}

//判断栈是否为空

isEmpty(){

return this.numbers.length===0

}

//清空栈内元素

clear(){

this.numbers=[]

}

//获取栈内元素数量

size():number{

return this.numbers.length

}

}

const numberstack =new NumberStack()

export default numberstack

已解决问题

1、括号不对应,对前括号去掉,或直接报错;

2、重复输入符号的问题;

3、首相为符号的问题;

存在问题

1、“3-”不可以输出正常的3;

在这里插入图片描述

2、对负数不可进行计算;…(存在未发现问题)

3、完整代码(一个文件)

<code>@Entry

@Component

struct calcultorDemo {

@State value:string =''

@State result:string=''code>

@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(()=>{

this.value=this.value.slice(0,this.value.length-1)

this.result=''code>

})

GridItem(){

Text('C')

.TextStyle()

}

.oneStyle()

.onClick(()=>{

this.value=''code>

this.result=''code>

})

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'

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。