0


使用ArkTs进行计算器的实现

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

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
  2. @Component
  3. struct calcultorDemo {
  4. @State value:string =''
  5. @State result:string=''
  6. @State opacityValue:number=0
  7. @State fontSizeValue:number=30
  8. numbers :string[]=['(',')','÷','×','1','2','3','-','4','5','6','+','7','8','9']
  9. numbers2:string[]=['%','0','.']
  10. build() {
  11. Column(){
  12. Column(){
  13. TextInput({text:this.value})
  14. .height(80)
  15. .margin({top:60})
  16. .placeholderFont({size:60})
  17. .fontSize(60)
  18. .fontWeight(450)
  19. .textAlign(TextAlign.End)
  20. .backgroundColor(Color.White)
  21. Text(this.result)
  22. .opacity(this.opacityValue)
  23. .width('100%')
  24. .height(60)
  25. .fontSize(this.fontSizeValue)
  26. .fontWeight(450)
  27. .textAlign(TextAlign.End)
  28. .animation({duration:500})
  29. // @ts-ignore
  30. .textOverflow(TextOverflow.Clip)
  31. }
  32. Column(){//计算机主体页面
  33. Grid(){
  34. GridItem(){
  35. Text('MC')
  36. .TextStyle()
  37. }
  38. .oneStyle()//MC(清零)工具
  39. GridItem(){
  40. Text('MR')
  41. .TextStyle()
  42. }
  43. .oneStyle()
  44. GridItem(){
  45. Image($r('app.media.delete'))
  46. .fillColor(Color.Blue)
  47. .height(40)
  48. }
  49. .oneStyle()
  50. .onClick(()=>{
  51. this.value=this.value.slice(0,this.value.length-1)
  52. this.result=''
  53. })
  54. GridItem(){
  55. Text('C')
  56. .TextStyle()
  57. }
  58. .oneStyle()
  59. .onClick(()=>{
  60. this.value=''
  61. this.result=''
  62. })
  63. ForEach(this.numbers,item=>{
  64. GridItem(){
  65. Text(item)
  66. .TextStyle()
  67. }
  68. .onClick(()=>{
  69. if (this.value === '' && (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%')) {
  70. return
  71. }//判断点击的第一个字符是不是运算符,若是则返回
  72. if (this.value[this.value.length - 1] === '+' || this.value[this.value.length - 1] === '-' ||
  73. this.value[this.value.length - 1] === '×' || this.value[this.value.length - 1] === '÷' ||
  74. this.value[this.value.length - 1] === '%') {
  75. // 如果当前点击的是运算符,则替换最后一个运算符
  76. if (item === '+' || item === '-' || item === '×' || item === '÷' || item === '%') {
  77. this.value = this.value.slice(0, this.value.length - 1) + item
  78. } else {
  79. this.value += item
  80. }
  81. } else {
  82. this.value = this.value.concat(item)
  83. }
  84. })
  85. .oneStyle()
  86. })
  87. GridItem(){
  88. Text('=')
  89. .TextStyle()
  90. .fontColor(Color.White)
  91. }
  92. .rowStart(5)
  93. .rowEnd(6)
  94. .borderRadius(40)
  95. .backgroundColor(Color.Blue)
  96. .onClick(()=>{
  97. this.result=total(checkParentheses(this.value+'#').cleanedExpression)
  98. this.opacityValue=1
  99. this.fontSizeValue=50
  100. })
  101. ForEach(this.numbers2,item=>{
  102. GridItem(){
  103. Text(item)
  104. .TextStyle()
  105. }
  106. .onClick(()=>{this.value=this.value.concat(item)})
  107. .oneStyle()
  108. })
  109. }
  110. .width('100%')
  111. .height(500)
  112. .columnsTemplate('1fr 1fr 1fr 1fr')
  113. .rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr')
  114. .columnsGap(8)
  115. .rowsGap(12)
  116. .padding(12)
  117. .backgroundColor('#fff6f0f0')
  118. .borderRadius({topLeft:20,topRight:20})
  119. }
  120. .layoutWeight(1)
  121. .justifyContent(FlexAlign.End)
  122. }
  123. .height('100%')
  124. }
  125. }
  126. @Styles function oneStyle(){
  127. .backgroundColor(Color.White)
  128. .height(70)
  129. .width(70)
  130. .borderRadius(40)
  131. .shadow({color:Color.Gray,radius:5})
  132. }
  133. @Extend(Text) function TextStyle() {
  134. .fontSize(25)
  135. .fontWeight(400)
  136. }
  137. //运算符栈
  138. class CharacterStack{
  139. private characters:string[]
  140. constructor() {
  141. this.characters=[]
  142. }
  143. //入栈
  144. push(item:string){
  145. this.characters.push(item)
  146. }
  147. //出栈
  148. pop(){
  149. return this.characters.pop()
  150. }
  151. //返回栈顶元素
  152. peek(){
  153. return this.characters[this.characters.length-1]
  154. }
  155. //判断栈是否为空
  156. isEmpty(){
  157. return this.characters.length===0
  158. }
  159. //清空栈内元素
  160. clear(){
  161. this.characters=[]
  162. }
  163. //获取栈内元素数量
  164. size():number{
  165. return this.characters.length
  166. }
  167. }
  168. const characterstack =new CharacterStack()
  169. //数字栈
  170. export class NumberStack{
  171. private numbers:string[]
  172. constructor() {
  173. this.numbers=[]
  174. }
  175. //入栈
  176. push(item:string){
  177. this.numbers.push(item)
  178. }
  179. //出栈
  180. pop(){
  181. return this.numbers.pop()
  182. }
  183. //返回栈顶元素
  184. peek(){
  185. return this.numbers[this.numbers.length-1]
  186. }
  187. //判断栈是否为空
  188. isEmpty(){
  189. return this.numbers.length===0
  190. }
  191. //清空栈内元素
  192. clear(){
  193. this.numbers=[]
  194. }
  195. //获取栈内元素数量
  196. size():number{
  197. return this.numbers.length
  198. }
  199. }
  200. const numberstack =new NumberStack()
  201. //检查括号是否多余,且若前括号多余则去掉多余的前括号
  202. function checkParentheses(expression: string): { valid: boolean, cleanedExpression: string } {
  203. let stack = []
  204. let cleanedExpression = expression
  205. for (let ch of expression) {
  206. if (ch === '(') {
  207. stack.push(ch)
  208. } else if (ch === ')') {
  209. if (stack.length === 0) {
  210. return { valid: false, cleanedExpression: expression }
  211. }
  212. stack.pop()
  213. }
  214. }
  215. // 去掉多余的前括号
  216. while (stack.length > 0) {
  217. let index = cleanedExpression.indexOf('(')
  218. if (index !== -1) {
  219. cleanedExpression = cleanedExpression.slice(0, index) + cleanedExpression.slice(index + 1)
  220. }
  221. stack.pop()
  222. }
  223. console.log(cleanedExpression)
  224. return { valid: stack.length === 0, cleanedExpression }
  225. }
  226. function total(expression:string){
  227. characterstack.push('#')
  228. let i=0
  229. let ch=expression[i]
  230. while (ch!='#'||characterstack.peek()!='#') {
  231. if(!Instring(ch)){//进行多位数的入栈
  232. let numStr = ch
  233. while (i + 1 < expression.length && !Instring(expression[i + 1])) {
  234. ch = expression[++i]
  235. numStr += ch
  236. }
  237. numberstack.push(numStr)
  238. ch = expression[++i]
  239. }
  240. else{
  241. switch (Precede(characterstack.peek(),ch)){
  242. case '<':{
  243. characterstack.push(ch);
  244. ch=expression[++i]
  245. break
  246. }
  247. case '>':{
  248. let theta= characterstack.pop()
  249. let b=numberstack.pop()
  250. let a=numberstack.pop()
  251. numberstack.push(Operate(a,theta,b))
  252. break
  253. }
  254. case '=':{
  255. characterstack.pop()
  256. ch=expression[++i]
  257. break
  258. }
  259. }
  260. }
  261. }
  262. return numberstack.peek()
  263. }
  264. //判断ch是否为运算符
  265. function Instring(ch:string){
  266. let num:string[]=['+','-','(',')','÷','×','#','%']
  267. return num.includes(ch)
  268. }
  269. //判断运算符的优先级
  270. function Precede(thetal:string,thetal2:string):string{
  271. if((thetal=='('&&thetal2==')')||(thetal=='#'&&thetal2=='#')){
  272. return '='
  273. }
  274. else if(thetal=='('||thetal=='#'||thetal2=='('||(thetal=='+'||thetal=='-')&&(thetal2=='×'||thetal2=='÷'||thetal2=='%')){
  275. return '<'
  276. }
  277. else return '>'
  278. }
  279. //计算两数的运算结果
  280. function Operate(first:string,theta:string,second:string):string{
  281. switch (theta){
  282. case '+':
  283. return ((+first)+(+second)).toString()
  284. case '-':
  285. return ((+first)-(+second)).toString()
  286. case '×':
  287. return ((+first)*(+second)).toString()
  288. case '÷':
  289. return ((+first)/(+second)).toString()
  290. case '%':
  291. return ((+first)%(+second)).toString()
  292. }
  293. return 'NaN'
  294. }
标签: 前端 harmonyos 华为

本文转载自: https://blog.csdn.net/weixin_74943910/article/details/140805647
版权归原作者 了了一。 所有, 如有侵权,请联系我们删除。

“使用ArkTs进行计算器的实现”的评论:

还没有评论