【HarmonyOS——ArkTS语言】计算器的实现【合集】

简介: 【ArkTS语言-HarmonyOS】计算器的实现【合集】组件,点击等号后计算函数高效解析表达式并给出准确结果,达成核心功能要求。错误提示不够详尽,难以助力用户快速定位输入错误;响应式设计不足,在不同屏幕规格下适配性差。总体而言,本次实验已成功构建起基本功能框架,后续将针对上述问题深入探究优化方案,不断打磨细节,在完善计算器功能与提升用户体验的道路上持续精进,进而提升自身编程与应用开发的综合能力水平。利用按钮组件顺利完成布局设计,数字、运算符及功能按钮排列有序,操作逻辑清晰直观。

目录

🎯学习小目标:

📺演示效果:

📖实验步骤及方法:

1. 在index.ets文件中通过 @Extend(Button) 装饰器扩展Button 组件设置按钮样式函数myButton

2. 设置运算符枚举类型 Operator

3. 设置获取运算符优先级的函数 getOperatorPrecedence

4.设置计算表达式结果的函数 calculateResult

5.设置主界面组件 Index

6.模拟机运行测试

👋实验小结


🎯学习小目标:

  1. 创建一个工程,在index.ets文件中进行编辑
  2. 使用按钮组件设计计算器的布局
  3. 点击按钮后将计算过程显示在Text组件中
  4. 点击等号显示计算结果

📺演示效果:

image.gif image.gif image.gif

图1 预览器演示效果


📖实验步骤及方法:

1. 在index.ets文件中通过 @Extend(Button) 装饰器扩展Button 组件设置按钮样式函数myButton

@Extend(Button)
function myButton() {
.type(ButtonType.Normal)
.width("270px")
.height("270px")
.backgroundColor(Color.Black)
.border({ color: Color.White, style: BorderStyle.Solid, width: 2 })
.fontSize(40)
.fontColor(Color.White)
.fontWeight(800)
.borderRadius(0)
}

image.gif

2. 设置运算符枚举类型 Operator

enum Operator {
  PLUS = '+',
  MINUS = '-',
  TIMES = '*',
  DIVIDE = '/'
}

image.gif

3. 设置获取运算符优先级的函数 getOperatorPrecedence

function getOperatorPrecedence(operator: string): number {
  switch (operator) {
    case Operator.PLUS:
    case Operator.MINUS:
      return 1;
    case Operator.TIMES:
    case Operator.DIVIDE:
      return 2;
    default:
      throw new Error("Invalid operator: " + operator);
  }
}

image.gif

4.设置计算表达式结果的函数 calculateResult

function calculateResult(expression: string): number {
  // 去除表达式两端可能存在的空白字符
  expression = expression.trim();
  // 使用两个栈,一个用于存储操作数,一个用于存储运算符
  let operandStack: number[] = [];
  let operatorStack: string[] = [];
  // 用于临时存储数字字符组成的字符串,以便转换为数字
  let tempNumber = "";
  for (let i = 0; i < expression.length; i++) {
    let char = expression[i];
    if (char >= '0' && char <= '9' || char === '.') {
      // 如果是数字字符或小数点,累加到临时数字字符串中
      tempNumber += char;
    } else if (char === '+' || char === '-' || char === '*' || char === '/') {
      // 如果是运算符
      // 先将之前临时存储的数字转换为实际数字并压入操作数栈
      if (tempNumber!== "") {
        operandStack.push(Number(tempNumber));
        tempNumber = "";
      }
      // 处理运算符栈,按照优先级进行运算
      while (
        operatorStack.length > 0 &&
          getOperatorPrecedence(operatorStack[operatorStack.length - 1]) >= getOperatorPrecedence(char)
      ) {
        let operator = operatorStack.pop();
        let operand2 = operandStack.pop();
        +
        let operand1 = operandStack.pop();
        // 验证弹出的操作数是否有效
        if (Operand1 === undefined || operand2 === undefined) {
          throw new Error("Invalid operation: missing operand(s)");
        }
        if (operator === Operator.PLUS) {
          operandStack.push(Operand1 + operand2);
        } else if (operator === Operator.MINUS) {
          operandStack.push(Operand1 - operand2);
        } else if (operator === Operator.TIMES) {
          operandStack.push(Operand1 * operand2);
        } else if (operator === Operator.DIVIDE) {
          operandStack.push(Operand1 / operand2);
        }
      }
      // 将当前运算符压入运算符栈
      operatorStack.push(char);
    } else if (char === '(') {
      // 如果是左括号,直接压入运算符栈
      operatorStack.push(char);
    } else if (char === ')') {
      // 如果是右括号
      // 先将之前临时存储的数字转换为实际数字并压入操作数栈
      if (tempNumber!== "") {
        operandStack.push(Number(tempNumber));
        tempNumber = "";
      }
      // 处理运算符栈,直到遇到左括号
      while (
        operatorStack.length > 0 &&
          operatorStack[operatorStack.length - 1]!== '(') {
        let operator = operatorStack.pop();
        let operand2 = operandStack.pop();
        let operand1 = operandStack.pop();
        // 验证弹出的操作数是否有效
        if (Operand1 === undefined || operand2 === undefined) {
          throw new Error("Invalid operation: missing operand(s)");
        }
        if (operator === Operator.PLUS) {
          operandStack.push(Operand1 + operand2);
        } else if (operator === Operator.MINUS) {
          operandStack.push(Operand1 - operand2);
        } else if (operator === Operator.TIMES) {
          operandWordStack.push(Operand1 * operand2);
        } else if (operator ==Operator.DIVIDE) {
          operandStack.push(Operand1 / operand2);
        }
      }
      // 弹出左括号
      operatorStack.pop();
    }
  }
  // 处理表达式末尾可能存在的数字
  if (tempNumber!== "") {
    operandStack.push(Number(tempNumber));
  }
  // 处理运算符栈中剩余的运算符
  if (operatorStack.length > 0) {
    let operator = operatorStack.pop();
    let operand2 = operandStack.pop();
    let operand1 = operandStack.pop();
    // 验证弹出的操作数是否有效
    if (Operand1 === undefined || operand2 === undefined) {
      throw new Error("Invalid operation: missing operand(s)");
    }
    if (operator === Operator.PLUS) {
        operandStack.push(Operand1 + operand2);
    } else if (operator === Operator.MINUS) {
        operandStack.push(Operand1 - operand2);
    } else if (operator === Operator.TIMES) {
        operandStack.push(Operand1 * operand2);
    } else if (operator ==Operator.DIVIDE) {
        operandStack.push(Operand1 / operand2);
    }
    }
    // 返回最终的计算结果
    return operandStack[0];
}

image.gif

5.设置主界面组件 Index

@Entry
@Component
struct Index {
  @State result: string = ""
  @State number: number = 0
  build() {
    Column() {
      Row() {
        Text(this.result).fontSize(50)
      }
      Row() {
        Column() {
          Button("7").onClick(() => {
            this.result += "7"
          }).myButton()
        }
        Column() {
          Button("8").onClick(() => {
            this.result += "8"
          }).myButton()
        }
        Column() {
          Button("9").onClick(() => {
            this.result += "9"
          }).myButton()
        }
        Column() {
          Button("+").onClick(() => {
            this.result += "+"
          }).myButton()
        }
      }
      Row() {
        Column() {
          Button("4").onClick(() => {
            this.result += "4"
          }).myButton()
        }
        Column() {
          Button("5").onClick(() => {
            this.result += "5"
          }).myButton()
        }
        Column() {
          Button("6").onClick(() => {
            this.result += "6"
          }).myButton()
        }
        Column() {
          Button("-").onClick(() => {
            this.result += "-"
          }).myButton()
        }
      }
      Row() {
        Column() {
          Button("1").onClick(() => {
            this.result += "1"
          }).myButton()
        }
        Column() {
          Button("2").onClick(() => {
            thisresult += "2"
          }).myButton()
        }
        Column() {
          Button("3").onClick(() => {
            this.result += "3"
          }).myButton()
        }
        Column() {
          Button("*").onClick(() => {
            this.result += "*"
          }).myButton()
        }
      }
      Row() {
        Column() {
          Button("0").onClick(() => {
            this.result += "0"
          }).myButton()
        }
        Column() {
          Button(".").onClick(() => {
            this.result += "."
          }).myButton()
        }
        Column() {
          Button("=").onClick(() => {
            try {
              this.result = calculateResult(this.result).toString();
            } catch (e) {
              this.result = "Error: " + e.message;
            }
          }).myButton()
        }
        Column() {
          Button("/").onClick(() => {
            this.result += "/"
          }).myButton()
        }
      }
      Row() {
        Column() {
          Button("C").onClick(() => {
            this.result = "";
            this.number = 0;
          }).myButton()
        }
      }
    }
  }
}

image.gif

6.模拟机运行测试  

image.gif image.gif image.gif

👋实验小结

       本次计算器应用开发实验主要围绕 index.ets 文件展开。利用按钮组件顺利完成布局设计,数字、运算符及功能按钮排列有序,操作逻辑清晰直观。点击事件处理精准,计算过程能实时且无误地呈现在 Text 组件,点击等号后计算函数高效解析表达式并给出准确结果,达成核心功能要求。然而,实验中也发现一些待改进之处,例如错误提示不够详尽,难以助力用户快速定位输入错误;界面美观性欠佳,颜色与样式缺乏精致感;响应式设计不足,在不同屏幕规格下适配性差。总体而言,本次实验已成功构建起基本功能框架,后续将针对上述问题深入探究优化方案,不断打磨细节,在完善计算器功能与提升用户体验的道路上持续精进,进而提升自身编程与应用开发的综合能力水平。

image.gif

目录
相关文章
|
15天前
|
数据安全/隐私保护
【HarmonyOS——ArkTS语言】面向对象【合集】
【ArkTS语言-HarmonyOS】面向对象【合集】本次实验,我们在utils目录中创建了MyClass.ets和MyConfig.ets文件,在此过程中定义了Config接口和Color枚举。同时,我们实现了Auth类及其子类WechatAuth和AlipayAuth,从而深入了解了面向对象编程在HarmonyOS开发中的应用。在实验中,我们学会了如何遵循接口规范来实现类的功能,并通过继承机制来扩展类的行为。通过这些实践,我们完成了用户创建、密码设置以及登录操作。
28 3
|
23天前
|
存储 人工智能 JavaScript
Harmony OS开发-ArkTS语言速成二
本文介绍了ArkTS基础语法,包括三种基本数据类型(string、number、boolean)和变量的使用。重点讲解了let、const和var的区别,涵盖作用域、变量提升、重新赋值及初始化等方面。期待与你共同进步!
88 47
Harmony OS开发-ArkTS语言速成二
|
16天前
|
UED 开发者
【HarmonyOS——ArkTS语言】计算器的实现【合集】
【ArkTS语言-HarmonyOS】计算器的实现【合集】组件,点击等号后计算函数高效解析表达式并给出准确结果,达成核心功能要求。错误提示不够详尽,难以助力用户快速定位输入错误;响应式设计不足,在不同屏幕规格下适配性差。总体而言,本次实验已成功构建起基本功能框架,后续将针对上述问题深入探究优化方案,不断打磨细节,在完善计算器功能与提升用户体验的道路上持续精进,进而提升自身编程与应用开发的综合能力水平。利用按钮组件顺利完成布局设计,数字、运算符及功能按钮排列有序,操作逻辑清晰直观。
35 8
|
15天前
|
存储 JSON 区块链
【HarmonyOS NEXT开发——ArkTS语言】购物商城的实现【合集】
HarmonyOS应用开发使用@Component装饰器将Home结构体标记为一个组件,意味着它可以在界面构建中被当作一个独立的UI单元来使用,并且按照其内部定义的build方法来渲染具体的界面内容。txt:string定义了一个名为Data的接口,用于规范表示产品数据的结构。src:类型为,推测是用于引用资源(可能是图片资源等)的一种特定类型,用于指定产品对应的图片资源。txt:字符串类型,用于存放产品的文字描述,比如产品名称等相关信息。price:数值类型,用于表示产品的价格信息。
37 5
|
15天前
|
开发工具 开发者 容器
【HarmonyOS NEXT开发——ArkTS语言】欢迎界面(启动加载页)的实现【合集】
从ArkTS代码架构层面而言,@Entry指明入口、@Component助力复用、@Preview便于预览,只是初窥门径,为开发流程带来些许便利。尤其动画回调与Blank组件,细节粗糙,后续定当潜心钻研,力求精进。”,字体颜色为白色,字体大小等设置与之前类似,不过动画配置有所不同,时长为。,不过这里没有看到额外的动画效果添加到这个特定的图片元素上(与前面带动画的元素对比而言)。这是一个显示文本的视图,文本内容为“奇怪的知识”,设置了字体颜色为灰色(的结构体,它代表了整个界面组件的逻辑和视图结构。
35 1
|
25天前
|
API 索引
鸿蒙开发:实现一个超简单的网格拖拽
实现拖拽,最重要的三个方法就是,打开编辑状态editMode,实现onItemDragStart和onItemDrop,设置拖拽移动动画和交换数据,如果想到开启补位动画,还需要实现supportAnimation方法。
76 13
鸿蒙开发:实现一个超简单的网格拖拽
|
24天前
|
索引 API
鸿蒙开发:自定义一个股票代码选择键盘
金融类的软件,特别是股票基金类的应用,在查找股票的时候,都会有一个区别于正常键盘的键盘,也就是股票代码键盘,和普通键盘的区别就是,除了常见的数字之外,也有一些常见的股票代码前缀按钮,方便在查找股票的时候,更加方便的进行检索。
鸿蒙开发:自定义一个股票代码选择键盘
|
24天前
|
API
鸿蒙开发:自定义一个英文键盘
实现方式呢,有很多种,目前采用了比较简单的一种,如果大家采用网格Grid组件实现方式,也是可以的,但是需要考虑每行的边距以及数据,还有最后两行的格子占位问题。
鸿蒙开发:自定义一个英文键盘
|
25天前
|
存储 JSON 数据库
鸿蒙元服务项目实战:备忘录内容编辑开发
富文本内容编辑我们直接使用RichEditor组件即可,最重要的就是参数,value: RichEditorOptions,通过它,我们可以用来设置样式,和获取最后的富文本内容,这一点是很重要的。
鸿蒙元服务项目实战:备忘录内容编辑开发
|
24天前
|
前端开发 API 数据库
鸿蒙开发:异步并发操作
在结合async/await进行使用的时候,有一点需要注意,await关键字必须结合async,这两个是搭配使用的,缺一不可,同步风格在使用的时候,如何获取到错误呢,毕竟没有catch方法,其实,我们可以自己创建try/catch来捕获异常。
鸿蒙开发:异步并发操作