1、写出大抵的计算器构造
在calcultorDemo.ets文件中
- import {calculatorResult} from './calculatorResult'
- import numberstack from './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.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)的编写
- @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 =‘’ 在每次举行点击时,对所点击的内容做出判断,储存所点击的内容。
- .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组件中。
- .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[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、完整代码(一个文件)
- @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(()=>{
- 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.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企服之家,中国第一个企服评测及商务社交产业平台。 |