Java语言GUI实现计算器以及源代码

一、 设计分析
1.1任务及其目的
设计一个计算器应用程序,完成复杂的科学运算。设计的计算器应用程序可以完成加法、减法、乘法、除法和科学函数运算。且有小数点、正负号、求倒数、退格和清零等功能。用鼠标点击相应的数字键和运算符号键,然后点击=按钮。窗口上方的文本框将会显示计算出来的结果,如果未显示说明输入的表达式有误。要将文本框清零,科单击清零按钮。
1.2设计思路
实现主要分为两部分:

  1. 编写能实现简单四则运算的类(BaseCalcucator.class)
    将传入的中缀表达式转化为逆波兰表达式,在进行计算。
  2. 编写进行科学计算的类(SceneCalculator.class)
    将传入的式子进行相应的科学计算,并用计算出来的结果进行替代掉进行科学计算的式子。
    二,程序结构
    1、程序流程如下图

    图2.1程序流程图
    2、程序界面

    图2.2程序界面图
    控件
    1.文本框TextArea:text用于显示当前计算的式子,recordArea用于显示过去计算的式子,mermoryArea用于显示计算器“寄存器”中的值。
    2.功能Button:record和mermor用于在历史记录和“寄存器”之间进行切换。
    3.数字Button:0-9.小数点
    4.运算符Button:+ - * / ( ) =
    5.计算器基本Button:←用于退格,c用于清空mathNow、recordArea、mermoryArea
    6.科学运算符Button::(15个)
    sin,cos,tan,ln,log,e,π,1/x, x2,x3, , x!,√, ,|x|,
    7.切换Button:Deg代表角度制,Rad代表弧度制。通过点击Deg实现角度制与弧度制之间的切换
    成员变量
    1.private String mathPast=” ”,用于存储上次运算的式子
    2.private String mathNow =” ”,用于存储现在运算的式子
    3.private String showNow=” ”,用于存储显示在文本框的式子
    4.private String m;用于存储使用计算器寄存器的数
    5.private String restult=””;用于计算出来的结果
    6.pivate String temp=””,用于暂时存储的数字
    7.private int TrigCalculMethod=0;(默认设置为0,进行角度制运算)
    TrigCalculMethod=0,进行角度制运算,TrigCalculMethod=1,进行弧度制运算
    8.private int equal_flag=0;进行等号按钮的标记(及刚刚是否进行了一次运算)
    equal_flag=0,及刚刚没有进行运算,equal_flag=1,代表刚刚进行了一次运算

三、 各模块的功能及程序说明
3.1 Calcuator主类模块
3.1.1 初始化特殊函数按钮
由于JButton 按钮上无法显示出x2,x3, , ,所以图片粘贴的办法,将相应的函数图片粘贴到按钮的表面。,

//创建x的平方,x的三次方,x的y次方,x开y次方按钮ImageIcon squareimg = new ImageIcon("src\\Calcuator\\x的平方.png");// 创建图片对象ImageIcon cubeimg = new ImageIcon("src\\Calcuator\\x的三次方.png");// 创建图片对象ImageIcon powerimg = new ImageIcon("src\\Calcuator\\x的y次方.png");// 创建图片对象ImageIcon readicationimg = new ImageIcon("src\\Calcuator\\x开y次方.png");// 创建图片对象Image squareimage = squareimg.getImage();Image cubeimage = cubeimg.getImage();Image powerimage = powerimg.getImage();Image readicationimage = readicationimg.getImage();//为把它缩小点,先要取出这个Icon的image ,然后缩放到合适的大小Image squaresmallImage = squareimage.getScaledInstance(25,25,Image.SCALE_FAST);Image cubesmallImage = cubeimage.getScaledInstance(25,25,Image.SCALE_FAST);Image powersmallImage = powerimage.getScaledInstance(25,25,Image.SCALE_FAST);Image readictionsmallImage = readicationimage.getScaledInstance(30,30,Image.SCALE_FAST);//再由修改后的Image来生成合适的Icon;//***Image对象创建ImageIcon对象,可查阅ImageIcon的构造方法***ImageIcon smallIcon  = new ImageIcon(squaresmallImage);ImageIcon cmallIcon = new ImageIcon(cubesmallImage);ImageIcon pmallIcon = new ImageIcon(powersmallImage);ImageIcon rmallIcon = new ImageIcon(readictionsmallImage);JButton squarebuttion=new JButton(smallIcon);JButton cubebuttion=new JButton(cmallIcon);JButton powerbuttion=new JButton(pmallIcon);JButton readictionbuttion=new JButton(rmallIcon);
  图3.1.1 特殊函数按钮初始化代码图

3.1.2 初始化计算器的界面

使用构造法,进行计算器开始界面的设计。

public Calcuator (){super("计算器");this.setBounds(400, 250, 900, 680);//设置窗体图片
//    this.setIconImage(walkpaperimage);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗体的布局形式
GridBagLayout gr=new GridBagLayout();
GridBagConstraints gc=new GridBagConstraints();//设置窗体布局this.setLayout(gr);//创建模板JPanel jp1 = createPanel1();JPanel jp2 = createPanel2();//对整个窗体进行网格包布局 jp1,jp4gc.weightx=90;gc.weighty=68;gc.fill=GridBagConstraints.BOTH;gc.gridwidth=7;gc.gridheight=10;gc.gridx=0;gc.gridy=0;gr.setConstraints(jp1,gc);this.add(jp1);gc.gridwidth=3;gc.gridheight=10;gc.gridx=7;gc.gridy=0;gr.setConstraints(jp2,gc);this.add(jp2);this.setVisible(true);}

图3.1.2构造计算器开始界面

设计思路:
1、 将计算器开始窗口划分为两个左右大面板。左边的面板放置用于显示的文本域和按钮,右边的面板用于放置历史记录按钮和内存按钮及其对应的文本域.。然后采用网格包布局管理器,进行分配比例和布局。
2、 (方法createPanel1())在左边的大面板中再创建两个面板。将文本域放置在一个面板,按钮也放置在单独的一个面板。然后采用边界布局,将文本域所在的面板放置大面板的North,按钮所在的面板放置在Center。在按钮所在的面板中采用网格布局放置每一个按钮,然后实例化监听类(ButtonAction)的对象(ba),并在每一个按钮上添加监听对象(ba)。
3、 (方法 createPanel2())在右边的大面板中同样创建两个面板。一个放置历史记录按钮和内存按钮,一个放置对应的文本域。也是采用边界布局,将按钮所在的面板置于North,将文本域的面板置于Center。放置文本域的面板再采用卡片布局,放置不同按钮对应的文本域。

3.1.3 监听类(ButtonAction)的设置
用Plantuml绘制监听类的原理如下:
代码与原理图有所出入,不过大致原理是一样的。
3.1.3 监听类原理图
设计思路
1、 将计算器所有按钮(除去Degr、历史记录、内存)的监听编写在一个类中。
2、 把计算器的按钮分为四个类型:常量型、运算符、函数型、功能。并设计对应的四个模块。点击按钮则运行对应模块。

3.2 ScienCalcuator类
把要进行计算的表达式转入到ScienCalcuator类,进行科学运算,并计算出来的结果替代相应的字符。最后得到没有科学运算符的字符串,再将其传入BaseCalcuator中。
3.2.1 对计算式进行预处理
去掉 math 中的空格,替换 π,替换自然指数 e
3.2.1 计算式的预处理
3.2.2 pow运算(”^”)
获取^左右两边的参数进行Math.pow计算,如果参数是表达式,需要调用fScienCalcuator方法,然后用结算结果替换科学运算式部分。
大致原理如下图:

String fPower(String con_str) {while (con_str.contains("^")) {//1.中间寻找的点int midIndex = con_str.lastIndexOf("^");//2.获取左边参数double leftNum; //左边的数String leftStr; //左边math字符串int leftIndex = midIndex - 1;if (con_str.charAt(leftIndex) == ')') {        //1.左边是一个表达式,即左边用括号括起来int i = leftIndex - 1;int LeftBrackSum=0;int RightBrackSum=1;while(LeftBrackSum!=RightBrackSum) {if(con_str.charAt(i)=='(')LeftBrackSum+=1;if(con_str.charAt(i)==')')RightBrackSum+=1;i--;}String subLeftMath = con_str.substring(i+2, leftIndex);if(subLeftMath.contains("sin")||subLeftMath.contains("^")||subLeftMath.contains("cos")||subLeftMath.contains("tan")||subLeftMath.contains("ln")||subLeftMath.contains("log")||subLeftMath.contains("!")||subLeftMath.contains("abs")) {String  subLeftMath1=subLeftMath;leftNum =Double.parseDouble(fScienceCalcuator(subLeftMath1));}elseleftNum =Double.parseDouble(fBaseCalcuator(subLeftMath));if (leftNum == Double.MAX_VALUE) //每次计算要判断是否出现 math errorreturn String.valueOf(Double.MAX_VALUE);leftStr = "(" + subLeftMath + ")";} else {                                    //2.左边是一个数//注意:判定index范围一定要在左边,否则可能出现IndexOutOfRange异常while (leftIndex >= 0 && !isOper(con_str.charAt(leftIndex))) {leftIndex--;}leftStr = con_str.substring(leftIndex + 1, midIndex);leftNum = Double.parseDouble(leftStr);}//3.获取右边参数double rightNum;String rightStr;int rightIndex = midIndex + 1;if (con_str.charAt(rightIndex) == '(') {int i = rightIndex + 1;int  LeftBrackSum=1;int  RightBrackSum=0;while (LeftBrackSum !=RightBrackSum) {if(con_str.charAt(i)=='(')LeftBrackSum+=1;if(con_str.charAt(i)==')')RightBrackSum+=1;i++;}String subRightMath = con_str.substring(rightIndex + 1, i-1);if(subRightMath.contains("sin")||subRightMath.contains("cos")||subRightMath.contains("^")||subRightMath.contains("tan")||subRightMath.contains("ln")||subRightMath.contains("log")||subRightMath.contains("!")||subRightMath.contains("abs")) {String subRightMath1=subRightMath;rightNum=Double.parseDouble(fScienceCalcuator(subRightMath1));}elserightNum=Double.parseDouble(fBaseCalcuator(subRightMath));if (rightNum == Double.MAX_VALUE)return String.valueOf(Double.MAX_VALUE);rightStr = "(" + subRightMath + ")";} else {while (rightIndex < con_str.length() && !isOper(con_str.charAt(rightIndex))) {rightIndex++;}rightStr = con_str.substring(midIndex + 1, rightIndex);rightNum = Double.parseDouble(rightStr);}//4.得到完整的运算式并运算和替换String wholeMath = leftStr + "^" + rightStr;double result = Math.pow(leftNum, rightNum);con_str = con_str.replace(wholeMath, String.valueOf(result));}return con_str;}

图3.2.2 pow运算代码实现
3.2.3 计算剩下的运算符
包括 sin, cos, tan, ln, log, !
通过获取括号位置,如sin(cos(50)),先获取cos(50)完成计算并进行对应位置的替代,在调用Math.sin计算,根据angle_metric的值选择DEG还是RAD.
下图是fTraingle函数的核心部分

 String fTraingle(String con_str) {while (con_str.contains("sin")|| con_str.contains("cos")|| con_str.contains("tan")|| con_str.contains("ln")|| con_str.contains("log")||con_str.contains("abs")) {String tempor = null;//用于暂时保留三角运算符int beginIndex =0;//保留运算符号后面括号的索引值String temp="";if(con_str.contains("sin")|| con_str.contains("cos")|| con_str.contains("tan")|| con_str.contains("ln")|| con_str.contains("log")||con_str.contains("abs")) {if(con_str.contains("sin")) {tempor="sin";beginIndex=con_str.lastIndexOf(tempor)+3;}elseif(con_str.contains("cos")) {tempor="cos";beginIndex=con_str.lastIndexOf(tempor)+3;}elseif(con_str.contains("tan")) {tempor="tan";beginIndex=con_str.lastIndexOf(tempor)+3;}elseif(con_str.contains("ln")) {tempor="ln";beginIndex=con_str.lastIndexOf(tempor)+2;if(beginIndex-2>0) {if (isNum(con_str.charAt(beginIndex - 3))||con_str.charAt(beginIndex-3)=='.') {int i = con_str.lastIndexOf(tempor) - 1;while ((isNum(con_str.charAt(i))||con_str.charAt(i)=='.')&&i!=0) {i--;}//进行字符串的赋值if (i>0)temp = con_str.substring(i + 1, con_str.lastIndexOf(tempor));elsetemp=con_str.substring(i,con_str.lastIndexOf(tempor));}if (con_str.charAt(beginIndex-3)==')'){int leftIndex=beginIndex-3;int i = leftIndex - 1;int LeftBrackSum=0;int RightBrackSum=1;while(LeftBrackSum!=RightBrackSum) {if(con_str.charAt(i)=='(')LeftBrackSum+=1;if(con_str.charAt(i)==')')RightBrackSum+=1;i--;}temp = con_str.substring(i+1, leftIndex+1);System.out.println(temp+"templn");}
                        else
//                            if (con_str.charAt(beginIndex-3)=='e'||con_str.charAt(beginIndex-3)=='π') {//                                temp = "";
//                                System.out.println("提前知道数");
//                            }}}elseif(con_str.contains("abs")) {tempor="abs";beginIndex=con_str.lastIndexOf(tempor)+3;}elseif(con_str.contains("log")) {tempor="log";beginIndex=con_str.lastIndexOf(tempor)+3;if(beginIndex-3>0) {if (isNum(con_str.charAt(beginIndex - 4))||con_str.charAt(beginIndex-4)=='.') {int i = con_str.lastIndexOf(tempor) - 1;while ((isNum(con_str.charAt(i))||con_str.charAt(i)=='.')&&i!=0) {i--;}//进行字符串的赋值if (i>0)temp = con_str.substring(i + 1, con_str.lastIndexOf(tempor));elsetemp=con_str.substring(i,con_str.lastIndexOf(tempor));}if (con_str.charAt(beginIndex-4)==')'){int leftIndex=beginIndex-4;int i = leftIndex - 1;int LeftBrackSum=0;int RightBrackSum=1;while(LeftBrackSum!=RightBrackSum) {if(con_str.charAt(i)=='(')LeftBrackSum+=1;if(con_str.charAt(i)==')')RightBrackSum+=1;i--;}temp = con_str.substring(i+1, leftIndex+1);
//                            System.out.println(temp+"templn");}}}}//1.获取()内运算式并计算出结果,此时假设()不再包含复杂的科学运算if (con_str.charAt(beginIndex) == '(') {int i = beginIndex + 1;int  LeftBrackSum=1;int  RightBrackSum=0;while (LeftBrackSum !=RightBrackSum) {if(con_str.charAt(i)=='(')LeftBrackSum+=1;if(con_str.charAt(i)==')')RightBrackSum+=1;i++;}//获取括号内得字符串String subMath = con_str.substring(beginIndex + 1, i-1);double subResult;if(subMath.contains("sin")||subMath.contains("cos")||subMath.contains("^")||subMath.contains("tan")||subMath.contains("ln")||subMath.contains("log")||subMath.contains("!")||subMath.contains("abs")) {String subRightMath1=subMath;subResult=Double.parseDouble(fScienceCalcuator(subRightMath1));}elsesubResult = Double.parseDouble(fBaseCalcuator(subMath));if (subResult == Double.MAX_VALUE) //每次计算要判断是否出现 math errorreturn String.valueOf(Double.MAX_VALUE);//           3.匹配scienceOper进行科学运算,并替换相应部分String tempMath;double tempResult = 0;int DEG = 0; //判断角度制switch (tempor) {case "sin":tempMath = "sin(" + subMath + ")";if (angle_metric == DEG) {tempResult = Math.sin(subResult / 180 * Math.PI); //将默认的 Rad → Deg} else {tempResult = Math.sin(subResult);}con_str = con_str.replace(tempMath, String.valueOf(tempResult));break;case "cos":tempMath = "cos(" + subMath + ")";if (angle_metric == DEG) {tempResult = Math.cos(subResult / 180 * Math.PI);} else {tempResult = Math.cos(subResult);}con_str= con_str.replace(tempMath, String.valueOf(tempResult));break;case "tan":tempMath = "tan(" + subMath + ")";if (angle_metric == DEG) {if(subResult==90)con_str="error";elsetempResult = Math.tan(subResult / 180 * Math.PI);} else {if(subResult==Math.PI/2)con_str="error";elsetempResult = Math.tan(subResult);}con_str = con_str.replace(tempMath, String.valueOf(tempResult));break;case "ln":tempMath =temp+ "ln(" + subMath + ")";if(!temp.equals("")) {temp=fScienceCalcuator(temp);subResult = Math.pow(subResult, Double.parseDouble(temp));
//                            System.out.println("temp="+temp);}tempResult = Math.log(subResult);con_str = con_str.replace(tempMath, String.valueOf(tempResult));break;case "log":tempMath = temp+"log(" + subMath + ")";if(!temp.equals("")){temp=fScienceCalcuator(temp);subResult=Math.pow(subResult, Double.parseDouble(temp));
//                        System.out.println("temp="+temp);}tempResult = Math.log10(subResult);con_str = con_str.replace(tempMath, String.valueOf(tempResult));break;case "abs":tempMath = "abs(" + subMath + ")";tempResult = Math.abs(subResult);con_str= con_str.replace(tempMath, String.valueOf(tempResult));break;default:break;}}
////}return con_str;}

图 3.2.3 fTraingle函数核心部分代码实现

3.3 BaseCalcuator类
把ScienCalcuator类,传入的式子,采用逆波兰表达式算法进行计算,最后得到结果。
关于逆波兰表达式算法介绍:
https://blog.csdn.net/qq_39662044/article/details/76595701
十分感谢这位博主,这篇博客给予我的很大帮助,谢谢您。
四、 程序测试
成功计算则会显示出结果,反之则表达式有误。

图4.1 成功计算
这只是个例子,可以实现很多正确表达式的计算。

图4.2 错误表达式的计算
五、设计心得
用 Java 做计算器,主要是处理 String 类型的 mathNow 表达式,灵活运用 String 的方法,通过截取原始的 mathNow 分治结果问题:先预处理 mathNow,去掉影响计算的空格等再替换 π,e再计算科学运算式,最后把 mathNow 替换成没有科学运算符的中缀表达式,再利用逆波兰运算的方法计算出最终结果
总的来说,此次设计我收获很多,基本上理解了编写一个 Java 应用的基本架构,先编写好接口,再设计界面,最后把响应事件与接口联系起来,做成一个体验很好的计算器。

源代码链接:https://download.csdn.net/download/qq_49207029/12599057

Java语言GUI实现计算器相关推荐

  1. java计算器用什么布局_求JAVA语言写的计算器的代码。用GridLayout布局。

    展开全部 package com.citi.Util; import java.awt.BorderLayout; import java.awt.GridLayout; import java.aw ...

  2. 【java毕业设计】基于java+swing+GUI的雷电游戏GUI设计与实现(毕业论文+程序源码)——雷电游戏

    基于java+swing+GUI的雷电游戏GUI设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+swing+GUI的雷电游戏GUI设计与实现,文章末尾附有本毕业设计的论文和源码下 ...

  3. java语言编写计算器_第二次作业利用java语言编写计算器进行四则运算

    随着第一次作业的完成,助教 牛老师又布置了第二次作业:用java语言编写一个程序然后进行四则运算用户用键盘输入一个字符来结束程序显示统计结果.一开始看到这个题目我也着实吓了一跳 因为不知道如何下手而且 ...

  4. java获取界面输入数字_通过JAVA设计 GUI 界面的计算器程序,用户可以通过鼠标依次输入参加计算的数值,进行加、减、乘、...

    通过JAVA设计 GUI 界面的计算器程序,用户可以通过鼠标依次输入参加计算的数值,进行加.减.乘. 2016-08-22 0 0 0 4.0 分 其他 1 积分下载 如何获取积分? 通过JAVA设计 ...

  5. 基于Java语言实现一元稀疏多项式计算器【100010608】

    1.实验内容 一元稀疏多项式计算器 使用语言:Java 语言 编译环境:openJDk-1.8 2.问题描述 设计一个简易的一元稀疏多项式计算器. 3.需求分析 经过分析,本系统需完成的主要功能如下: ...

  6. 简易计算器 java_用Java做一个简易计算器,要用到哪些知识?

    分析问题关键词:Java.计算器 深夜无聊,暂且一答. 计算器分两个步骤:计算 + 器 篇一 ·「器」 在编程中,我们可以把「器」理解为「GUI(图形界面)」,Java 语言描绘的图形界面有很多种类, ...

  7. 计算器java程序设计报告总体设计,java程序设计实验报告-计算器

    <java程序设计实验报告-计算器>由会员分享,可在线阅读,更多相关<java程序设计实验报告-计算器(18页珍藏版)>请在金锄头文库上搜索. 1. Java 程序设计实验报告 ...

  8. Java语言程序设计基础篇-第10版-第一部分-程序设计基础)

    Java程序语言设计(基础篇)-第10版 第一部分 程序设计基础 第1章 计算机.程序和Java概述 1.1 引言 程序设计就是创建(或者开发)软件,软件也称为程序. 简言之,软件包含了指令,告诉计算 ...

  9. Java语言与系统设计笔记(II:从多线程开发到网络编程)

    ch6.Java多线程开发 6.1 进程与线程的概念 进程(Process):操作系统中能够"同时"运行的多个应用程序(QQ.浏览器.Word.WPS). 线程(Thread):一 ...

最新文章

  1. [AlwaysOn Availability Groups]排查:Primary上的修改无法在Secondary体现
  2. Dynamic Rankings——带修改区间第k大
  3. 【CTF大赛】100步getshell之就差一步——The MOVAPS issue
  4. Java中的方法调用有多昂贵
  5. 随笔之:VC操作Word系列(四)
  6. 一段平平无奇的秋招经历
  7. bug5-tensorflow.python.framework.errors_impl.UnknownError: Failed to get convolution algorithm
  8. mysql 主从延迟
  9. 一款免费在线文字识别(OCR)工具
  10. repost 从APP工厂到游戏工厂?字节跳动进攻腾讯腹地
  11. javacpp-opencv图像处理系列:国内车辆牌照检测识别系统(万份测试车牌识别准确率99.7%以上,单次平均耗时39ms)...
  12. 恶意软件Emotet卷土重来滥用.LNK文件进行攻击,你只需要一项技术就能有效保护组织
  13. 单链表的定义、特点、结构及其一些基本操作
  14. Vue+el-tree,元素拖拽时出现禁用图标, 请看解决办法
  15. python放大代码放大_Python中的放大缩小功能
  16. FHQ-Treap 简介
  17. CNN反向传播源码实现——CNN数学推导及源码实现系列(4)
  18. 开启编程世界的临门一脚
  19. 技术支持岗位面试问题汇总,绝对有你遇到的面试题!!
  20. 机器人主板需求配置参数有哪些呢?

热门文章

  1. css3魔方3乘3每层旋转_学习做旋转魔方 (css3)
  2. linux 命令 ls
  3. WebStorm+Vue-cli 配置alias 点击跳转无效问题
  4. 海思AI芯片(Hi3519A/3559A)方案学习一Ubuntu18.0.4上编译Hi3519AV100 uboot和kernel
  5. 微信小程序中使用Echarts(折线图)
  6. fluent转载内容
  7. PostgreSQL密码重置方法
  8. api有哪些 javasocket_Java原生Socket API
  9. 笔记本光驱在计算机里不显示器,电脑开机硬盘灯一直亮不闪的 光驱没反应显示器不显示 风扇都转的...
  10. echarts中国地图边缘设置阴影投影效果,并添加散点,大小根据数值改变