Java实现简单的计算器

2023-05-16

文章目录

  • 前言
  • 一、主界面部分
  • 二、监听器部分
  • 三、结果计算部分
  • 总结


前言

最近在复习着Java Swing的使用,在布局这块反复又看了很久,然后突然发现GirdLayout机器适合来做一个计算器的简单样子,所以花了一点时间做了一下,最后没想到是在处理结果的算法这一块花的时间最多,这个简单的计算器目前来说支持的是加减乘除和括号运算,当然之后可能会扩展三角函数等功能吧。。。。


下面我将从各个模块来展示对应的代码

一、主界面部分

这个部分就是一个展示计算器的界面,只是简单的套用了GirdLayout和几个button(所以最后写完发现好像Swing没有复习到多少hhh)

package com.UI;

import com.UI.Listener.buttonListener;

import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

/*
 * 2015-06-10
 */

/***
 * 计算器的主页面的设置
 */
public class calcUI extends JFrame{

    JButton resultButton = new JButton("");
    JPanel[] panel = new JPanel[5];
    public calcUI()
    {
        setSize(500,400);
        //设置为GirdLayout
        setLayout(new GridLayout(6,1));
        add(resultButton);
        for(int i = 0;i < 5;i++){
            panel[i] = new JPanel();
            add(panel[i]);
            //gridLayout
            GridLayout gridLayout = new GridLayout(1,4,3,3);
            panel[i].setLayout(gridLayout);
        }
        //计算器输入
        String [] buttonNames = new String []{"<-","(",")","C","7", "8","9","/","4","5","6","*","1","2","3","-","0",".","=","+"};
        for (int i=0;i<buttonNames.length;i++) {
            JButton jButton = new JButton(buttonNames[i]);
            panel[i/4].add(jButton);
            // 添加监听器来监听计算器
            jButton.addActionListener(new buttonListener(resultButton));
        }
        //config resultButton
        resultButton.setSize(200, 50);
        resultButton.setHorizontalAlignment(SwingConstants.RIGHT);
        resultButton.setEnabled(false);
        setTitle("calcUI");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        calcUI demo = new calcUI();
        demo.setVisible(true);
    }

}

二、监听器部分

这部分使用的是按钮监听器,通过获取每个按钮对应的文字类型改变上方显示结果按钮给出的文字。

package com.UI.Listener;

import com.UI.Utils.Calc;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class buttonListener implements ActionListener {
    JButton ansButton;
    String text;
    public void actionPerformed(ActionEvent e) {
        String actionCommand = e.getActionCommand();
        text = ansButton.getText();
        if ("=".equals(actionCommand)) {  // 如果选择的是求解则开始计算
            text = Calc.CalcAns(text);  // 将计算结果的作为工具类
        }
        else if(actionCommand.equals("C"))  // 清空
        {
            text = "";
        }
        else if(actionCommand.equals("<-"))  // 删除一位
        {
            if (text.length() <= 1) text = "";
            else text = text.substring(0,text.length()-1);
        }
        else
        {
            text += actionCommand;
        }
        ansButton.setText(text);
    }
    public buttonListener(JButton ansButton) {
        this.ansButton = ansButton;
    }
}


三、结果计算部分

这个部分的代码量甚至比前两部分加起来还多了,主要是要加上正确性判断,结果求解等等,虽然似乎jdk已经给出来了对应的函数,但是既然已经做了,这部分的代码还是自己写为好,求解的部分就是通过双栈,一个符号栈一个数字栈来进行处理,避免了各种if情况的判断。(虽然没必要,但是把它设置为了静态类)

package com.UI.Utils;

import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
import java.util.regex.Pattern;

public class Calc {
    /**
     * 以下部分为处理字符串包含的数字
     *
     * @param str 待处理的字符串
     * @return
     */
    public static String StringToNum(String str) {
        Pattern patternSc = Pattern.compile("[+-]*\\d+\\.?\\d*[Ee]*[+-]*\\d+");  // 判断是否为科学计数法
        Pattern patternNum = Pattern.compile("-?[0-9]+\\.?[0-9]*");  // 判断是否为数字
        if (patternSc.matcher(str).matches()) {
            BigDecimal bd = new BigDecimal(str);
            return bd.toPlainString();
        } else if (patternNum.matcher(str).matches())
            return str;
        else
            return "";
    }

    /***
     * 处理读入的字符串
     * @param s 读入的字符串
     * @return
     */
    public static Queue<String> ReadInNums(String s) {
        Queue<String> count = new LinkedList<String>();
        double sum = -1;
        double Point = -1;
        int flag = 1;
        for (int index = 0; index < s.length(); index++) {
            if (s.charAt(index) >= '0' && s.charAt(index) <= '9' || s.charAt(index) == '.') {  //为数字的情况
                if (index > 0 && s.charAt(index - 1) == '-')  //遇到减法变加法处理
                    flag = -1;
                if (s.charAt(index) == '.') {  // 判断是否为.
                    if (Point != -1 || sum == -1)  // 如果已经有或者只是单个的.则判断为错误
                        return null;
                    else
                        Point = 0;  // 标记为有小数点
                } else {
                    if (Point != -1)  //如果之前有小数点出现则说明现在是小数位
                        Point++;
                    if (sum == -1)
                        sum = s.charAt(index) - '0';
                    else
                        sum = sum * 10 + s.charAt(index) - '0';
                }
            } else {
                if (Point != -1)
                    sum = sum / Math.pow(10, Point);//如果当前数字有小数位则除去相应的小数位位数
                if (sum != -1)
                    count.offer(String.valueOf(flag * sum));
                if (s.charAt(index) == '-') {
                    if (index < s.length() - 1 && s.charAt(index + 1) >= '0' && s.charAt(index + 1) <= '9'
                            && index != 0 && s.charAt(index - 1) != '(')
                        count.offer(String.valueOf('+'));  // 减法做加法处理
                    else
                        count.offer(String.valueOf('-'));
                } else
                    count.offer(String.valueOf(s.charAt(index)));
                sum = -1;
                Point = -1;
                flag = 1;
            }
            if (index == s.length() - 1 && sum != -1) {//处理尾部为数字的情况
                if (Point != -1) sum = sum / Math.pow(10, Point);
                count.offer(String.valueOf(flag*sum));
            }
        }
        return count;
    }

    /***
     * 此函数用来判断字符串表达式是否正确
     * @param countString
     * @return
     */
    public static boolean StRight(String[] countString) {
        int countKuo = 0;  // 计算括号的数量
        int countChar = 0;  // 计算计算符的数量
        for (int index = 0; index < countString.length; index++) {
            String str = countString[index];
            System.out.println(str);
            if (str.equals("(")) {
                countKuo++;
            } else if (str.equals(")")) {
                countKuo--;
            } else if (StringToNum(str).length() != 0) {
                countChar--;
            } else
                countChar++;
            if (countKuo < 0) return false;
        }
        if (countKuo != 0 || countChar != -1) return false;
        return true;
    }

    /**
     * 处理方法总入口的函数
     *
     * @param s 待处理的字符串
     * @return
     */
    public static String CalcAns(String s) {
        Queue<String> count = ReadInNums(s);  // 处理读取的字符串
        if (count == null || count.size() == 0) return "error!";  // 如果存在错误则返回
        String[] countString = new String[count.size()];
        int index = 0;
        while (count.peek() != null) {
            countString[index++] = count.poll();
            System.out.println(countString[index - 1]);
        }
        boolean stRight = StRight(countString);  // 判断表达式是否正确
        if (stRight)
            return CalcNums(countString);
        return "error!";
    }

    /***
     * 计算数字结果
     * @param countString
     * @return
     */
    private static String CalcNums(String[] countString) {
        //  开两个栈,分别存操作符合操作数
        Stack<String> operator = new Stack<String>();  // 操作符
        Stack<Double> operatorNum = new Stack<Double>();  // 操作数
        for (String sIndex : countString) {
            String s = StringToNum(sIndex);
            if (s != null && s.length() != 0)  // 判断字符串为数字
                operatorNum.push(Double.parseDouble(s));
            else  // 字符串不为数字
                switch (sIndex.charAt(0)) {
                    case '+':
                    case '-':
                    case '*':
                    case '/':
                        while (operator.size() != 0 && (operator.peek() != null && operator.peek().equals('*')
                                || operator.peek().equals("/"))) {  // 前置的乘除需要先处理
                            if (operatorNum.size() < 2)
                            return "error";
                            else {
                                String opera = operator.pop();
                                double num2 = operatorNum.pop();
                                double num1 = operatorNum.pop();
                                if (opera.equals("/")) {
                                    if (num2 == 0) return "error!";
                                    else operatorNum.push(num1 / num2);
                                } else {
                                    operatorNum.push(num1 * num2);
                                }
                            }
                        }
                        operator.push(sIndex);
                        break;
                    case '(':
                        operator.push(sIndex);
                        break;
                    case ')':
                        while (!operator.peek().equals("(")) {  //遇到一个括号则需要清除对等的括号
                            if (unableToOperate(operator, operatorNum)) return "error";
                        }
                        operator.pop();
                        break;
                }
        }
        while(operator.size() != 0)
        {
            if (unableToOperate(operator, operatorNum)) return "error";
        }
        if(operatorNum.size() != 1)
            return "error";
        else {
            double nums = operatorNum.pop();
            if(nums == (int)nums) return String.valueOf((int)nums);
            return String.valueOf(nums);

        }
    }

    /***
     * 判断当前求和过程是否出错
     * @param operator
     * @param operatorNum
     * @return
     */
    private static boolean unableToOperate(Stack<String> operator, Stack<Double> operatorNum) {
        if (operatorNum.size() < 2)
            return true;
        else {
            String opera = operator.pop();
            double num2 = operatorNum.pop();
            double num1 = operatorNum.pop();
            if (opera.equals("/")) {
                if (num2 == 0) return true;
                else
                    operatorNum.push(num1 / num2);
            } else if (opera.equals("*"))
                operatorNum.push(num1 * num2);
            else if (opera.equals("+"))
                operatorNum.push(num1 + num2);
            else
                operatorNum.push(num1 - num2);
        }
        return false;
    }
}


总结

算是一个小练手?最近一直在学SSM导致没啥时间写代码了,不过想想其实SSM框架最终目的也只是为了更好地写代码,而不是喧宾夺主,没有它就不行,例如我这个代码好像根本没有用这个框架啥的,可能自己之前有点太过于看重这种形式了吧(当然也得学!)学完SSM后就回头去学JVM吧,把最基础的一些东西搞懂!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java实现简单的计算器 的相关文章

  • 关于stm32中串口重定向问题详解(找个时间好好理解下)

    usart这部分代码我也是从网上copy出来的 xff0c 一下是作者的解释 xff1a 简单地说 xff1a 想在mdk 中用printf xff0c 需要同时重定义fputc函数和避免使用semihosting 半主机模式 xff09
  • 缓冲区溢出(buffer overflow)避免方法

    什么是缓冲区溢出 xff1f copy数据进buffer时 xff0c 数据长度超过buffer中的剩余空间 缓冲区溢出的危害 xff1f 缓冲区溢出 xff0c 结果随机 xff0c 可能会导致程序功能不正常 xff0c 也可能导致程序崩
  • 【嵌入式系统应用开发】ROS环境安装配置与入门实操

    目录 前言1 ROS简介2 ROS软件安装2 1 添加ROS软件源2 2 添加密钥2 3 安装ROS2 4 初始化rosdep2 5 设置环境变量2 6 安装rosinstall 3 ROS初试 小海龟3 1 启动ROS Master3 2
  • 头文件包含的合理顺序

    如果包含顺序不当 xff0c 可能出现包含顺序依赖问题 xff0c 甚至引起编译错误 推荐如下顺序 xff1a 在头文件中 xff1a xff08 1 xff09 包含当前工程中所需要的自定义头文件 xff08 顺序自定 xff09 xff
  • windows下使用 SITL 模拟飞行——APM

    1 环境配置 按照官网教程配置环境 xff0c 链接 xff1a https ardupilot org dev docs building setup windows cygwin html building setup windows
  • Nvidia Xavier Nx平台修改CAN时钟调试记录

    1 前言 JETSON NX开发板上配置CAN bus与一个CAN收发器SN65HVD230 要求是改变设备树中的CAN时钟速率 让CAN时钟修改为40MHZ 2 如何设置准确的40MHz 要实现40MHz 首先需要设置CAN父时钟为pll
  • 【CMake】常见目录——10.1安装项目

    CMake中的目录 常见目录所代表的含义 PROJECT SOURCE DIR xff1a 工程的根目录 PROJECT BINARY DIR xff1a 运行cmake命令的目录 xff0c 通常为 PROJECT SOURCE DIR
  • 编译的时候所使用的动态库中出现错误:未定义的引用

    1 使用makefile编译的时候 xff0c 出现错误如下 xff1a 如上图所示 xff0c 是在动态库libicdbapi so中出现了未定义错误 xff0c 既然是未定义错误 xff0c 说明sqlprct sqlnult这5个符号
  • STL1:简介

    STL1 简介 1 背景1 1 STL是什么 xff1f 1 2 STL与C 43 43 标准库的关系1 3 版本 2 STL的组成3 容器分类4 迭代器分类4 1 分类原则 xff1a 访问方式4 2 分类原则 xff1a 操作类型4 3
  • Linux网络编程 5 - select模式的TCP服务器

    为了同时处理多个客户端的连接 xff0c 上一篇介绍了利用多线程的方法实现 xff0c 每个连接新建一个线程 xff0c 然后各自去处理 这是最简单也是最容易想到的方式 客户端的连接存在 xff0c 线程就存在 但是 xff0c 对于每一个
  • c标准库—参考手册

    1 lt errno h gt 2 lt float h gt 3 lt limits h gt 4 lt locale h gt 5 lt math h gt 6 lt signal h gt 7 lt setjmp h gt 8 lt
  • MPU6050

    1 个人总结 常用的MPU6050有八个针脚 xff0c VCC 跟GND 给模块供电 xff0c 模块通讯方式采用IIC通讯 xff0c SCL跟SDA为信号传递通道 xff0c XDA 跟 XCl是用来外接电磁传感器 xff0c 玩过M
  • 自学 Python 第一天

    总结 xff1a 感觉Python 前边学起来 跟c差不多 xff0c 之前学习过c语言 xff0c 但是并没有学这么细 xff0c 刚好学python xff0c 把当时忽略的知识点 重新减一下 打算花费两周学完Python为后续学习Op
  • 多功能悬赏任务平台app+小程序源码开源版搭建开发

    悬赏任务app源码 xff0c 从名字本身就可以理解这个PHP项目的流程 通过在线管理员工任务 即使它也可以在Intranet中工作 MySQL数据库是此源代码的最终部分 它易于实施和遵循 它是所有企业公司的主要项目应用程序 IT公司的任务
  • usart串口发送与接收问题

    项目场景 xff1a 串口通信可以说很常用的一种通信方式 xff0c 例如 蓝牙通信 openmv 与串口 通信 等等 问题描述 1 我们在进行数据传输过程中数据不时出现丢失的情况 xff0c 偶尔会丢失一部分数据 xff0c 导致数据部分
  • 基于51单片机光照强度检测系统

    介绍 本设计采用单片机作为数据处理与控制单元 xff0c 为了进行数据处理 xff0c 通过光敏电阻来感应光强弱变化 xff0c 经过ADC0804转换 xff0c 直接将数字信号送入到单片机中进行数据处理 单片机数据处理之后 xff0c
  • 基于51单片机控制的波形输出

    介绍 本模块采用PCF8591 xff0c 它是一款AD DA集成芯片 所以本节对iic通信协议不做过多的介绍 xff0c 重心放在iic的rtl建模 xff0c 本次通过iic控制PCF8591实现DAC输出功能 及输出波形 将数字量转为
  • 基于51单片机通过译码器控制系统

    用二极管 开关 译码器 单片机 数码管 xff08 点阵显示器 xff09 等器件设计仿真电路 xff0c 实现的功能 xff0c 用红黄绿二极管分别连接开关作为3 8译码器的输入 xff0c 译码器的输出连接到单片机的端口 xff0c 单
  • 基于51单片机串口通信的实验

    串口介绍 串口是一种应用十分广泛的通讯接口 xff0c 串口成本低 容易使用 通信线路简单 xff0c 可实现两个设备的互相通信 单片机的串口可以使单片机与单片机 单片机与电脑 单片机与各式各样的模块互相通信 xff0c 极大的扩展了单片机
  • 【QT】设置子窗口显示位置

    QT通过setGeoment来设置子窗口的位置 QWidget span class token operator span widget test span class token operator 61 span new span cl

随机推荐

  • 【散文诗】C语言的本质(基于ARM深入分析C程序)

    文章目录 1 ARM架构ARM通用寄存器及其别名基本汇编指令LDR xff1a STR xff1a ADD xff1a SUB xff1a BL xff1a PUSH xff1a POP xff1a MOV xff1a 2 局部变量的分配与
  • 【MQTT基础篇(三)】连接MQTT服务端

    文章目录 连接MQTT服务端1 CONNECT 连接服务端1 1 clientId 客户端ID1 2 cleanSession 清除会话1 3 keepAlive 心跳时间间隔 2 CONNACK 确认连接请求2 1 returnCode
  • 【MQTT基础篇(五)】发布、订阅和取消订阅

    文章目录 发布 订阅和取消订阅1 PUBLISH 发布消息1 1 topicName 主题名1 2 QoS 服务质量等级1 3 packetId 报文标识符1 4 retainFlag 保留标志1 5 Payload 有效载荷1 6 dup
  • 【FreeRTOS(六)】队列

    文章目录 队列创建队列 xQueueCreate发送消息至队列 xQueueSend接受队列消息 xQueueReceive获取队列信息数目 uxQueueMessagesWaiting代码示例创建队列集 xQueueCreateSet将队
  • 2021-09-29 使用安卓手机Camera和IMU信息运行ORBSLAM3

    目的 安卓手机具备camera imu gps等SLAM技术所需要的传感器 xff0c 且安卓手机很普及 如果能使用安卓设备作为ros的sensor xff0c 通过安卓设备节点传输到计算机 xff0c 进行实时定位与建图分析 xff0c
  • 【ESP32 WiFi篇(五)】ESP32 HTTP

    文章目录 1 HTTP概述1 1 超文本1 2 请求 响应1 3 TCP 2 HTTP请求和响应2 1 HTTP请求响应过程2 2 客户端请求消息2 2 1 请求行2 2 1 1 请求方法2 2 1 2 URL2 2 1 3 HTTP版本
  • 【Linux 裸机篇(五)】I.MX6ULL BSP工程管理下的 Makefile编写、链接脚本

    目录 一 BSP 工程二 Makefile三 链接脚本 Makefile 的静态模式和函数1 静态模式2 函数2 1 patsubst2 2 dir2 3 notdir2 4 foreach 一 BSP 工程 文件夹描述bsp存放驱动文件i
  • 【Linux 裸机篇(六)】I.MX6U 主频和时钟配置

    目录 一 时钟系统详解1 系统时钟来源2 7路 PLL 时钟源2 1 ARM PLL PLL1 2 2 528 PLL PLL2 2 3 USB1 PLL PLL3 2 4 USB2 PLL PLL7 2 5 ENET PLL PLL6 2
  • 【Linux 裸机篇(七)】I.MX6U 中断系统

    目录 一 中断向量表1 中断向量偏移 二 中断系统简介1 创建中断向量表 三 GIC 控制器简介1 中断 ID 四 GIC 逻辑分块1 Distributor 分发器端 2 CPU Interface CPU 接口端 五 CP15 协处理器
  • 【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖

    目录 一 EPIT 定时器简介二 定时器按键消抖 一 EPIT 定时器简介 EPIT 的全称是 xff1a Enhanced Periodic Interrupt Timer xff0c 直译过来就是增强的周期中断定时器 xff0c 它主要
  • PCB拼板和工艺边教程

    PCB拼板 xff0c 主要是为了充分利用板材 xff0c 从而提高生产效率 比较简单的是 xff0c 规则板框的拼板 如上图的 xff0c 板框是正方形 xff0c 很容易就拼了四块板 xff0c 其中 xff0c 只需要有一块板有布线
  • curl命令模拟get请求时遇到特殊字符{}被过滤异常处理

    curl命令模拟get请求时遇到特殊字符 xff0c 接口接受参数不符合预期 crul请求 curl GET http test com opdgApply pageNum 61 1 amp sortDesc 61 true amp sea
  • 函数声明在头文件中的好处,可以利用静态库隐藏算法

    背景 xff1a 现在有个程序员A想实现一个算法 xff0c 这个算法是俩数之和 xff0c 他自己不会于是他去买程序员B的已经做好的算法 xff0c 但是程序员B不想让他看到算法结构应该怎么做 1 首先程序员B需要写程序 xff0c 包括
  • Javaparser使用

    Javaparser使用 什么是Javaparser 分析 转换 生成Java代码 Javaparser库为你提供了一个 Java 代码的抽象语法树 Abstract Syntax Tree AST 结构允许您以一种简单的编程方式使用 Ja
  • YUV和RGB图像格式说明

    对于进行图像处理的程序员来说 xff0c 图像格式是必须了解的问题 本文不涉及压缩图像格式 xff0c 只对YUV和RGB图像进行描述 1 RGB图像和YUV图像区别 RGB和YUV图像的区别在于色彩空间坐标系描述上不同 xff0c 就如同
  • CMake 常用指令

    文章目录 范式环境 amp 工程配置 96 cmake minimum required 96 96 project 96 96 file 96 添加头文件搜索路径 96 link directories 96 96 add compile
  • (JAVA)国际跳棋--棋里乾坤

    导入 因为假期内被朋友带入坑后起了兴趣 xff0c 但发现网上似乎没有什么人写过国际跳棋的相关制作过程 xff0c 于是制作了一个单纯的java的国际跳棋程序 xff0c 虽然没有AI xff0c 但能够实现玩家双方的任务和皮肤 目前只设置
  • 力扣刷题日记 211. 添加与搜索单词

    211 添加与搜索单词 题目描述题解思路代码结语 题目描述 题解思路 首先 xff0c 这道题要求我们给出所有结果 xff0c 那就意味着我们可能只能选择枚举这一条路 xff0c 然后再看到数据范围 xff0c 好家 伙 xff0c 确实挺
  • 力扣刷题日记 798. 得分最高的最小轮调

    798 得分最高的最小轮调 题目描述题解思路代码结语 题目描述 题解思路 数据范围没有截图到 xff0c 这里的数据范围为0 20000 题目的内容还是很好理解的 xff0c 就是给你一个数组 xff0c 你可以将数组内容向左推移若干次 x
  • Java实现简单的计算器

    文章目录 前言一 主界面部分二 监听器部分三 结果计算部分总结 前言 最近在复习着Java Swing的使用 xff0c 在布局这块反复又看了很久 xff0c 然后突然发现GirdLayout机器适合来做一个计算器的简单样子 xff0c 所