四则运算计算器程序设计(java-GUI)
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
四则运算计算器程序设计(java-GUI)
北京林业大学信息学院 闫煜鸿
一、 实例描述
用户通过按钮输入一个四则混合运算表达式,当按下‘=’时能够计算并显示计算结果, 如果用户输入的表达式有错误则要给出 ERROR 提示。
二、 实例分析
本实例需要用户通过按钮输入四则混合运算表达式,那么程序界面需要提供数字和符号 的按钮,同时还需要能够显示输入和输出结果的控件。为了便于布局和管理,使用三个 JButton 数组存放所有的按钮对象,分别为数字键(0 到 9 以及小数点)、运算符键(加、 减、乘、除、括号、等号等)和功能键(包括重置、后退、说明等)。用于显示信息的控件 使用 JLable 类型的对象 lable。
当事件源为‘=’按钮时,除了在 label 后添加字符‘=’,还要调用自定义的方法 EvaluateExpression()得到表达式的值并将此值添加在 lable 之后,同时将 p 的值设为 false。 此时数字键和运算符按钮以及‘后退’键都不可使用。
当事件源为‘重置’按钮时,将 lable 中的字符清空,同时恢复 p 的值为 true。 当事件源为‘说明’按钮时,在 lable 中显示说明文字,同时设置 p 的值为 false,以防 止用户输入的表达式错误。
五、 数据结构与算法设计
如何根据用户输入的字符串表达式计算表达式的值呢?这里介绍使用堆栈来计算表达 式的值的方法。
首先是关于堆栈的描述。使用 java.util 包中的 Stack<E>泛型类可以创建一个堆栈对象。 堆栈对象可以调用 public E push(E item)方法实现入栈操作,及在栈顶插入元素 item;调用 public E pop()方法实现出栈操作,及删除并返回栈顶元素;调用 public boolean empty()方法 判断堆栈是否为空,如果为空则返回 true;调用 public E peek()方法可以获取栈顶元素,但 不删除该元素。在这个程序中需要有两个堆栈对象,分别是用来存放运算数的 OPND 栈(E 为 Float 类型)和存放运算符的 OPTR 栈(E 为 Character 类型)。
之后一位。 3) 若 ch 为运算数,则将 ch 压入 OPND 栈,读取下一个字符。 4) 若 ch 为运算符,则比较 OPTR 栈顶元素与 ch 的优先级:
a) 若是小于,则将 ch 压入 OPTR 栈,读取下一个字符; b) 若是大于,则弹出 OPTR 栈顶的运算符,从 OPND 中弹出两个运算数,进行
ab
+
-
×
÷
(
)
﹦
+
>
>
<
<
<
>
>
-
>
>
<
<
<
>
>
×
>
>
>
>
<
>
>
÷
>
>
>
>
<
>
>
(
<
<
<
<
<
=
?
)
>
>
>
>
?
>
>
﹦
<
பைடு நூலகம்
<
<
<
<
?
=
因为表达式中的数字占有多个连续字符,所以还需要将连续数字字符变为 Float 类型的
数字,在程序中面对错误的表达式还要返回“ERROR”信息,这些算法的实现详见程序代码 部分。
{ JButton curr = (JButton)e.getSource(); int i = 0; if(p && label.getText().length()<40)//这些按钮可用(p)且以输入字符长度小于40 { for( i=0 ; i<11 ; i++)//事件源为数字键按钮 if(curr == button_num[i]) { label.setText( label.getText() + button_num[i].getText()); break; } for( i=0 ; i<6 ; i++)//事件源为运算符按钮 if(curr == button_bol[i]) { label.setText( label.getText() + button_bol[i].getText()); break; } if(curr == button_bol[6])//事件源为„=‟按钮 { label.setText( label.getText() + button_bol[6].getText()); label.setText( label.getText() + EvaluateExpression()); p = false; } if(curr == button_fun[1] && label.getText().compareTo("")!=0)//事件源为„后退‟
button_fun[0] = new JButton("重置"); button_fun[1] = new JButton("后退"); button_fun[2] = new JButton("说明"); }//成员变量及其初始化
Expression()//构造方法,用于布局设计 {
int i = 0;
用户通过数字键和运算符按钮输入表达式并在 lable 控件中显示,当按下‘=’键的时候, 计算表达式的值并显示在显示控件中。由于用户在输入表达式的过程中存在这很多的不确定 因素,为了防止这些不确定因素引起的程序错误,对表达式的处理集中在用户按下‘=’按 钮的时候,同时其他按钮不可使用(‘重置’除外),点击‘重置’后方可继续使用。三个 功能键能够实现不同的功能,‘重置’可将已输入的内容清除,‘后退’可以向前删除一个 字符,‘说明’则在显示控件中显示说明内容。
相应的计算,并将计算结果压入 OPDN 栈内; c) 若是等于,则删除 OPTR 栈顶的元素,读取下一个字符。 5) 循环结束,返回 OPDN 栈顶元素,该元素为表达式的运算结果。 相继出现的运算符 a 和 b 之间的优先关系如下表,‘<’表示 a 的优先级低于 b,‘=’ 表示 a 与 b 的优先级相等,‘>’表示 a 的优先级高于 b,‘?’表示错误的运算符顺序:
在实例分析中提到在某些时刻有些按钮不能使用,这就需要一个 boolean 类型的成员变 p 量来确定这些按钮是否可以使用,其初始值为 true。当 p 为 true 的时候,所有的数字键、 运算符按钮和功能键中的后退键均可使用。这些按钮的功能都是对 lable 的内容进行修改, 数字键和运算符按钮在 lable 后添加该按钮表示的字符,‘后退’则删除 lable 末尾的一个字 符。
当进行按下‘=’键时,进行表达式的求值。表达式求值的过程参见数据结构与算法设 计部分。
三、 布局设计
如右图所示的布局方式, 整体分为三部分,使用三个 中间容器即可实现此种布局。 构造方法用于布局的实现, 在构造方法中申明和初始化 三个中间容器 p1、p2、p3, 其中 p1 存放显示控件,位于 窗体的上部;p2 存放数字键, 位于窗体的左部;p3 存放功能键和运算符按钮,位于窗体的右部。p1 使用 FlowLayout 布局, 并设置对齐方式为左对齐;p2 和 p3 使用 GridLayout 布局,网格规模分别为 4*3 和 3*3。窗 体布局使用 BorderLayout 布局,按图所示分别使 p1 在 NORTH 位置,p2 在 WEST 位置,p3 在 CENTER 位置。
p2.setLayout(new GridLayout(4,3)); for(i=1 ; i<10 ; i++)
p2.add(button_num[i]); p2.add(button_num[10]); p2.add(button_num[0]); p2.add(button_bol[6]);
p3.setLayout(new GridLayout(3,3)); for( i=0 ; i<3 ; i++)
{ for( int i=0 ; i<10 ; i++) button_num[i] = new JButton(""+i); button_num[10] = new JButton(".");
button_bol[0] = new JButton("+"); button_bol[1] = new JButton("-"); button_bol[2] = new JButton("×"); button_bol[3] = new JButton("÷"); button_bol[4] = new JButton("("); button_bol[5] = new JButton(")"); button_bol[6] = new JButton("﹦");
boolean p = true;
JLabel label = new JLabel();
JButton[] button_num = new JButton[11]; JButton[] button_bol = new JButton[7]; JButton[] button_fun = new JButton[3];
布局的方式有多种多样,读者可以有自己的创新,不局限与这一种布局方式。
四、 事件处理响应
通过实现 ActionListener 接口中的 public void actionPerformed(ActionEvent e)方法,将事 件处理全部集中在 actionPerformed(ActionEvent e)方法中。首先在构造方法中为所有的 JButton 对象添加监听器,在 actionPerformed(ActionEvent e)方法中,首先有一个 JButton 类 型的变量用来获取事件源的引用,然后程序根据事件源的不同做出不同的响应。
六、 程序代码
import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Expression extends JFrame implements ActionListener//继承JFrame类,实现 ActionListener接口 {
for( i=0 ; i<11 ; i++)//为所有的按钮添加监听器 button_num[i].addActionListener(this);
for( i=0 ; i<7 ; i++) button_bol[i].addActionListener(this);
for( i=0 ; i<3 ; i++) button_fun[i].addActionListener(this);
接着是将 lable 字符串通过 toCharArray()方法转换为字符数组。一个个地读取表达式中 的字符,根据不同的字符进行不同的处理,这个过程如下:
1) 建立并初始化 OPTR 和 OPND 栈,并将表达式起始符‘=’压入 OPTR 栈。 2) 依次读取表达式中的每个字符 ch,然后循环一下步骤,直到定位到最后一个字符
JPanel p1 = new JPanel(); JPanel p2 = new JPanel(); JPanel p3 = new JPanel();
FlowLayout flow = new FlowLayout(); flow.setAlignment(FlowLayout.LEFT); p1.setLayout(flow); p1.add(new JLabel("显示:")); p1.add(label);
setTitle("计算器"); setBounds(100, 100 , 350 , 220); setVisible(true); setResizable(false); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
public void actionPerformed(ActionEvent e)//实现ActionListener接口的actionPerformed方 法,用于事件处理响应
p3.add(button_fun[i]); for( i=0 ; i<6 ; i++)
p3.add(button_bol[i]);
add(p1 , BorderLayout.NORTH); add(p2 , BorderLayout.CENTER); add(p3 , BorderLayout.EAST);
北京林业大学信息学院 闫煜鸿
一、 实例描述
用户通过按钮输入一个四则混合运算表达式,当按下‘=’时能够计算并显示计算结果, 如果用户输入的表达式有错误则要给出 ERROR 提示。
二、 实例分析
本实例需要用户通过按钮输入四则混合运算表达式,那么程序界面需要提供数字和符号 的按钮,同时还需要能够显示输入和输出结果的控件。为了便于布局和管理,使用三个 JButton 数组存放所有的按钮对象,分别为数字键(0 到 9 以及小数点)、运算符键(加、 减、乘、除、括号、等号等)和功能键(包括重置、后退、说明等)。用于显示信息的控件 使用 JLable 类型的对象 lable。
当事件源为‘=’按钮时,除了在 label 后添加字符‘=’,还要调用自定义的方法 EvaluateExpression()得到表达式的值并将此值添加在 lable 之后,同时将 p 的值设为 false。 此时数字键和运算符按钮以及‘后退’键都不可使用。
当事件源为‘重置’按钮时,将 lable 中的字符清空,同时恢复 p 的值为 true。 当事件源为‘说明’按钮时,在 lable 中显示说明文字,同时设置 p 的值为 false,以防 止用户输入的表达式错误。
五、 数据结构与算法设计
如何根据用户输入的字符串表达式计算表达式的值呢?这里介绍使用堆栈来计算表达 式的值的方法。
首先是关于堆栈的描述。使用 java.util 包中的 Stack<E>泛型类可以创建一个堆栈对象。 堆栈对象可以调用 public E push(E item)方法实现入栈操作,及在栈顶插入元素 item;调用 public E pop()方法实现出栈操作,及删除并返回栈顶元素;调用 public boolean empty()方法 判断堆栈是否为空,如果为空则返回 true;调用 public E peek()方法可以获取栈顶元素,但 不删除该元素。在这个程序中需要有两个堆栈对象,分别是用来存放运算数的 OPND 栈(E 为 Float 类型)和存放运算符的 OPTR 栈(E 为 Character 类型)。
之后一位。 3) 若 ch 为运算数,则将 ch 压入 OPND 栈,读取下一个字符。 4) 若 ch 为运算符,则比较 OPTR 栈顶元素与 ch 的优先级:
a) 若是小于,则将 ch 压入 OPTR 栈,读取下一个字符; b) 若是大于,则弹出 OPTR 栈顶的运算符,从 OPND 中弹出两个运算数,进行
ab
+
-
×
÷
(
)
﹦
+
>
>
<
<
<
>
>
-
>
>
<
<
<
>
>
×
>
>
>
>
<
>
>
÷
>
>
>
>
<
>
>
(
<
<
<
<
<
=
?
)
>
>
>
>
?
>
>
﹦
<
பைடு நூலகம்
<
<
<
<
?
=
因为表达式中的数字占有多个连续字符,所以还需要将连续数字字符变为 Float 类型的
数字,在程序中面对错误的表达式还要返回“ERROR”信息,这些算法的实现详见程序代码 部分。
{ JButton curr = (JButton)e.getSource(); int i = 0; if(p && label.getText().length()<40)//这些按钮可用(p)且以输入字符长度小于40 { for( i=0 ; i<11 ; i++)//事件源为数字键按钮 if(curr == button_num[i]) { label.setText( label.getText() + button_num[i].getText()); break; } for( i=0 ; i<6 ; i++)//事件源为运算符按钮 if(curr == button_bol[i]) { label.setText( label.getText() + button_bol[i].getText()); break; } if(curr == button_bol[6])//事件源为„=‟按钮 { label.setText( label.getText() + button_bol[6].getText()); label.setText( label.getText() + EvaluateExpression()); p = false; } if(curr == button_fun[1] && label.getText().compareTo("")!=0)//事件源为„后退‟
button_fun[0] = new JButton("重置"); button_fun[1] = new JButton("后退"); button_fun[2] = new JButton("说明"); }//成员变量及其初始化
Expression()//构造方法,用于布局设计 {
int i = 0;
用户通过数字键和运算符按钮输入表达式并在 lable 控件中显示,当按下‘=’键的时候, 计算表达式的值并显示在显示控件中。由于用户在输入表达式的过程中存在这很多的不确定 因素,为了防止这些不确定因素引起的程序错误,对表达式的处理集中在用户按下‘=’按 钮的时候,同时其他按钮不可使用(‘重置’除外),点击‘重置’后方可继续使用。三个 功能键能够实现不同的功能,‘重置’可将已输入的内容清除,‘后退’可以向前删除一个 字符,‘说明’则在显示控件中显示说明内容。
相应的计算,并将计算结果压入 OPDN 栈内; c) 若是等于,则删除 OPTR 栈顶的元素,读取下一个字符。 5) 循环结束,返回 OPDN 栈顶元素,该元素为表达式的运算结果。 相继出现的运算符 a 和 b 之间的优先关系如下表,‘<’表示 a 的优先级低于 b,‘=’ 表示 a 与 b 的优先级相等,‘>’表示 a 的优先级高于 b,‘?’表示错误的运算符顺序:
在实例分析中提到在某些时刻有些按钮不能使用,这就需要一个 boolean 类型的成员变 p 量来确定这些按钮是否可以使用,其初始值为 true。当 p 为 true 的时候,所有的数字键、 运算符按钮和功能键中的后退键均可使用。这些按钮的功能都是对 lable 的内容进行修改, 数字键和运算符按钮在 lable 后添加该按钮表示的字符,‘后退’则删除 lable 末尾的一个字 符。
当进行按下‘=’键时,进行表达式的求值。表达式求值的过程参见数据结构与算法设 计部分。
三、 布局设计
如右图所示的布局方式, 整体分为三部分,使用三个 中间容器即可实现此种布局。 构造方法用于布局的实现, 在构造方法中申明和初始化 三个中间容器 p1、p2、p3, 其中 p1 存放显示控件,位于 窗体的上部;p2 存放数字键, 位于窗体的左部;p3 存放功能键和运算符按钮,位于窗体的右部。p1 使用 FlowLayout 布局, 并设置对齐方式为左对齐;p2 和 p3 使用 GridLayout 布局,网格规模分别为 4*3 和 3*3。窗 体布局使用 BorderLayout 布局,按图所示分别使 p1 在 NORTH 位置,p2 在 WEST 位置,p3 在 CENTER 位置。
p2.setLayout(new GridLayout(4,3)); for(i=1 ; i<10 ; i++)
p2.add(button_num[i]); p2.add(button_num[10]); p2.add(button_num[0]); p2.add(button_bol[6]);
p3.setLayout(new GridLayout(3,3)); for( i=0 ; i<3 ; i++)
{ for( int i=0 ; i<10 ; i++) button_num[i] = new JButton(""+i); button_num[10] = new JButton(".");
button_bol[0] = new JButton("+"); button_bol[1] = new JButton("-"); button_bol[2] = new JButton("×"); button_bol[3] = new JButton("÷"); button_bol[4] = new JButton("("); button_bol[5] = new JButton(")"); button_bol[6] = new JButton("﹦");
boolean p = true;
JLabel label = new JLabel();
JButton[] button_num = new JButton[11]; JButton[] button_bol = new JButton[7]; JButton[] button_fun = new JButton[3];
布局的方式有多种多样,读者可以有自己的创新,不局限与这一种布局方式。
四、 事件处理响应
通过实现 ActionListener 接口中的 public void actionPerformed(ActionEvent e)方法,将事 件处理全部集中在 actionPerformed(ActionEvent e)方法中。首先在构造方法中为所有的 JButton 对象添加监听器,在 actionPerformed(ActionEvent e)方法中,首先有一个 JButton 类 型的变量用来获取事件源的引用,然后程序根据事件源的不同做出不同的响应。
六、 程序代码
import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Expression extends JFrame implements ActionListener//继承JFrame类,实现 ActionListener接口 {
for( i=0 ; i<11 ; i++)//为所有的按钮添加监听器 button_num[i].addActionListener(this);
for( i=0 ; i<7 ; i++) button_bol[i].addActionListener(this);
for( i=0 ; i<3 ; i++) button_fun[i].addActionListener(this);
接着是将 lable 字符串通过 toCharArray()方法转换为字符数组。一个个地读取表达式中 的字符,根据不同的字符进行不同的处理,这个过程如下:
1) 建立并初始化 OPTR 和 OPND 栈,并将表达式起始符‘=’压入 OPTR 栈。 2) 依次读取表达式中的每个字符 ch,然后循环一下步骤,直到定位到最后一个字符
JPanel p1 = new JPanel(); JPanel p2 = new JPanel(); JPanel p3 = new JPanel();
FlowLayout flow = new FlowLayout(); flow.setAlignment(FlowLayout.LEFT); p1.setLayout(flow); p1.add(new JLabel("显示:")); p1.add(label);
setTitle("计算器"); setBounds(100, 100 , 350 , 220); setVisible(true); setResizable(false); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
public void actionPerformed(ActionEvent e)//实现ActionListener接口的actionPerformed方 法,用于事件处理响应
p3.add(button_fun[i]); for( i=0 ; i<6 ; i++)
p3.add(button_bol[i]);
add(p1 , BorderLayout.NORTH); add(p2 , BorderLayout.CENTER); add(p3 , BorderLayout.EAST);