第2章 Java 仿Windows计算器

mousefat 贡献于2012-06-19

作者 雨林木风  创建于2009-10-01 12:33:00   修改者yangenxiong  修改于2010-01-19 08:06:00字数16773

文档摘要:Windows计算器,是Windows操作系统自带计算器,,可以帮助用户完成数据的运算,它可分为“标准型”和“科学型”,本章的仿Windows计算器是标准型的Java实现,标准型Windows计算器实现的主要功能有:四则运算;求倒数;求开方;存储计算结果;读取计算结果;累积计算结果。
关键词:

·· 第2章 仿Windows计算器 第2章 仿Windows计算器 2.1 仿Windows计算器概述 Windows计算器,是Windows操作系统自带计算器,,可以帮助用户完成数据的运算,它可分为“标准型”和“科学型”,本章的仿Windows计算器是标准型的Java实现,标准型Windows计算器实现的主要功能有:四则运算;求倒数;求开方;存储计算结果;读取计算结果;累积计算结果。 我们在第一章中,我们实现了一个在控制台进行的五子棋游戏,我们从本章开始将在Swing界面中实现本书的项目。在本章中,我们将使用到JFrame和JPanel两个Swing容器,使用到JTextField和JButton两个Swing容器,使用BorderLayout和GridLayout做两个布局器,以及使用到事件、事件监听器和事件适配器等。 实现一个计算器,界面中需要提供各种输入的按钮,再以这些按钮组成计算器的键盘,用户点击键盘输入值后,就可以将其所输入的值显示到一个文本框中,运算后,再将结果显示到文本框中。计算器的最终效果如图2.1所示。 图 2.1 用Swing制作的计算器 从图2.1中可以看到,我们开发界面的时候,需要提供一个文本框在窗口的最上部,文本框下面再提供各个计算器的按钮。 2.1.1 数学与其它符号介绍 在此计算器中,主要使用的数学运算有加、减、乘、除四则运算,或者对一个正数进行开方,或者对一个非0的数学求倒数,使用到的数学符号有: q 加、减、乘、除,对应使用的符号是“+”、“-”、“*”、“/”。 q 开方与倒数,对应使用的符号是“sqrt”和“1/x”。 q 求结果使用的数学符号是“=”。 ·· 第2章 仿Windows计算器 q “%”号,如果使用此符号,第二个操作数就等于两数相乘再除以100。 除了用于数学运算的符号,Windows计算器还提供对计算结果做存储、读取、累加、清除等操作,亦有对数字显示框中的数字做退格操作,还可以清除上次计算结果或者全部结果: q 使用符号“MC”、“MR”、“MS”、“M+”代表清除存储结果、读取存储结果、保存存储结果和累加存储结果。 q 使用“Backspace”符号代表退格。 q 使用“CE”和“C”代表清除上次计算结果和清除所有计算结果。 四则运算在程序中可以直接使用Java运算符实现,实现开方可以调用Math类的sqrt方法,倒数可以使用1来除以原始的数字。当用户需点击“=”的时候,计算器就需要将最终的计算结果显示到文本框中。其他的计算器功能都可以通过计算器内部的程序实现,例如使用某个字符串或者数字来保存相应的结果,如果需要计取、存储、累加或者清除结果,可以通过改变或者读取我们所保存的值来实现。 2.1.2 界面说明 界面中使用的Swing组件相对简单,整个大窗口可以看作一个JFrame对象,在JFrame对象中,存放一个JPanel对象,我们需要为这个JPanel对象进行布局,将文本框(JTextField对象)与各个计算器按钮(JButton对象)添加到这个JPanel中。在添加计算器按钮的时候,我们可以使用GridLayout布局处理器来进行网格状布局,由于各个计算器按钮都是以网格状分布在界面中的,因此使用GridLayout非常适合。本章计算器的界面布局并不复杂,因此在这里不再详细描述。 2.2 流程描述 用户打开计算器后,在没有关闭计算器之前,可以通过鼠标点击“1”到“9”数字键和点击“+”、“-”、“*”、“/”键去输入要运算结果的算术式,再通过点击“=”、“sqrt”、“1/x”等键去直接获取计算结果,除外,还可以点击“MC”、“MR”、“MS”、“M+”键去清除、读取、保存、累加计算显示框中显示的数字,还有清除上次结果、清除所有结果、退格等操作。从图2.2中可以看出,计算器打开之后,就开始监听用户的鼠标动作,如果输入是关于计算结果或者“MC”、“MR”、“MS”、“M+”、“Backspace”、“CE”、“C”等操作指令,而且没有关闭计算器,就返回计算结果并显示,如果不是,则不计算结果。接下来再继续等待用户的输入。 本章的计算器并没有复杂的流程,只需要简单的操作,返回计算结果等。在实现计算器的过程中,我们需要注意的是,例如已经点击了某个数字,再点击运算符,那么程序需要记录之前选点击的数字,当用户再次点击运算符(非“=”)时,系统就需要将结果显示到文本框中。因此在开发计算器的时候,我们需要注意用户点击的具体顺序。 ·· 第2章 仿Windows计算器 图 2.2 计算流程 2.3 建立计算器对象 实现一个计算器,我们需要建立一系列的对象来实现,例如,计算界面我们要建立一个界面类,还需要建立一个专门负责处理加、减、乘、除的基本计算类,还需要一个负责处理计算功能的业务类。本小节中只讲解创建这三个基本的类,如果在开发的过程发现可以将一些行为或者属性放置到一个新的对象中,那么可以再建立这些对象来完成需要实现的功能或者操作。 本章主要设计四个类来完成计算器的功能,界面类(CalFrame)—主要用来显示计算器界面,功能类(CalService)—主要用于完成计算器中的逻辑功能,计算工具类(MyMath)—此类是工具类,用于处理大型数字的加减乘除,计算器类(Cal)—用于打开计算器,计算器中各个类的关系如图2.3所示,从图中可以看出,我们的界面类继承了java.swing.JFrame类,计算器类使用了界面类,界面类使用了功能类,功能类使用了MyMath工具类,下面章节将对这些计算器的相关类作详细介绍。 ·· 第2章 仿Windows计算器 图2.3 计算器类图 2.3.1 MyMath工具类 使用float,double两种浮点基本类型来进行计算,容易损失精度,所以,我们使用一个自己定义了加,减,乘,除方法的类,此类使用BigDecimal来封装基本类型,在不损失精度的同时,也可以进行超大数字的四则运算。为了方便调用,此类的方法全部都是静态方法,可以直接用“类名.方法名”调用,这个类包含以下方法: q static double add( double num1, double num2 ),加法,使用来计算结果的数字是封装后的num1和 num2,并返回double类型。 q static double subtract ( double num1, double num2 ),减法,使用来计算结果的数字是封装后的num1和 num2,并返回double类型。 q static double multiply ( double num1, double num2 ),乘法,使用来计算结果的数字是封装后的num1和 num2,并返回double类型。 q static double divide ( double num1, double num2 ),除法,使用来计算结果的数字是封装后的num1和 num2,并返回double类型。 MyMath类提供了基础的四则运算方法,由于该类中所有的方法都是静态的,因此外界可以直接调用。在实现MyMath的过程中需要注意的是,这几个四则运算方法,参数都是double类型的,要进行运算的话,需要将double类型转换成一个BigDecimal对象,我们可以使用以下代码来创建一个BigDecimal对象: ·· 第2章 仿Windows计算器 new BigDecimal(String.valueOf(number)); 2.3.2 CalService类 CalService类主要是用来处理计算器的业务逻辑,用户在操作计算器时,此类将计算结果,并且返回,并且,会记录计算器的状态(用户的上一步操作)。包含以下方法: q String callMethod( String cmd , String text ),调用方法并返回计算结果。 q String cal( String text , boolean isPercent ),用来计算加、减、乘、除法,并返回封装成String内型的结果。参数text是显示框中的数字内容,boolean类型的参数isPercent代表是否有"%"运算,如果有,便加上去。 q String setReciprocal( String text ),用来计算倒数,并返回封装成String内型的结果。 q String sqrt( String text ),用来计算开方,并返回封装成String内型的结果。 q String setOp( String cmd , String text ),设置操作符号。 q String setNegative( String text ),设置正负数,当text是正数时,返回负数的数字字符串,反之,则返回正数的数字字符串。 q String catNum( String cmd, String text ),连接输入的数字,每次点击数字,就把把新加的数字追加到后面,并封装成字符串返回。 q String backSpace( String text ),删除最后一个字符,并返回结果。 q String mCmd( String cmd, String text ),用来实现“M+”、“MC”、“MR”、“MS”与存储有关的功能。 q String clearAll(),清除所有计算结果。 q String clear( String text),清除上次计算结果。 CalService类中的各个方法都是用于处理计算的逻辑,其中callMethod方法可以看作中一个中转的方法,根据参数中的cmd值进行分发处理,例如调用该方法时将“CE”字符串作为cmd,那么该方法就根据这个字符串再调用需要执行“CE”的方法。如果需要做更好的程序解耦,我们可以将这些做成一个状态模式,将各个计算的方法都抽象成一个计算接口,该接口提供一个计算的方法,然后按照具体的情况,为该接口提供不同的实现,例如计算开方、计算倒数等实现,然后向callMethod传入不同的实现类,直接调用接口方法。 2.3.3 CalFrame类 CalFrame类继承javax.swing.Jframe类,主要是用于计算器界面的实现,此类中,排版了计算器中各个组件的位置,为组件增加事件监听器,用来监听用户的操作,并做调用相应的方法,主要包含以下方法: q void initialize(),初始化计算器界面。 q ActionListener getActionListener(),如果动作监听器为空,则创建一个,并返回,如果不为空,直接返回。 q JTextField getTextField(),这个方法初始化输入框。 q JButton[] getMButton(),此方法获得计算器的存储操作键。 q JButton[] getRButton(),此方法获得计算器的结果操作键。 q JButton[] getNButton(),此方法获得计算器的其它操作键。 由于CalFrame是界面类,因此所需要进行的业务处理并不多,更多的是监听用户的操作,并进行分发处理。这就有点像web应用中的MVC模式中的V(视图),并不处理任务的业务逻辑,主要职责是显示相应的数据。 ·· 第2章 仿Windows计算器 在本章中,CalFrame包括了一些监听器,监听界面事件并调用相关的业务方法,在实际开发中,我们可以将这些监听器作为MVC模式中的C(控制器)提取到另外的类中。 2.4 MyMath工具类实现 MyMath是一个工具类,主要用于处理加、减、乘、除四则运算,我们已经确定了实现这四个方法的时候,都使用BigDecimal对象进行计算。由于我们定义MyMath方法的时候,所有方法的参数都是double类刑的,因此我们可以提供一个工具方法来将double转换成BigDecimal类型。 以下代码根据一个double类型转换成一个BigDecimal。 代码清单:code\cal\src\org\crazyit\cal\MyMath.java /** * 为一个double类型的数字创建BigDecimal对象 * @param number * @return */ private static BigDecimal getBigDecimal(double number) { return new BigDecimal(number); } 提供了这个工具方法后,我们可以在其他的计算方法中使用这个工具方法,选择将double的参数转换成BigDecimal对象,然后再进行具体的运算。 2.4.1 实现四则运算 编写了double转换的工具方法后,实现加、减、乘、除比较简单,由于BigDecimal已经为我们实现了,因此可以直接调用该类的相应方法即可实现,以下代码分别实现四则运算。 代码清单:code\cal\src\org\crazyit\cal\MyMath.java 加法: public static double add(double num1, double num2) { //调用工具方法将double转换成BigDecimal BigDecimal first = getBigDecimal(num1); BigDecimal second = getBigDecimal(num2); return first.add(second).doubleValue(); } 减法: public static double subtract(double num1, double num2) { BigDecimal first = getBigDecimal(num1); BigDecimal second = getBigDecimal(num2); return first.subtract(second).doubleValue(); } 乘法: public static double multiply(double num1, double num2) { BigDecimal first = getBigDecimal(num1); BigDecimal second = getBigDecimal(num2); return first.multiply(second).doubleValue(); } 除法: public static double divide(double num1, double num2) { ·· 第2章 仿Windows计算器 BigDecimal first = getBigDecimal(num1); BigDecimal second = getBigDecimal(num2); return first.divide(second, DEFAULT_SCALE, BigDecimal.ROUND_HALF_UP) .doubleValue(); } 四个方法都是调用了BigDecimal的方法来实现,Java的BigDecimal类为我们提供了许多强大的计算方法,可以让我们很方便的进行数学运算,除本章介绍的方法我,读者可以查阅Java的API来学习该类的详细使用。 2.5 计算器主界面 这里实现计算器的界面,是用java的Swing实现的,主要用到的类有javax.swing.JFrame(窗口),javax.swing.JButton(按钮),javax.swing.JTextField(输入框),并使用java.awt.BorderLayout和java.awt.GridLayout进行布局。在这里,我们使用“自下而下”的方法去观察此类,先看总体的排版实现,再看各个小组件的实现。为了方便布局,我们按相近的外观把计算器分为四个部分,见图2.4: 图 2.4 布局 2.5.1 初始化界面(initialize()方法) 此类就是一个JFrame(继承了javax.swing.JFrame),用来做其它窗口或者组件的父容器,初始化计算器窗口的大概流程: q 设置父窗口JFrame标题、布局管理器、是否可以改变等属性 。 q 增加输入与计算结果显示框。对应图2.4中的左上角那部分。 q 增加左边存储操作键。 q 增加结果操作键。 q 增加数字与其它运算符。 由于按外观相近的方式把组件分成了四部分,就方便程序中对相同属性的组件统一地创建与设置属性,对于界面的布局也更加地直观与方便,观察此图,我们可以使用BorderLayout做总体布局,如图2.5所示。 ·· 第2章 仿Windows计算器 图 2.5 布局管理器 以下代码设置父窗口JFrame标题和设置是否可以改变大小的属性。 //设置窗口的标题 this.setTitle("计算器"); //设置为不可改变大小 this.setResizable( false ); 增加输入与结果显示的JTextField输入框,这里调用本类的getTextField()方法获取,并把它加入panel中的NORTH位置中: //增加计算输入框 JPanel panel = new JPanel(); panel.setLayout( new BorderLayout(10,1) ); panel.add( getTextField(), BorderLayout.NORTH ); panel.setPreferredSize( new Dimension( PRE_WIDTH, PRE_HEIGHT ) ); 增加左边存储操作键,本类需要通过getMButton()方法获取一个保存JButton对象的数组,getMButton方法我们将在2.5.2中实现。获取数组后,遍历数组,并把数组中的元素加到一个新建的JPanel中,最后再把这个JPanel加到JFrame的相应位置: //增加左边存储操作键 JButton[] mButton = getMButton(); //新建一个panel,用于放置按钮 JPanel panel1 = new JPanel(); //设置布局管理器 panel1.setLayout( new GridLayout( 5, 1, 0, 5 ) ); //迭代增加按钮 for( JButton b : mButton ) panel1.add(b); 增加结果操作键,这些结果操作键包括:Back,CE,C。通过本类的getRButton()方法获取一个保存JButton对象的数组,获取数组后,遍历数组,并把数组中的元素加到一个新建的JPanel中,最后再把这个JPanel加到JFrame相应的位置,具体实现的代码如下: //增加结果操作键 ·· 第2章 仿Windows计算器 JButton[] rButton = getRButton(); JPanel panel2 = new JPanel(); panel2.setLayout( new BorderLayout(1, 5) ); //新建一个panel,用于放置按钮 JPanel panel21 = new JPanel(); //设置布局管理器 panel21.setLayout( new GridLayout( 1, 3, 3, 3 ) ); //迭代增加按钮 for( JButton b : rButton ) panel21.add(b); 接下来将其他的按键加入到界面的JPanel对象中,这些操作键主要包括数字键和其他的一些运算键,我们同样的通过一个getNButton方法来返回这些操作键对应的JButton对象,最后将这些JButton对象加入到相应的JPanel中,加入到JPanel并设置相应布局的代码如下: //增加数字与其它运算符 JButton[] nButton = getNButton(); //新建一个panel,用于放置按钮 JPanel panel22 = new JPanel(); //设置布局管理器 panel22.setLayout( new GridLayout( 4, 5, 3, 5 ) ); //迭代增加按钮 for( JButton b : nButton ) panel22.add(b); //把新增加的面板加到frame … this.add(panel); 在本小节中,我们通过getMButton、getRButton和getNButton方法来返回不同的JButton数组,然后再对这些数组进行遍历,将每一个JButton加入到界面中。这一个返回JButton数组的方法并没有实现,下面将介绍如何实现这三个方法。 以上所有的代码均在code\cal\src\org\crazyit\cal\CalFrame.java中。 2.5.2 创建运算键 运算键主要包括数字键与基本运算键,数字键从0到9,基本运算键包括开方、正负、小数点等键,主要实现计算器界面的getNButton方法即可。以下是该方法的实现。 代码清单:code\cal\src\org\crazyit\cal\CalFrame.java private JButton[] getNButton() { // 这个数组保存需要设置为红色的操作符 String[] redButton = { "/", "*", "-", "+", "=" }; JButton[] result = new JButton[nOp.length]; for (int i = 0; i < this.nOp.length; i++) { // 新建按钮 JButton b = new JButton(this.nOp[i]); // 为按钮增加事件 b.addActionListener(getActionListener()); // 对redButton排序,才可以使用binarySearch方法 Arrays.sort(redButton); // 如果操作符在redButton出现 if (Arrays.binarySearch(redButton, nOp[i]) >= 0) { b.setForeground(Color.red); } else { b.setForeground(Color.blue); ·· 第2章 仿Windows计算器 } result[i] = b; } return result; } 以上代码需要注意的是,我们需要提供一个红色按键的字符串数组,在遍历所有的需要创建的按键数组时,就需要作判断,如果按键数组里面存在红色按键数组的某个元素,就需要调用JButton的setForeground方法来设置该按钮的字体颜色。在代码中我们不能看到该方法帮我们创建了哪些按键,代码中使用了一个nOp的字符串数组来保存需要创建的按键,该数组包含的内容如下: private String[] nOp = { "7", "8", "9", "/", "sqrt", "4", "5", "6", "*", "%", "1", "2", "3", "-", "1/x", "0", "+/-", ".", "+", "=" }; 2.5.3 创建操作按键 操作按键的创建与运算键的创建基本一致,只是所有的按键的字体都必须是红色的,创建操作按钮,我们需要实现getMButton和getRButton方法,以下是这两个方法的具体实现。 代码清单:code\cal\src\org\crazyit\cal\CalFrame.java private JButton[] getMButton() { JButton[] result = new JButton[mOp.length + 1]; result[0] = getButton(); for (int i = 0; i < this.mOp.length; i++) { // 新建按钮 JButton b = new JButton(this.mOp[i]); // 为按钮增加事件 b.addActionListener(getActionListener()); // 设置按钮颜色 b.setForeground(Color.red); result[i + 1] = b; } return result; } private JButton[] getRButton() { JButton[] result = new JButton[rOp.length]; for (int i = 0; i < this.rOp.length; i++) { // 新建按钮 JButton b = new JButton(this.rOp[i]); // 为按钮增加事件 b.addActionListener(getActionListener()); // 设置按钮颜色 b.setForeground(Color.red); result[i] = b; } return result; } getMButton创建的是界面左侧的操作键,getRButton创建的是运作键上面的操作键,getMButton和getRButton创建的操作键如下: //getMButton private String[] mOp = { "MC", "MR", "MS", "M+" }; //getRButton ·· 第2章 仿Windows计算器 private String[] rOp = { "Back", "CE", "C" }; 创建完界面元素后,我们可以运行计算器,具体的效果如图2.4所示。 2.5.4 增加事件监听器 在上一节中,我们注意到程序为JButton类型的组件增加了事件监听器,这个事件监听器是用来响应用户的鼠标操作。我们使用java.awt.event.ActionListener接口来创建一个事件监听器,主要是实现接口中的actionPerformed( ActionEvent e )方法,当监听器监听到用户的操作时,会自动调用此方法,并在此方法中处理业务逻辑,再把数据返回显示给用户。见以下代码。 代码清单:code\cal\src\org\crazyit\cal\CalFrame.java actionListener = new ActionListener(){ public void actionPerformed( ActionEvent e ) { String cmd = e.getActionCommand(); String result = null; try { //计算操作结果 result = service.callMethod( cmd, textField.getText() ); } catch( Exception e1 ) { System.out.println( e1.getMessage() ); } //处理button的标记 if( cmd.indexOf("MC") == 0 ) { button.setText(""); } else if( cmd.indexOf("M") == 0 && service.getStore() > 0 ) { button.setText("M"); } //设置计算结果 if( result != null ) { textField.setText( result ); } } }; 从上面代码中可以看到,这里是通过实现java.awt.event.ActionListener接口中的actionPerformed( ActionEvent e )方法去创建一个java.awt.event.ActionListener类型的内部类,并在actionPerformed方法中处理业务逻辑。 首先,调用CalService实例中的callMethod方法去处理计算,并把结果返回。 result = service.callMethod( cmd, textField.getText() ); 再设置标志存储结果类型的存储标记,如果是点击“MC”按钮,就把标记设置为空,如果是点击“MS”,“MR”,“M+”,并且存储结果大于0,就把标记设置为“M”,这里弄不明白的读者,可以先试着使用一下windows计算器的这几个按钮,再看这里就很容易理解了。 if( cmd.indexOf("MC") == 0 ) { button.setText(""); } else if( cmd.indexOf("M") == 0 && service.getStore() > 0 ) { button.setText("M"); } 最后把计算结果设置到结果文本显示框中,显示给使用者。 if( result != null ) { textField.setText( result ); } ·· 第2章 仿Windows计算器 在监听器中,我们调用了CalServer的callMethod方法来取得操作的结果,换言之,界面中的每次点击都会执行该方法,callMethod我们并没有提供任何实现,在下一小节,我们将实现该方法。 2.6 计算业务处理 在2.3章节中,我们建立了一个类名为CalService的类来处理计算器的计算业务,该类处理了整个应用中的大部分业务,其中包括数字运算,存储运算,操作结果等业务。有四个重要的属性:firstNum代表第一个操作数,secondNum代表第二个操作数,lastOp代表上次用户所做的操作, isSecondNum代表是否第二个操作数。 2.6.1 计算四则运算结果 在使用计算器计算加、减、乘、除法的过程中,正常的情况应该是用户先输入第一个操作数,再点击加、减、乘、除计算符号,再输入第二个操作数,最后点“=”号计算出结果,所以这时用firstNum去保存用户输入的第一个操作数,secondNum去保存第二个操作数,lastOp去保存计算符号或者其它操作,isSecondNum用来判断用户是在输入第几个操作数。 在用户输入数字的时候(包括“0123456789.”),首先判断是第一个操作数还是第二个,如果是第一个,就把用户新输入的数字追加到原来数字的后面,并做为结果返回;如果是第二个,直接返回结果,并把isSecondNum标志为false,用户继续输入数字的时候,就把数字追加到原来数字的后面做为结果返回,见以下代码。 代码清单:code\cal\src\org\crazyit\cal\CalService.java public String catNum( String cmd, String text ) { String result = cmd; //如果目前的text不等于0 if( !text.equals("0") ) { if( isSecondNum ) { //将isSecondNum标志为false isSecondNum = false; } else { //刚返回结果为目前的text加上新点击的数字 result = text + cmd; } } //如果有.开头,刚在前面补0 if( result.indexOf(".") == 0 ) { result = "0" + result; } return result; } 当用户点击“+-*/”(四则运算)的时候,就把lastOp设置为其中一个符号,这个变量用来记录用户正要进行计算的类型,见以下代码。 代码清单:code\cal\src\org\crazyit\cal\CalService.java public String setOp( String cmd , String text ) { //将此操作符号设置为上次的操作 this.lastOp = cmd; //设置第一个操作数的值 this.firstNum = text; ·· 第2章 仿Windows计算器 //将第二个操作数赋值为空 this.secondNum = null; //将isSecondNum标志为true this.isSecondNum = true; //返回空值 return null; } 在上面的代码中,可以看到,除了设置lastOp外,还把输入的数字设置给firstNum,把secondNum设置为空,并把isSecondNum设置为true,代表下次输入数字时,要清空输入框并重新输入。 最后用户点击“=”号时,就是程序计算出最后结果的时候,此类的String cal( String text , boolean isPercent )方法实现了此计算,注意到这个方法的第二个参数isPercent,这是计算器的“%”号操作,如果有这种操作,第二个操作数就等于两数相乘再除以100,请看以下代码。 代码清单:code\cal\src\org\crazyit\cal\CalService.java public String cal( String text , boolean isPercent ) throws Exception { //初始化第二个操作数 double secondResult = secondNum == null ? Double.valueOf( text ).doubleValue() : Double.valueOf( secondNum ).doubleValue(); //如果除数为0,不处理 if( secondResult == 0 && this.lastOp.equals("/") ) { return "0"; } //如果有"%"操作,则第二个操作数等于两数相乘再除以100 if( isPercent ) { secondResult = MyMath.multiply( Double.valueOf( firstNum ) , MyMath.divide( secondResult, 100 ) ); } //四则运算,返回结果赋给第一个操作数 if( this.lastOp.equals("+") ) { firstNum = String.valueOf( MyMath.add( Double.valueOf( firstNum ), secondResult ) ); } else if( this.lastOp.equals("-") ) { firstNum = String.valueOf( MyMath.subtract( Double.valueOf( firstNum ), secondResult ) ); } else if( this.lastOp.equals("*") ) { firstNum = String.valueOf( MyMath.multiply( Double.valueOf( firstNum ), secondResult ) ); } else if( this.lastOp.equals("/") ) { firstNum = String.valueOf( MyMath.divide( Double.valueOf( firstNum ), secondResult ) ); } //给第二个操作数重新赋值 secondNum = secondNum == null ? text : secondNum; //把isSecondNum标志为true this.isSecondNum = true; return firstNum; } ·· 第2章 仿Windows计算器 上面计算结果中,经历了几个步骤,首先,确定secondNum的值,如果secondNum为空,secondNum就等于最后输入的数字,如果不为空,则等于原来的值,如果有“%”号操作,则secondNum再等于两数相乘除以100的结果;然后根据lastOp的值(+、-、*、/)去调用MyMath类中的add、subtract、multiply、divide方法,并把返回的结果保存到firstNum;最后把secondNum设置为空,把firstNum当做结果返回。 2.6.2 存储操作 定义一个double类型的属性store来充当存储器,在用户点击“MC(清除)”、“M+(累加)”、“MR(读取)”、“MS(保存)”操作时,就调用此方法,再根据得到的字符串去进行清除、累加、读取、保存操作,见以下代码。 代码清单:code\cal\src\org\crazyit\cal\CalService.java public String mCmd( String cmd, String text ) { if( cmd.equals( "M+" ) ) { //如果是"M+"操作,刚把计算结果累积到store中 store = MyMath.add( store, Double.valueOf( text ) ); } else if( cmd.equals( "MC" ) ) { //如果是"MC"操作,则清除store store = 0; } else if( cmd.equals( "MR" ) ) { //如果是"MR"操作,则把store的值读出来 isSecondNum = true; return String.valueOf( store ); } else if( cmd.equals( "MS" ) ) { //如果是"MS"操作,则把计算结果保存到store store = Double.valueOf( text ).doubleValue(); } return null; } 程序中提供了一个store的属性用来保存计算结果,当用户点击了“M+”时,就将结果加到store中,点击了“MC”时,就将store设置为0,点击了“MR”,则将store的值读取,点击了“MS”,则将store设置为当前的结果。 2.6.3 实现开方、倒数等 开方与倒数的计算实现都比较简单,开方是直接使用Math类的sqrt方法去计算接收到的数值,并且返回结果: public String sqrt(String text) { // 将isSecondNum标志为true this.isSecondNum = true; // 计算结果并返回 return String.valueOf(Math.sqrt(Double.valueOf(text))); } 倒数是调用MyMath的divide方法去计算1与接收到的数值相除的值。 代码清单:code\cal\src\org\crazyit\cal\CalService.java public String setReciprocal(String text) { // 如果text为0,则不求倒数 if (text.equals("0")) { ·· 第2章 仿Windows计算器 return text; } else { // 将isSecondNum标志为true this.isSecondNum = true; // 计算结果并返回 return String.valueOf(MyMath.divide(1, Double.valueOf(text))); } } 2.6.4 实现倒退操作 当我们的程序中得到用户在界面输入的相关数字时,如果用户进行了倒退操作,我们可以将用户输入的数字进行截取,如果接收到的字符串是“0”或者为null,则不作任何操作,直接返回,否则,我们将使用String的substring方法进行处理,将输入字符串的最后一位截取。以下方法实现倒退操作。 代码清单:code\cal\src\org\crazyit\cal\CalService.java public String backSpace(String text) { return text.equals("0") || text.equals("") ? "0" : text.substring(0, text.length() - 1); } 2.6.5 清除计算结果 清除所有计算结果,把firstNum与secondNum都设置为原始值,并返回firstNum,在CalService中提供了一个clearAll方法,用于清除所有的计算结果。 代码清单:code\cal\src\org\crazyit\cal\CalService.java public String clearAll() { // 将第一第二操作数恢复为默认值 this.firstNum = "0"; this.secondNum = null; return this.firstNum; } 2.6.6 实现中转方法(callMethod) 在前面的章节中,我们已经实现了各个方法,例如四则运算、开方、倒数、清除计算等,但是在界面的监听器中,只会调用CalService的callMethod方法进行运算,因此我们需要对callMethod进行相关的实现。 代码清单:code\cal\src\org\crazyit\cal\CalService.java public String callMethod(String cmd, String text) throws Exception { if (cmd.equals("C")) { return clearAll(); } else if (cmd.equals("CE")) { return clear(text); } else if (cmd.equals("Back")) { return backSpace(text); } else if (numString.indexOf(cmd) != -1) { return catNum(cmd, text); } else if (opString.indexOf(cmd) != -1) { ·· 第2章 仿Windows计算器 return setOp(cmd, text); } else if (cmd.equals("=")) { return cal(text, false); } else if (cmd.equals("+/-")) { return setNegative(text); } else if (cmd.equals("1/x")) { return setReciprocal(text); } else if (cmd.equals("sqrt")) { return sqrt(text); } else if (cmd.equals("%")) { return cal(text, true); } else { return mCmd(cmd, text); } } CalService中的callMethod方法,只是判断输入命令,再决定调用具体的哪个方法处理计算。例如监听器监听到用户点击了倒退了按键,那么callMethod方法就会根据点击的按键文本来找到backSpace方法。当然,使用这么多的if…else…并不是最佳的解决方案,我们可以使用一些的设计模式来解决。有兴趣的读者可以了解相关的设计模式,考虑如何解决这些问题。 2.7 本章小结 本章主要是通过一个仿Windows计算器的基本实现,向读者讲解Java swing编程,示范了JFrame,JPanel,JTextField,JButton的使用。界面布局方面,使用到了awt的BorderLayout与GridLayourt布局管理器去布局。并且向读者介绍了ActionLisner事件监听器的使用,介绍如何监听用户的动作响应用户,并且向用户返回有用的信息。本章中实现的计算相对较为简单,有兴趣的读者可以在本文的基础上实现更强大的计算器(科学型计算器)。另外需要注意的是,本章程序编写的过程中,使用了许多if…else…语句,对设计模式有一定了解或者希望对此有了解的读者,可以尝试去重构本章的代码,消除这些if…else…。在下面的章节中,我们会在编写的过程中,展示一些设计模式的概念。

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档