Java编写计算器--学习笔记,附源码
目录实验题目及内容软件设计简易流程图实验流程图实验程序与结果实验结果分析和问题讨论实验题目及内容注:嵌套布局需要灵活使用中间容器JPanel软件设计简易流程图实验流程图实验程序与结果package counter;//引用包import java.awt.*;import java.awt.event.ActionEvent;import ja...
实验题目及内容
注:嵌套布局需要灵活使用中间容器JPanel
软件设计简易流程图
实验流程图
实验程序与结果
package counter; //引用包
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack;
import javax.swing.*;
//处理计算结果异常
class MyException extends Exception{ private static final long serialVersionUID = 1649159247013670200L;
public MyException() {
super(); }
public MyException(String message) {
super(message);
}
}
//将计算器的参数传递
class SwingConsole{
public static void run(final JFrame f,final int width,final int height){
//调用invokeLater来请求事件分发线程以运行某段代 码
//必须将这段代码放入一个Runnable对象的run方法中,并将该指定Runnable对象作为参数传递给invokeLater。
SwingUtilities.invokeLater(new Runnable(){
//invokeLater函数会立即返回,不会等到事件分发线程执行完这段代码。
public void run(){
f.setTitle(f.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(width,height);
f.setVisible(true);
}
});
}
}
public class calculator2 extends JFrame{
private static final long serialVersionUID = 1L; //定义变量
private JTextField textField; //输入文本框
private String input; //结果
private JButton button; //按钮
//在构造方法中重写,创建框架,创建组件,添加组件,以及给组件注册事件监听器
public calculator2() {
input = ""; //得到框架的内容窗格,才可以添加组件,使用默认的BorderLayout
Container container = this.getContentPane();
//创建中间容器JPanel
JPanel panel = new JPanel();
//创建文本框,指定单行长度
textField = new JTextField(30);
textField.setEditable(false); //文本框禁止编辑
textField.setHorizontalAlignment(JTextField.LEFT); //textField.setBounds(100, 100, 20, 20);
//在容器布局为空情况下生效
textField.setPreferredSize(new Dimension(200,30)); //使用add来添加组件,添加文本框到北部
container.add(textField, BorderLayout.NORTH);
String[] name=
{"1","2","3","+","4","5","6","-","7","8","9","*","0","C","=","/"}; //给中间容器设置布局管理器,GridLayout(4,4,1,1)设置行数,列数,组件水平距离,垂直距离
panel.setLayout(new GridLayout(4,4,1,1)); //将16个按钮放入JPanel
for(int i=0;i<name.length;i++) {
button = new JButton(name[i]); //给按钮添加事件监听器
button.addActionListener(new MyActionListener()); //添加按钮组件
panel.add(button); } //添加JPanel到中部
container.add(panel,BorderLayout.CENTER);
}
//继承事件适配器,重写事件监听器的方法
//内部类实现按钮响应,将输入值送入
class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
int cnt=0;
String actionCommand = e.getActionCommand(); //获取按钮上的字符串 //用equals函数来判断是否为符号,若是括号中的则为true
if(actionCommand.equals("+") ||
actionCommand.equals("-") ||
actionCommand.equals("*") ||
actionCommand.equals("/")) {
input += " " + actionCommand + " ";
}
//按下C清除输入
else if(actionCommand.equals("C")) {
input = "";
}
//按下等号,若有异常,则调用MyException
else if(actionCommand.equals("=")) {
try {
input+= "="+calculate(input); }
catch (MyException e1) {
if(e1.getMessage().equals("Infinity"))
input+= "=" + e1.getMessage();
else
input = e1.getMessage(); }
//文本框输出input
textField.setText(input);
//储存结果清零
input="";
//cnt置1表示计算结束
cnt = 1;
}
else//按下数字
input += actionCommand;
//cnt为零时,输入继续,储存之前的结果
if(cnt == 0)
textField.setText(input);
}
}
//借助栈来完成表达式的计算
private String calculate(String input) throws MyException{
//创建数组
String[] comput = input.split(" ");
//创建栈
Stack<Double> stack = new Stack<>();
//创建变量
Double m = Double.parseDouble(comput[0]);
//第一个操作数入栈
stack.push(m);
//将字符串分割成字符串数组,依次运算
for(int i = 1; i < comput.length; i++) {
//数组奇数位为运算符(从第0位开始),偶数位为操作数,因此可将偶数为操作数进栈,
if(i%2==1) {
//遇见+(-)运算符,则将下一个数以正(负)的形式压人栈中
if(comput[i].equals("+"))
stack.push(Double.parseDouble(comput[i+1]));
if(comput[i].equals("-"))
stack.push(-Double.parseDouble(comput[i+1]));
//遇见*或/运算符,则将栈顶元素出栈与数组后一元素进行计算,并将其结果重新压入栈中,直至遍历至数组最后一个元素。最后将栈中的元素进行求和。
if(comput[i].equals("*")) { Double d = stack.peek(); //取栈顶元素
stack.pop(); //将栈顶元素出栈
stack.push(d*Double.parseDouble(comput[i+1]));//做乘法再入栈 }
if(comput[i].equals("/")) {
//将前一个数出栈做乘法再入栈
double help = Double.parseDouble(comput[i+1]);
if(help == 0)
throw new MyException("Infinity"); //若0是除数,不会继续执行该函数
double d = stack.peek();
stack.pop();
stack.push(d/help);
}
}
}
//将栈中元素求和
double d = 0d;
while(!stack.isEmpty()) {
d += stack.peek();
stack.pop();
}
//强制转换类型为字符,返回结果
String result = String.valueOf(d);
return result;
}
//main方法
public static void main(String[] args) {
//创建计算机,并且设置长宽
SwingConsole.run(new calculator2(), 250, 300);
}
}
之后不满意之前的设置,又进一步升级了计算器
package counter;
//引用包
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack;
import javax.swing.*;
//处理计算结果异常
class MyException extends Exception{
private static final long serialVersionUID = 1649159247013670200L;
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}
//将计算器的参数传递
class SwingConsole{
public static void run(final JFrame f,final int width,final int height){
//调用invokeLater来请求事件分发线程以运行某段代 码
//必须将这段代码放入一个Runnable对象的run方法中,并将该指定Runnable对象作为参数传递给invokeLater。
SwingUtilities.invokeLater(new Runnable(){
//invokeLater函数会立即返回,不会等到事件分发线程执行完这段代码。
public void run(){
f.setTitle(//f.getClass().getSimpleName() "计算器");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(width,height);
f.setVisible(true);
}
});
}
}
public class calculator2 extends JFrame{
private static final long serialVersionUID = 1L;
//定义变量
private JTextField textField; //输入文本框
private String input; //结果
private JButton button; //按钮
private JLabel jlabel;
//在构造方法中重写,创建框架,创建组件,添加组件,以及给组件注册事件监听器
public calculator2() {
//由于在线程设置里设置了title,所以这里不用再设计
super("计算器");
//在屏幕上显示计算器的位置为(500, 300)
this.setLocation(500, 300);
input = "";
//得到框架的内容窗格,才可以添加组件,使用默认的BorderLayout
Container container = this.getContentPane();
//创建中间容器JPanel
JPanel panel = new JPanel();
//设置颜色
this.setBackground(Color.blue);
//创建文本框,指定单行长度
textField = new JTextField(30);
textField.setEditable(false); //文本框禁止编辑
textField.setHorizontalAlignment(JTextField.LEFT);
//textField.setBounds(100, 100, 20, 20); //在容器布局为空情况下生效
textField.setPreferredSize(new Dimension(200,30));
//设置文本框颜色
textField.setBackground(Color.WHITE);
//使用add来添加组件,添加文本框到北部
container.add(textField, BorderLayout.NORTH);
//添加标题
jlabel = new JLabel("DESIGN BY **",JLabel.CENTER);
container.add(jlabel,BorderLayout.SOUTH);
String[] name=
{"1","2","3","+","4","5","6","-","7","8","9","*","0","C","=","/"};
//给中间容器设置布局管理器,GridLayout(4,4,1,1)设置行数,列数,组件水平距离,垂直距离
panel.setLayout(new GridLayout(4,4,1,1));
//将16个按钮放入JPanel
for(int i=0;i<name.length;i++) {
button = new JButton(name[i]);
//给按钮添加事件监听器
button.addActionListener(new MyActionListener());
//添加按钮组件
panel.add(button);
if((i==3)||(i==7)||(i==11)||(i==14)||(i==15))button.setBackground(Color.RED);
if(i==14)button.setBackground(Color.GREEN);
}
//添加JPanel到中部
container.add(panel,BorderLayout.CENTER);
String[] name2= {"%","1/X","sqrt"};
JPanel panel2 = new JPanel();
panel2.setLayout(new GridLayout(3,1,1,1));
//将16个按钮放入JPanel
for(int i=0;i<name2.length;i++) {
button = new JButton(name2[i]);
//给按钮添加事件监听器
button.addActionListener(new MyActionListener());
//添加按钮组件
button.setBackground(Color.RED); panel2.add(button); }
//添加JPanel到中部
container.add(panel2,BorderLayout.EAST);
}
//继承事件适配器,重写事件监听器的方法
//内部类实现按钮响应,将输入值送入
class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
int cnt=0;
String actionCommand = e.getActionCommand();
//获取按钮上的字符串
//用equals函数来判断是否为符号,若是括号中的则为true
if(actionCommand.equals("+") || actionCommand.equals("-") ||
actionCommand.equals("*")
|| actionCommand.equals("/")||actionCommand.equals("%"))
{
input += " " + actionCommand + " ";
}
//按下C清除输入
else if(actionCommand.equals("C")) {
input = "";
}
//按下1/x求相反数
else if(actionCommand.equals("1/X")) {
input += " " + actionCommand + " ";
}
//按下sqrt求相反数
else if(actionCommand.equals("sqrt")) { input += " " + actionCommand + " "; }
//按下等号,若有异常,则调用MyException
else if(actionCommand.equals("=")) {
try {
input+= "="+calculate(input);
} catch (MyException e1) {
if(e1.getMessage().equals("Infinity"))
input+= "=" + e1.getMessage();
else
input = e1.getMessage();
}
//文本框输出input
textField.setText(input);
//储存结果清零
input="";
//cnt置1表示计算结束
cnt = 1;
}
else//按下数字
input += actionCommand;
//cnt为零时,输入继续,储存之前的结果
if(cnt == 0)
textField.setText(input);
}
}
//借助栈来完成表达式的计算
private String calculate(String input) throws MyException{
//创建数组
String[] comput = input.split(" ");
//创建栈
Stack<Double> stack = new Stack<>();
//创建变量
Double m = Double.parseDouble(comput[0]);
//第一个操作数入栈
stack.push(m);
//将字符串分割成字符串数组,依次运算
for(int i = 1; i < comput.length; i++) {
//数组奇数位为运算符(从第0位开始),偶数位为操作数,因此可将偶数为操作数进栈,
if(i%2==1) {
//遇见+(-)运算符,则将下一个数以正(负)的形式压人栈中
if(comput[i].equals("+"))
stack.push(Double.parseDouble(comput[i+1]));
if(comput[i].equals("-"))
stack.push(-Double.parseDouble(comput[i+1]));
//遇见*或/运算符,则将栈顶元素出栈与数组后一元素进行计算,并将其结果重新压入栈中,直至遍历至数组最后一个元素。最后将栈中的元素进行求和。
if(comput[i].equals("*")) {
Double d = stack.peek(); //取栈顶元素
stack.pop(); //将栈顶元素出栈
stack.push(d*Double.parseDouble(comput[i+1]));//做乘法再入栈
}
if(comput[i].equals("/")) {
//将前一个数出栈做乘法再入栈
double help = Double.parseDouble(comput[i+1]);
if(help == 0)
throw new MyException("Infinity"); //若0是除数,不会继续执行该函数
double d = stack.peek();
stack.pop();
stack.push(d/help);
}
if(comput[i].equals("%")) {
double help = Double.parseDouble(comput[i+1]);
if(help == 0)
throw new MyException("Infinity"); //若0是除数,不会继续执行该函数
double d = stack.peek(); //取栈顶元素
stack.pop(); //将栈顶元素出栈
stack.push(d%Double.parseDouble(comput[i+1]));//做求余再入栈
}
if(comput[i].equals("sqrt")) {
Double d = stack.peek(); //取栈顶元素
stack.pop(); //将栈顶元素出栈
stack.push(Math.sqrt(d));//做乘法再入栈
}
if(comput[i].equals("1/X")) {
double help = Double.parseDouble(comput[i-1]);
if(help == 0)
throw new MyException("Infinity"); //若0是除数,不会继续执行该函数
else{
double d = stack.peek(); //取栈顶元素
stack.pop(); //将栈顶元素出栈
stack.push(1/d);}//做求余再入栈
}
}
}
//将栈中元素求和
double d = 0;
while(!stack.isEmpty()) {
d += stack.peek();
stack.pop();
}
//强制转换类型为字符,返回结果
String result = String.valueOf(d);
return result;
}
//main方法
public static void main(String[] args) {
//创建计算机,并且设置长宽
SwingConsole.run(new calculator2(), 250, 300);
}
}
实验结果分析和问题讨论
1.当开发了一个应用程序后,这个应用程序包含了很多类,如果需要把这个应用程序提供给别人使用,通常会将这些类文件打包成一个JAR文件,把这个JAR文件提供给别人使用。只要别人在系统的CLASSPATH环境变量中添加这个JAR文件,则Java虚拟机就可以自动在内存中解压这个JAR包,把这个JAR文件当成一个路径,在这个路径中查找所于晓的类或宝层次对应的路径结构。
2.第一次用java写一个GUI,是挺累的。但是仔细看书后,知道了该编程GUI的几个环节和步骤:1引入包和类2设置顶层容器3设置布局管理器4将组件添加入容器5为相应的事件编写事件监听器的方法
3.麻烦的是,使用了嵌套布局,用BorderLayout布局面板,显示框放容器北部,整个按钮面板放容器中部。显示框是一个JTextFiled组件,按钮面板是一个JPanel组件存放16个JButton组件,且它的布局是4x4的网格布局(GridLayout)。
4之后在编程计算器的时候,也就是对事件监听器内部方法重写,由于继承的是适配器,所以只重写了一个方法,将输入的运算符和数字存入并且计算,当检测到“=”时输出结果并清零。
5之后运算的时候,运用到了栈这种数据结构,首先将字符串分割成字符串数组,数组奇数位为运算符(从第0位开始),偶数位为操作数,因此可将偶数为操作数进栈,遇见+(-)运算符,则将下一个数以正(负)的形式压人栈中,遇见*或/运算符,则将栈顶元素出栈与数组后一元素进行计算,并将其结果重新压入栈中,直至遍历至数组最后一个元素。最后将栈中的元素进行求和。
6注意到,在事件处理和计算的过程中,还使用了异常处理,这是很好的思想。
7通过在网上查阅资料,使用了线程的方法,调用invokerLater来请求事件分发线程来运行这段代码。但是必须将这段代码放入Runnable对象中的run方法中,并将该对象作为参数传递给invokerLater。这样的话,就直接可以在main方法里传递参数创建对象了。
8. 这次第一次写这样的代码,开始有点发虚,后来查阅书本以及在网上找了很多资料,明白了代码的思路,对GUI的编程,以及用栈来写计算器,异常处理,以及一些线程的思想,真的是受益匪浅。所谓抄袭是把别人的东西百分百拿过来,创新就是把百分之九十九抄袭,然后加上百分之一的自己的东西。所谓代码,就是别人的拿过来,看懂学会,然后自己去写,再加上自己的东西,这就算完成了。以后有这样的机会,还是要多练习,Java很有趣,我很喜欢Java。
9. 最后将java文件打包成jar文件,再用exe4j生成.exe文件,这样的话点击是可以运行的,但如果要在其他电脑运行,则每次都要把jre文件和exe一起复制到其他电脑上。所以下一步就是把exe文件和jre用innosetup编译成在windows下的可按照文件。
码字不易,都看到这里了不如点个赞哦~
我还写了很多文章,欢迎关注我哦~
亲爱的朋友,这里是我新成立的公众号,欢迎关注!
本博客的优秀博文也将陆续搬运到公众号,之后还将推出更多优秀博文,并将优先发在公众号,敬请期待!
关注起来,让我们一起成长!
更多推荐
所有评论(0)