资讯专栏INFORMATION COLUMN

利用ArrayList, swing, ActionListener创造简单GUI计算器

Acceml / 3084人阅读

摘要:废话不多说,在网上搜索了编写计算器相关的源码,要么算法低效要么不全。什么意思呢就是像这样的算数是没办法解决的,只能解决像这样的。所以小编先将中缀表达式转化成后缀并标记多位数的操作符,然后在处理后缀表达式。

废话不多说,在网上搜索了编写计算器相关的源码,要么算法低效要么不全。于是这周小编决定简单讲讲如何制作一个简易计算器,首先你要清楚GUI里要显示什么:

结果显示框

0~9的数字

删除功能

清楚功能

搜寻历史记录功能

计算结果的功能

括号优先计算功能

接下来通过流程图简单介绍一下思路:

GUI 源码

以下代码是根据我的设计来编写的

/**
 * @author Hephaest
 * @since  2018/04/19
 * JDK 1.6
 */
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
/**
 * Calculator类用来创造GUI
 */
public class Calculator extends JFrame
{
    //新建文本框
    JTextField text = new JTextField();
    // set up row 2
    JPanel row2 = new JPanel();
    //创建按钮们
    String[][] buttons= {{"7","8","9","DEL","AC"},{"4","5","6","×","÷"},{"1","2","3","+","-"},{"0","(",")","Replay","="}};
    JButton[][]button = new JButton[4][5];
    /**
     * 这个计算机的界面我模拟的是卡西欧fx-82ES PLUS A
     * 但是仅有其中的部分功能
     */
    public Calculator()
    {
        super("CASIO");
        setSize(400,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        //设置文本框的尺寸、位置以及禁止键盘输入
        text.setPreferredSize(new Dimension(30, 40));
        text.setHorizontalAlignment(SwingConstants.TRAILING);
        text.setEditable(false);
        getContentPane().add(text, BorderLayout.NORTH);
        //声明每一个按钮代表的意义
        add(row2, BorderLayout.CENTER);
        GridLayout layout2 = new GridLayout(4,5,5,5);
        row2.setLayout(layout2);
        for(int i=0;i
效果

事件监听器源码

有了按钮后下一步就是要想办法实现按钮功能,我的思路在上面流程图里给过了,不再累赘,直接看如何利用代码实现:

/**
 * @author Hephaest
 * @since  2018/04/19
 * JDK 1.6
 */
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JTextField;
/**
 * Listener 类
 * 用来将按钮输入的结果通过链表的方式一个字一个字存储在字符串里,然后调用另一类计算整个字符串,返回一个值
 */
public class Listener implements ActionListener
{
    private Calculator cl;
    private ArrayList list=new ArrayList();
    private ArrayList his=new ArrayList();//这个链表用来添加每一次得到的最终的结果
    private ArrayList arr = new ArrayList();//把his里的一整串字符分割成单个字符,再连接
    private String[] arrayStr = new String[] {};//储存单次的历史记录
    private String out="";
    private String output="";
    
    public Listener(Calculator cl)
    {
        this.cl=cl;
    }
    
    public void actionPerformed(ActionEvent event)
    {
        JButton button = (JButton) event.getSource();
        /**
         * 如果点“=”,计算整个表达式的结果,如果是错误表达式,在文本框输入“Input Error!”
         */
        if(button.getText().equals("="))
        {
            try
            {    
                Function f = new Function();
                double result=f.compute(out);
                cl.text.setText(Double.toString(result));
            }catch(Exception e)
            {
                cl.text.setText("Input Error!");
            }
            
        }
        /**
         * 如果点击"×",先把它转换为"*"
         */
        else if(button.getText().equals("×"))
        {
            if(list.isEmpty())
            {
                arr.add("*");
                output+="*";
                out=output;
                cl.text.setText(output);
            }
            else
            {
                list.add("*");
                output+="*";
                out=output;
                cl.text.setText(output);
            }
        }
        /**
         * 如果点击"÷",把它转换为"/"
         */
        else if(button.getText().equals("÷"))
        {
            if(list.isEmpty())
            {
                arr.add("/");
                output+="/";
                out=output;
                cl.text.setText(output);
            }
            else
            {
                list.add("/");
                output+="/";
                out=output;
                cl.text.setText(output);
            }
        }
        /**
         * 如果点击"DEL",删除表达式里最后一个字符,每点一次删一个
         */
        else if(button.getText().equals("DEL"))
        {
            if(list.isEmpty())
            {
                arr.remove(arr.size()-1);
                 output="";
                 for(int i=0;i
计算器表达式算法

关于如何分析整个表达式并计算出正确值,小编实践了一下,还是后缀表达式比较方便,不用考虑括号这种优先级问题。对于理论算法不再这累赘了,小编在查阅资料的时候发现算法不管用栈还是正则等等,似乎只处理操作符是0~9的数,这是很不可取的。什么意思呢?就是像10/5这样的算数是没办法解决的,只能解决像5/5这样的。所以小编先将中缀表达式转化成后缀并标记多位数的操作符,然后在处理后缀表达式。

/**
 * @author Hephaest
 * @since  2018/07/13
 * JDK 1.6
 */
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
public class function {
    private String[] str=new String[10];
    private int begin;
    public function()
    {
        
    }
    /**
     * 中缀表达式转换成后缀表达式
     * @param exp 在计算器上显示的文本 中缀表达式
     * @return 正确的计算结果
     */
    public double compute(String exp) 
    {
        char[] ch=exp.toCharArray();
        Stack  stack= new Stack<>();
        String convertToPostfix=new String();
        int size=ch.length;
        begin=0;
        for (int i = 0; i < size; i++) {
          //遇到左括号直接入栈
          if(ch[i]=="(") 
          {
              stack.push(ch[i]);
          }
          //遇到右括号出栈(追加到后缀表达式),直到出栈的元素为左括号或为0
          else if(ch[i]==")")
          {
              char popValue=stack.pop();
              do 
              {
                  convertToPostfix=convertToPostfix.concat(String.valueOf(popValue));
                  popValue=stack.pop();
              }while(!stack.isEmpty()&&popValue!="(");
          }
          /*
           * 遇到运算符需要判断:
           * 1.是否为空栈,是的话直接入栈
           * 2.即将入栈的运算符是否比栈顶元素优先级高
           *     是,直接入栈
           *    否,栈顶元素出栈(追加到后缀表达式),当前运算符入栈
           */
          else if(checkOperator(ch[i]))
          {
              if(stack.isEmpty())
              {
                  stack.push(ch[i]);
              }
              else
              {
                  char popValue=stack.pop();
                  while(checkPriority(popValue,ch[i]))
                  {
                      convertToPostfix=convertToPostfix.concat(String.valueOf(popValue));
                      if(stack.isEmpty())
                      {
                          break;
                      }
                      popValue=stack.pop();
                  }
                  if(checkPriority(popValue,ch[i])==false)
                  {
                      stack.push(popValue);
                  }
                  stack.push(ch[i]);
              }
          }
          /*
           * 单个数字直接追加到后缀表达式
           * 含有不止一个数字的操作符需要做记录:
           *     1.计算该操作符的起始位置和终止位置
           *     2.把数字传到字符串数组里(全局变量,下一步需要用到)
           */
          else if(checkDigital(ch[i]))
          {
              if(i+1=0)
              {
                  if(checkDigital(ch[i-1])&&!checkDigital(ch[i+1]))
                  {
                      int end=i;
                      int j=end;
                      while(checkDigital(ch[j]))
                      {
                          j--;
                      }
                      j++;
                      List elements = new LinkedList<>();
                      do
                      {
                          elements.add(String.valueOf(ch[j]));
                          j++;
                      }while(j<=end);
                      str[begin]=String.join("", elements);
                      System.out.println(str[begin]);
                      begin++; 
                  }
                  
              }
              convertToPostfix=convertToPostfix.concat(String.valueOf(ch[i]));
          }
         }
        //第一遍结束后把栈中剩下的操作符依次出栈(追加到后缀表达式)
        while(!stack.isEmpty())
        {
            char popValue=stack.pop();
            convertToPostfix=convertToPostfix.concat(String.valueOf(popValue));
        }
        System.out.println(convertToPostfix);
        return computeResult(convertToPostfix);
    }
    /**
     * 计算后缀表达式
     * @param convertToPostfix 后缀表达式的字符串
     * @return 计算结果
     */
    public double computeResult(String convertToPostfix)
    {
        int[] index=new int[10];
        /*
         * 判断是否有多位数的操作符,有的话找到在后缀表达式的初始位置
         * 如果没有的话就不会执行
         */
        for(int i=0;i stack=new Stack<>();
        double result=0;
        for (int i = 0; i < ch.length; i++) {
            //如果是运算符,pop出栈顶的两个元素,记住先进后出
            if(checkOperator(ch[i]))
            {
                double num2=stack.pop();
                System.out.println("num2"+num2);
                System.out.print("
");
                double num1=stack.pop();
                System.out.println("num1"+num1);
                System.out.print("
");
                switch(ch[i])
                {
                    case "*":
                        result=num2*num1;
                        break;
                    case "/":
                        result=num1/num2;
                        break;
                    case "+":
                        result=num1+num2;
                        break;
                    case "-":
                        result=num1-num2;
                        break;
                }
                System.out.println(result);
                stack.push(result);
            }
            /*
             * 对于多位操作符,需要把单个字符连接起来然后作为一个双精度数放入栈中
             * 一位数的操作符直接放入栈即可,注意从字符变成数字时要减去48(0的字符型数据)
             */
            else
            {
                int stop=0;
                for(int j=0;j elements = new LinkedList<>();
                        do
                        {
                            elements.add(String.valueOf(ch[i]));
                            i++;
                        }while(i=0&&num<=9)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    /**
     * 判断即将入栈的优先级是否更高
     * @param popOne 栈顶元素
     * @param checkOne 即将入栈元素
     * @return 布尔型结果
     */
    public boolean checkPriority(char popOne,char checkOne)
    {
        if((popOne=="*"||popOne=="/")&&(checkOne=="+"||checkOne=="-"))
        {
            return true;
        }
        else if(popOne==checkOne)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}
小结

凡事靠自己,多研究多思考

算法比语言更重要

Github 源码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/23753.html

相关文章

  • Java 实现简单算器

    摘要:对于理论算法不再这累赘了。在查阅资料的时候发现算法不管用栈还是正则等等,似乎只处理操作符是的数,这是很不可取的。所以需要先将中缀表达式转化成后缀并标记多位数的操作符,然后在处理后缀表达式。 最后一次更新于2019/07/08 效果演示图 showImg(https://segmentfault.com/img/bVbuIwj?w=388&h=290); 功能与流程 要制作一个简易计算器...

    thekingisalwaysluc 评论0 收藏0
  • Java 实现小球碰撞GUI

    摘要:球类的构造函数。如果点文本框的信息被读取,生成指定的小球。所有小球组成的列表。框架需要文本框实现输入,两行,每行个变量。用于一行一行的放置文本框和按钮类的构造函数。 最后一次更新于2019/07/08修复问题: 错误输入未提醒问题 碰撞小球的图形重叠问题 高速小球越界问题 感谢 大一暑假拜读学姐的一篇文章:我说这是一篇很严肃的技术文章你信吗,本篇在她的基础上加以改进。 效果演示图 ...

    Dogee 评论0 收藏0
  • Java,console输出实时的转向GUI textbox

    摘要:下面这句话会转向中输出实时输出问题方法,本质上是多线程的更新内容。在处理上的点击事件时,事件处理返回之前,其他事件是不能触发的,界面类似于卡住的状况。因此,在点击事件结束后,更新内容的线程才能运行,这样的效果是内容输出是非实时的。 1 简单入门例子   入门例子是从参考文献2与3中粘过来的内容。  在Swing中,如果需要重定向System.err和System.out到一个JText...

    ivydom 评论0 收藏0
  • Java学习笔记

    摘要:读输入这个对象做读入下一行的操作这个对象打印下一行数组其中所有的元素都具有相同的数据类型数组定义创建的数组会得到默认的值创建个型数组直接初始化数组可以不用给出大小有成员函数可直接使用数组变量是数组的管理者而非数组本身数组必须创建出来交给数组 1、读输入 Scanner in=new Scanner(System.in);//in这个对象做读入下一行的操作 System.out.prin...

    jkyin 评论0 收藏0
  • 利用多线程、简单GUI实现小球的动能定理的二维可视化

    摘要:动能定理的实践出了问题,因为鼠标点击的小球生成是随机的,无法得知每个小球的情况,动能定理公式给定了,可能是算法不够精致。 要实现小球的运动,可以从以下几点切入: 小球都有那些具体特征? - 涉及动能定理就需要考虑质量了,除此之外常规的几个变量也不能忘:方向、球的尺寸,所在位置以及当前速度 谁能初始小球的状态? - 小球的状态无非两种:(随机)默认值、人工手动输入 谁能控制...

    simpleapples 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<