实验题目及内容

在这里插入图片描述
注:嵌套布局需要灵活使用中间容器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下的可按照文件。
在这里插入图片描述
在这里插入图片描述

码字不易,都看到这里了不如点个赞哦~
我还写了很多文章,欢迎关注我哦~
在这里插入图片描述

亲爱的朋友,这里是我新成立的公众号,欢迎关注!
本博客的优秀博文也将陆续搬运到公众号,之后还将推出更多优秀博文,并将优先发在公众号,敬请期待!
关注起来,让我们一起成长!

在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐