【Java】Java使用Swing实现一个模拟计算器(有源码)

  📝个人主页:哈__

期待您的关注 

今天翻了翻之前写的代码,发现自己之前还写了一个计算器,今天把我之前写的代码分享出来。

 我记得那会儿刚学不会写,写的乱七八糟,但拿来当期末作业还是不错的哈哈。

直接上源码,后上讲解。

一、源码

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.text.DecimalFormat;
import java.util.function.ToDoubleBiFunction;

public class MyCalculator  {
    private JFrame frame=new JFrame("CSDN--哈__");
    private String[] keys = {"%","C","CE","Back","1⁄x","X²","√x","÷","7","8","9",
            "X","4","5","6","-","1","2","3","+","+/-","0",".","="};//计算器的功能键保存
    private JButton [] buttons=new JButton[keys.length];//创建按钮
    private JTextField resultText=new JTextField("0");//结果保存用于在计算器上显示
    private double resultNum =0.0000;//用于保存运算的结果

    private boolean firstDigit=true;//判断是否是第一个输入的数字,或者是运算符后第一个数字
    private String operate ="=";//记录当前的运算符
    private boolean opearteValidFlag =true;//判断当前输入是否合法



    //构造函数
    public MyCalculator(){
        frame.setLocation(300,200);
        frame.setSize(new Dimension(366,439));
        frame.setVisible(true);
        frame.setResizable(true);//窗口大小可修改
        //这里采用awt组件来关闭窗口  事件监听
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    public void init(){
        //先定义三种颜色 用于背景板的填充  数值为网上查找
        Color c1=new Color(181,181,181);
        Color c2=new Color(126,192,238);
        Color c3=new Color(232,232,232);
        //计算器功能面板初始化
        JPanel pText =new JPanel();//用于保存文本域
        JPanel pKey =new JPanel();//用于保存功能按键
        //对文本域进行初始化
        pText.setLayout(new BorderLayout());
        pText.add(resultText);
        resultText.setFont(new Font("楷体",Font.BOLD,43));//设置文本框中字体的格式
        resultText.setHorizontalAlignment(JTextField.RIGHT);//文本框默认右对齐
        resultText.setEditable(false);//文本域不可编辑
        resultText.setBorder(null);//设置边框为无
        resultText.setBackground(c1);
        //对功能案件进行初始化
        pKey.setLayout(new GridLayout(6,4,2,2)); //六行四列,相邻两个按钮上下间隔均为两个像素
        //开始在按键区加入前八个功能键
        for (int i = 0; i < 8; i++) {
            buttons[i]=new JButton(keys[i]);
            pKey.add(buttons[i]);
            buttons[i].setBackground(c3);
            buttons[i].setForeground(Color.BLACK);
            buttons[i].setFont(new Font(Font.SERIF,Font.PLAIN,18));
            buttons[i].setBorderPainted(false);//设置无边框
            buttons[i].addActionListener(myActionListener);//添加监听器
        }
        for (int i = 8; i < keys.length; i++) {
            buttons[i]=new JButton(keys[i]);
            pKey.add(buttons[i]);
            if((i+1)%4==0)  buttons[i].setBackground(c3);
            else buttons[i].setBackground(Color.white);
            buttons[i].setForeground(Color.BLACK);
            buttons[i].setFont(new Font(Font.SERIF,Font.PLAIN,18));
            buttons[i].setBorderPainted(false);//设置无边框
            buttons[i].addActionListener(myActionListener);//添加监听器
        }
        //最后将=号的背景色改为蓝色,也就是c2
        buttons[keys.length-1].setBackground(c2);
        pKey.setBackground(c1);

        frame.add(pText,BorderLayout.NORTH);
        frame.add(pKey);
       /* pText.setBorder(BorderFactory.createMatteBorder(25,3,1,3,c1));
        pKey.setBorder(BorderFactory.createMatteBorder(6,3,3,3,c1));*/
    }
    public class MyActionListener implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            String key = e.getActionCommand();
            //对于具有清除删除功能按键的处理(CE C BACK)
            if(key.equals(keys[1])||key.equals(keys[2])||key.equals(keys[3])){
                doDeleteKey(key);
            }
            //对只需要一个数值的按键处理(% 1/x x² √x  +/-  )
            else if(key.equals(keys[0])||key.equals(keys[4])||key.equals(keys[5])||key.equals(keys[6])||
                    key.equals(keys[20])){
                doOperator1(key);

            }
            //对需要两个数值的按键的处理(÷ X - += )
            else if(key.equals(keys[7])||key.equals(keys[11])||key.equals(keys[15])||key.equals(keys[19])||
                    key.equals(keys[23])){
                doOperator2(key);
            }
            //对数字按键进行处理(1 2 3 4 5 6 7 8 9 .)
            else{
                doNumberKey(key);
            }
        }
    }
    private void doDeleteKey(String key){
        if(key.equals("CE")){
            resultText.setText("0");
        }
        else if(key.equals("C")){
            resultText.setText("0");
            resultNum=0.0000;
            firstDigit=true;
            opearteValidFlag=true;
            operate="=";
        }
        else{
            String text=resultText.getText();
            if(text.length()>1){
                resultText.setText(text.substring(0,text.length()-1)); //如果内容长度大于1,那么直接删掉最后一个字符
            }else{
                //内容长度等于1
                resultText.setText("0");
                firstDigit=true;
            }
        }
    }
    private void doOperator1(String key){
        //对只需要一个数值的按键处理(% 1/x x² √x  +/-  )
        operate=key;
        if(operate.equals("%")){
            resultNum=getNumFromText()/100;
        }
        else if(operate.equals("1⁄x")){
            if(getNumFromText()==0){
                //System.out.println("0没有倒数!");
                resultText.setText("零没有倒数!");
                opearteValidFlag=false;
            }else{
                resultNum=resultNum+1.0/getNumFromText();
            }
        }
        else if(operate.equals("√x")){
            if(getNumFromText()<0){
                //System.out.println("负数不能开方!");
                resultText.setText("负数不能开方!");
                opearteValidFlag=false;
            }else{
                resultNum=resultNum+Math.sqrt(getNumFromText());
            }
        }
        else if(operate.equals("X²")){

            resultNum=resultNum+getNumFromText()*getNumFromText();
        }
        else if(key.equals("+/-")){
            resultNum=-getNumFromText();
            firstDigit=true;
            opearteValidFlag=true;
        }
    }
    //两个数进行运算 ÷ X - + =
    private void doOperator2(String key){
        if(operate.equals("÷")){
            if(getNumFromText()==0){
                //System.out.println("零不能做除数!");
                resultText.setText("零不能做除数!");
                opearteValidFlag=false;
            }else{
                resultNum/=getNumFromText();
            }
        }
        else if(operate.equals("X")){
            resultNum*=getNumFromText();
        }
        else if(operate.equals("+")){
            resultNum+=getNumFromText();
        }
        else if(operate.equals("-")){
            resultNum-=getNumFromText();
        }
        else if(operate.equals("=")){
            resultNum=getNumFromText();
        }
        if(opearteValidFlag){
            long t1=(long)resultNum;
            double t2=resultNum-t1;
            if(t2==0){
                resultText.setText(String.valueOf(t1));
            }else{
                resultText.setText(String.valueOf(new DecimalFormat("0.0000").format(resultNum)));
            }
        }
        operate=key;
        firstDigit=true;
        opearteValidFlag=true;

    }
     private void doNumberKey(String key){
        //如果是第一个输入的数字或者符号后第一个数字
        if(firstDigit){
            if(key.equals(".")) /*resultText.setText(resultText.getText()+".");*/{
                //上来直接按.  
                if(resultNum==0&&operate=="=") resultText.setText(resultText.getText()+".");
                //上来先按了个别的运算符 在按.
                else{
                    resultText.setText("0.");
                   // resultText.setText("出错!");
                    //opearteValidFlag=false;
                }
            }
            else resultText.setText(key);
        }else if(key.equals(".")&&resultText.getText().indexOf(".")<0){
            resultText.setText(resultText.getText()+".");
        }else if(!key.equals(".")){
            resultText.setText(resultText.getText()+key);
        }
        firstDigit=false;
    }
   private double getNumFromText(){
       double result = 0;
       try {
           result = Double.valueOf(resultText.getText()).doubleValue();
       } catch (NumberFormatException e) {
       }
       return result;

    }
    MyActionListener myActionListener=new MyActionListener();
    public static void main(String[] args) {
        new MyCalculator().init();
    }
}

二、讲解

1、创建我们所需的变量

计算器上的按键不少,我们都定义在一个keys数组当中,并且初始化一个buttons按钮数组。

除了我们的按钮之外,还有我们的输出显示窗口resultText,输出的结果我们都用resultNum来记录,之后在放到我们的输出窗口上。

其他的都写成注解了。

private JFrame frame=new JFrame("CSDN--哈__");
    private String[] keys = {"%","C","CE","Back","1⁄x","X²","√x","÷","7","8","9",
            "X","4","5","6","-","1","2","3","+","+/-","0",".","="};//计算器的功能键保存
    private JButton [] buttons=new JButton[keys.length];//创建按钮
    private JTextField resultText=new JTextField("0");//结果保存用于在计算器上显示
    private double resultNum =0.0000;//用于保存运算的结果

    private boolean firstDigit=true;//判断是否是第一个输入的数字,或者是运算符后第一个数字
    private String operate ="=";//记录当前的运算符
    private boolean opearteValidFlag =true;//判断当前输入是否合法

2.面板初始化

面板初始化就是init方法,注释我都写了,这里不在讲了,也没啥重要的,就是美化一下面板。

3.添加按钮事件监听机制

当我们点击计算机上的按钮的时候,计算器要给出反馈,这时就需要我们添加一个事件监听机制了。注释写好了,当我们点击不同的按钮的时候要处理不同的功能。

 public class MyActionListener implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            String key = e.getActionCommand();
            //对于具有清除删除功能按键的处理(CE C BACK)
            if(key.equals(keys[1])||key.equals(keys[2])||key.equals(keys[3])){
                doDeleteKey(key);
            }
            //对只需要一个数值的按键处理(% 1/x x² √x  +/-  )
            else if(key.equals(keys[0])||key.equals(keys[4])||key.equals(keys[5])||key.equals(keys[6])||
                    key.equals(keys[20])){
                doOperator1(key);

            }
            //对需要两个数值的按键的处理(÷ X - += )
            else if(key.equals(keys[7])||key.equals(keys[11])||key.equals(keys[15])||key.equals(keys[19])||
                    key.equals(keys[23])){
                doOperator2(key);
            }
            //对数字按键进行处理(1 2 3 4 5 6 7 8 9 .)
            else{
                doNumberKey(key);
            }
        }
    }

4.处理对于具有清除删除功能按键的处理(CE C BACK)

计算器上有个清空按键C大家都用过吧,点了这个C之后我们所有的输入都会被初始化。倘若点了退格键那我们就把面板上的文字域删掉一个符号。比如我们输入的是111,点了退格之后就是11,当然你会想这只是文字域的变化,那我们保存的要计算的值为什么不变?别着急,真正开始计算是在我们点击了加减乘除这一类的符号的时候才会从面板读取值的。

 private void doDeleteKey(String key){
        if(key.equals("CE")){
            resultText.setText("0");
        }
        else if(key.equals("C")){
            resultText.setText("0");
            resultNum=0.0000;
            firstDigit=true;
            opearteValidFlag=true;
            operate="=";
        }
        else{
            String text=resultText.getText();
            if(text.length()>1){
                resultText.setText(text.substring(0,text.length()-1)); //如果内容长度大于1,那么直接删掉最后一个字符
            }else{
                //内容长度等于1
                resultText.setText("0");
                firstDigit=true;
            }
        }
    }

5.两个数进行运算加减乘除

上来先判断你当前的的符号是什么,并且也进行了一些错误情况的判断,如除数不能为0什么的。

下边你就能看到我们的resultNum被使用了。最后来个操作是否合法判断,如果合法并且输出结果最后是0那我们直接就把0输出到面板上,但是倘若我们的输出结果有精度差,那我们就得自己将0放到面板上了。

注:我使用的浮点数计算并不是BigDecimal,所以存在精度差。

private void doOperator2(String key){
        if(operate.equals("÷")){
            if(getNumFromText()==0){
                //System.out.println("零不能做除数!");
                resultText.setText("零不能做除数!");
                opearteValidFlag=false;
            }else{
                resultNum/=getNumFromText();
            }
        }
        else if(operate.equals("X")){
            resultNum*=getNumFromText();
        }
        else if(operate.equals("+")){
            resultNum+=getNumFromText();
        }
        else if(operate.equals("-")){
            resultNum-=getNumFromText();
        }
        else if(operate.equals("=")){
            resultNum=getNumFromText();
        }
        if(opearteValidFlag){
            long t1=(long)resultNum;
            double t2=resultNum-t1;
            if(t2==0){
                resultText.setText(String.valueOf(t1));
            }else{
                resultText.setText(String.valueOf(new DecimalFormat("0.0000").format(resultNum)));
            }
        }
        operate=key;
        firstDigit=true;
        opearteValidFlag=true;

    }

 剩下的大家自己研究吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/533814.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

坚持十天做完Python入门编程100题第三天加班

坚持十天做完Python入门编程100题第三天加班 第24题 扫描文件列表第25题 如何将字典转换成JSON并写入json文件&#xff1f;第26题 JSON转换成字典 第24题 扫描文件列表 如何扫描当前目录下的文件列表&#xff1f;解析&#xff1a;可以使用python内置的glob模块&#xff0c;用法…

MySQL高级(索引分类-聚集索引-二级索引)

目录 1、主键索引、唯一索引、常规索引、全文索引 2、 聚集索引、二级索引 3、回表查询 4、通过id查询和通过name查询那个执行效率高&#xff1f; 5、 InnoDB主键索引的 B tree 高度为多高呢&#xff1f; 1、主键索引、唯一索引、常规索引、全文索引 在MySQL数据库&#xff0c…

三维GIS平台标绘功能新玩法,不仅可以绘制点线面,还可以生成单体化

地图标绘是指在地图背景上标绘各种具有空间特征的事、物的分布状态或行动部署。标绘功能能够表达各种信息&#xff0c;描述各种对象&#xff0c;表示各种资源&#xff0c;可用于规划设计、电力、通信和应急等行业。 标绘技术是三维GIS的一个重要技术手段&#xff0c;在几何表达…

HelpLook 比 BookStack 胜在哪里

不可置否&#xff0c;现如今信息管理和知识分享平台已经成为我们工作和学习中必不可少的工具。在众多平台中&#xff0c;HelpLook和BookStack都是备受欢迎的选择。然而&#xff0c;当我们将两者放在一起比较时&#xff0c;会发现HelpLook在多个方面相较于BookStack有着显著的优…

Django之rest_framework(二)

格式后缀 为了使我们的响应不再硬连接到单个内容类型这一事实,我们可以将API格式后缀添加到API之后。使用格式后缀为我们提供了明确引用给定格式的URL,譬如:http://example.com/api/items/4.json 官网:2 - Requests and responses - Django REST framework views:在函数…

STC89C52学习笔记(八)

STC89C52学习笔记&#xff08;八&#xff09; 综述&#xff1a;本文讲述了LED点阵屏、如何进行数据串行输入&#xff0c;并行输出以及LED点阵屏显示一列多列图形。 一、LED点阵屏 1.介绍 LED点阵屏由多个LED组成&#xff0c;以矩阵形式排列&#xff08;类似于矩阵键盘&…

配置及第三方授权申请教程

项目需要配置的地方不多&#xff0c;主要就两个地方需要注意&#xff1a;邮箱授权和第三方授权需要提前申请 1.基本设置 1.1 打开application.yml&#xff0c;修改数据库ip等基本信息 这些基本的配置就不多说了&#xff0c;基本就是改下服务器ip和账号密码什么的 1.2 获取QQ…

软件详细设计说明书(套用案例)

2系统总体设计 2.1整体架构 2.2整体功能架构 2.3整体技术架构 2.4设计目标 2.5.1总体原则 2.5.2实用性和先进性 2.5.3标准化、开放性、兼容性 2.5.4高可靠性、稳定性 2.5.5易用性 2.5.6灵活性和可扩展性 2.5.7经济性和投资保护 3系统功能模块详细设计 3.1个人办公…

【c++】string类常见接口函数

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好啊&#xff0c;本节我们来到STL内容的第一部分&#xff1a;string类接口函数的介绍 目录 1.string类的认识2.常见接口讲解2.1 string类对象的常见构造2.2 对string对象的遍历和…

【问题】解决1130-Host‘ ‘is not allowed to connect to this MySQL 本地无法连接服务器的数据库

【问题】解决1130-Host‘ ‘is not allowed to connect to this MySQL 本地无法连接服务器的数据库 原因: 默认mysql只允许 localhost 本地访问数据库, 解决方法 将 localhost 改为 % 所有 第一步 回车 输入密码 mysql -u root -p 第二步 切换数据库 use mysql 第三步 更新所…

Vue通过自定义指令实现元素平滑上升的动画效果(可以自定义动画时间、动画效果、动画速度等等)。

1、演示 2、介绍 这个指令不是原生自带的&#xff0c;需要手动去书写&#xff0c;但是这辈子只需要编写这一次就好了&#xff0c;后边可以反复利用。 3、关键API IntersectionObserver IntersectionObserver 是一个用于监测元素是否进入或离开视口&#xff08;viewport&#x…

【无人机/平衡车/机器人】详解STM32+MPU6050姿态解算—卡尔曼滤波+四元数法+互补滤波——附3个算法源码

效果&#xff1a; MPU6050姿态解算-卡尔曼滤波四元数互补滤波 目录 基础知识详解 欧拉角 加速度计(Accelerometer)与姿态测量 陀螺仪(Gyroscope)与姿态测量 姿态解算算法1-互补滤波 姿态解算算法2-四元数法 姿态解算算法3-卡尔曼滤波 组成 1.预测状态方程 2. 预测协方…

[C++]map set

一、set 1、概念 set是按照一定次序存储元素的容器在set中&#xff0c;元素的value也标识它(value就是key&#xff0c;类型为T)&#xff0c;并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const)&#xff0c;但是可以从容器中插入或删除它们。在内部&…

C:数据结构之链栈(不带头)

目录 前序 准备工作 函数声明 函数接口 1.初始化 2.创造节点 3. 判断栈空 4.入栈 5.出栈 6.取栈顶元素 7.销毁栈 8. 获取栈的元素个数 总结 前序 链栈是基于单链表实现的,其实栈更加适合使用顺序表来实现的,这篇文章我们来探讨一下链栈的实现。 准备工作 老规…

Python | Leetcode Python题解之第22题括号生成

题目&#xff1a; 题解&#xff1a; class Solution:def generateParenthesis(self, n: int) -> List[str]:if n 0:return []total_l []total_l.append([None]) # 0组括号时记为Nonetotal_l.append(["()"]) # 1组括号只有一种情况for i in range(2,n1): …

SpringBoot和Vue2项目配置https协议

1、SpringBoot项目 ① 去你自己的云申请并下载好相关文件&#xff0c;SpringBoot下载的是Tomcat&#xff08;默认&#xff09;&#xff0c;Vue2下载的是Nginx ② 将下载的压缩包里面的.pfx后缀文件拷贝到项目的resources目录下 ③ 编辑配置文件 &#xff08;主要是框里面的内…

【GN】《Group Normalization》

ECCV-2018 Facebook AI Research 更多论文解读&#xff0c;可参考【Paper Reading】 文章目录 1 Background and Motivation2 Related Work3 Advantages / Contributions4 Method5 Experiments5.1 Datasets and Metrics5.2 Image Classification in ImageNet5.3 Object Detecti…

小程序打开空白的问题处理

小程序打开是空白的&#xff0c;如下&#xff1a; 这个问题都是请求域名的问题&#xff1a; 一、检查服务器域名配置了 https没有&#xff0c;如果没有&#xff0c;解决办法是申请个ssl证书&#xff0c;具体看这里 https://doc.crmeb.com/mer/mer2/4257 二、完成第一步后&#…

vmware esxi6.0安装配置操作

系统安装及配置 在服务器上安装ESXI 6.0 提示是否继续安装 如果不想安装,按ESC后再按F11即可,稍后电脑会重启. 继续安装,则按回车键 按F11同意声明继续 选择将EXSI 安装到哪个硬盘上,我这里使用的是虚拟机,所以只有这一个选项 选择默认键盘布局,默认的美国键盘即可 设置root…