黑马程序员——自学总结(七)图形用户界面GUI

<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流!

一、概述

        GUI(Graphical User Interface)图形用户接口,用图形的方式,来显示计算机操作的界面,这样更方便更直观。CLI (Command  Line User Interface)命令行用户接口,就是常见的Dos命令行操作,需要记忆一些常用的命令,操作不直观。Java为GUI提供的对象都存在java.awt和javax.Swing两个包中。java.awt(abstract window toolkit)抽象窗口工具包,需要调用本地系统方法实现功能,属重量级控件,依赖于平台。 javax.Swing是在awt的基础上建立的一套图形界面系统,其中提供了更多的组件,而且完全由java实现,增强了移植性,属轻量级控件,包含的类完全基于awt,有些直接继承自awt,覆写了其中的方法。

        组件体系图

二、布局管理器

        容器中的组件的排放方式,就是布局。常见的布局管理器:FlowLayout流式布局管理器,从左到右的顺序排列,FlowLayout是Panel默认的布局管理器,BorderLayout边界布局管理器,将整个界面分为东南西北中五个部分,添加组件时可指定方位,默认居中且全部填充,再使用默认方位添加就覆盖,BorderLayout是Frame默认的布局管理器,GridLayout网络布局管理器,将整个界面规则的分成矩阵形式,CardLayout卡片布局管理器,就是选项卡,GridBagLayout网络包布局管理器,将真个界面不规则的分成多个矩阵形式。最方便的布局管理器是坐标式布局管理器,可精确至具体坐标位置添加组件,在有的开发工具里提供该类布局管理器。

        当界面上下布局不一致时,先设置窗体总体布局,再添加Panel,在Panel中再设置某一部分的布局。

三、Frame

        java.awt中的Frame类,内部封装了一个集合,可以用add()方法添加组件。setVisible(true)设置窗体可见,默认不可见。setSize(宽度,高度)设置窗体的大小。setLocation(int x,int y)x是距左上角横坐标,y是距左上角纵坐标),设置窗体位置。 setLayout()设置窗体布局管理器,setBounds(int x,int y,int width,int height)一次性设置窗体的位置和大小。

       创建图形化界面的步骤:1、创建Frame窗体;2、对窗体进行基本设置,比如大小,位置,布局;3、定义组件;4、将组件通过窗体的add()方法添加到窗体中;4、让窗体显示,通过setVisible(true)。图形化界面是由另外一个前台线程控制的。

四、事件监听机制

        事件监听机制的组成包括:事件源(组件),事件(Event),监听器(Listener),事件处理(引发事件后处理方式)。事件源就是awt包或者swing包中的那些图形界面组件,每一个事件源都有自己的特有的对应事件和共性事件,监听器将可以触发某一个事件的动作(不止一个动作)都已经封装到了监听器中。以上三者在java中都已经定义好了,直接获取其对象来用就可以了。我们要做的事情是对产生的动作进行处理。

三、窗体事件

        addWindowListener(WindowListener l)为窗体注册监听器,因为WindowListener的子类WindowAdapter已经实现WindowListener接口,并用空函数的方式覆盖了其中的所有方法,那么我只要继承自WindowAdapter覆盖我需要的方法即可,可用匿名内部类格式。

        覆盖窗体关闭方法public void windowClosing(WindowEvent e){ } 需导入事件包import java.awt.event.*;

        覆盖窗体活动方法public void windowActivated(WindowEvent e) { } 当窗体为当前活动窗体时调用该方法

        覆盖窗体打开方法public void windowOpened(WindowEvent e) { } 窗体打开时执行,只执行一次

        下面的程序演示了创建一个窗体对象,并在窗体中添加一个按钮,窗体打开时,控制台打印“窗体打开”,窗体活动时,控制台打印“窗体活动”,关闭窗体后程序退出:

          

import java.awt.*;
import java.awt.event.*;
class GUIdemo{
	private Frame f;
	private Button b;
	public GUIdemo(){
		init();
	}
	public void init(){
		f=new Frame();
		f.setBounds(300,100,600,500);
		b=new Button("我的按钮");
		f.add(b);
		f.setLayout(new FlowLayout());
		myevent();
		f.setVisible(true);
	}
	public void myevent(){
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
			public void windowActivated(WindowEvent e){
				System.out.println("窗体活动");
			} 
			public void windowOpened(WindowEvent e){
				System.out.println("窗体打开");
				
			}
		});	
	}
	public static void main(String[] args){
		new GUIdemo();
	}
}


该程序第一次打开时,显示“窗体活动”,“窗体打开”,我认为是在init()函数中调用f.setVisible(true)时,系统先调用到f的方法,窗体活动一次,显示“窗体活动”,窗体全部显示完毕,显示“窗体打开”。关闭后又打印一次“窗体活动”,我认为同样是因为系统调用到f的方法导致的。

 四、Action事件

        现在让按钮具备退出程序的功能,按钮就是事件源,通过查阅button的描述,发现按钮支持一个特有监听ActionListener,注册方法addActionListener(ActionListener l), ActionListener是少数没有适配器的接口之一,接口方法actionPerformed(ActionEvent e)。当组件为当前对象,无论是鼠标还是键盘激活,即引发actionPerformed(ActionEvent e)方法。

 

import java.awt.*;
import java.awt.event.*;
class GUIdemo{
	private Frame f;
	private Button b;
	public GUIdemo(){
		init();
		myevent();
	}
	public void init(){
		f=new Frame();
		f.setBounds(300,100,600,500);
		b=new Button("我的按钮");
		b.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				System.exit(0);
			}
		});
		f.add(b);
		f.setLayout(new FlowLayout());
		f.setVisible(true);
	}
	public void myevent(){
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});	
	}
	public static void main(String[] args){
		new GUIdemo();
	}
}


五、鼠标、键盘事件

       几乎所有组件都响应鼠标和键盘事件。

       1、鼠标事件

            在Component接口里有注册鼠标事件监听器的方法addMouseListener(MouseListener l),MouseListener接口有适配器MouseAdapter,一般我们要覆写其中的鼠标进入、点击、离开、按下、释放方法

            public void mouseEntered(MouseEvent e){ } 鼠标进入组件引发

            public void mouseClicked(MouseEvent e){ }鼠标点击时引发, 通过e.getClickCount()获得鼠标点击次数,可判断单击还是双击,MouseEvent中有三个常量BUTTON1、BUTTON2、BUTTON3,分别代表鼠标左键、右键和中建,可通过getButton()方法返回

            public void mouseExited(MouseEvent e){ }鼠标离开时引发

            public void mousePressed(MouseEvent e){ }鼠标按下时引发

            public void mouseReleased(MouseEvent e){ } 鼠标在按在组件上释放时引发

           按钮Button对象可以注册活动事件监听器addActionListener(ActionListener l);来响应活动事件,同时也可以注册鼠标事件监听器响应鼠标事件,当两者都注册时,鼠标事件先执行,活动事件后执行,鼠标和键盘都能触发活动事件。

       2、键盘事件

            添加键盘事件监听器addKeyListener(KeyListener l);一般继承KeyListener接口的适配器KeyAdapter,覆写方法:

             public void keyPressed(KeyEvent e)键盘按下时触发,调用e.getKeyChar() 获得按键字符,e.getKeyCode()返回按键码 ,键码都设置成常量封装在KeyEvent类中,有一个小问题:当按下Shift键时,e.getKeyChar() 无法返回连串字符,可用静态方法KeyEvent.getKeyText(e.KeyCode())返回字符串。           

             public void keyReleased(KeyEvent e)键盘按下后释放时触发

             public void keyTyped(KeyEvent e)键入某个键时触发

             演示按下ESC键,程序退出。ESC键keycode值是27,或者用常量KeyEvent.VK_ESCAPE表示。

import java.awt.*;
import java.awt.event.*;
class GUIdemo{
	private Frame f;
	private Button b;
	public GUIdemo(){
		init();
		myevent();
	}
	public void init(){
		f=new Frame();
		f.setBounds(300,100,600,500);
		b=new Button("我的按钮");
		b.addKeyListener(new KeyAdapter(){
			public void keyPressed(KeyEvent e){
				if(e.getKeyCode()==KeyEvent.VK_ESCAPE)
						System.exit(0);			
			}
		});
		f.add(b);
		f.setLayout(new FlowLayout());
		f.setVisible(true);
	}
	public void myevent(){
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});	
	}
	public static void main(String[] args){
		new GUIdemo();
	}
}

如果想要按下ctrl+回车键退出,可以将判断条件改为e.isControlDown() && e.getKeyCode()==KeyEvent.VK_ENTER。

             演示TextField中添加键盘监听器,覆写按键按下方法,当e.getKeyCode()>=KeyEvent.VE_0 &&e.getKeyCode()<=KeyEvent.VE_9时存储到文本框中,其它不存储。程序中需要调用 e.consume()方法取消默认处理方式,因为KeyEvent 的父类 InputEvent是连续事件,默认是键盘按下并输入。

代码如下:

import java.awt.*;
import java.awt.event.*;
import java.io.*;
class GUIdemo{
	private Frame f;
	private Button b;
	private TextField t;
	private TextArea ta;
	public GUIdemo(){
		init();
		myevent();
	}
	public void init(){
		f=new Frame();
		f.setBounds(300,100,600,500);
                t=new TextField(30);
                ta=new TextArea(20,50);
		t.addKeyListener(new KeyAdapter(){
			public void keyPressed(KeyEvent e){
				if(e.getKeyCode()==KeyEvent.VK_ENTER){
					ta.setText("");
					String dir=t.getText();
					File file=new File(dir);
					if(file.exists() && file.isDirectory()){
						int level=0;
						show(file,ta,level);
					}
					else
						ta.setText("文件路径非法或不存在");
				}
			}
		});
		b=new Button("显示");
		b.addMouseListener(new MouseAdapter(){
			public void mouseClicked(MouseEvent e){
				ta.setText("");
				String dir=t.getText();
				File file=new File(dir);
				if(file.exists() && file.isDirectory()){
					int level=0;
					show(file,ta,level);
				}
				else
					ta.setText("文件路径非法或不存在");
			}
		});
		f.add(t);
		f.add(b);
		f.add(ta);
		f.setLayout(new FlowLayout());
		f.setVisible(true);
	}
	public void myevent(){
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});	
	}
	private void show(File file,TextArea ta,int level){
		level++;	
		if(file.isDirectory()){
			for(int i=0;i<level-1;i++)
				ta.append("—");
			ta.append(file.getName()+"\r\n");
			File[] files=file.listFiles();
			for(File f:files)
				show(f,ta,level);
		}else{
			for(int i=0;i<level-1;i++)
				ta.append("—");
			ta.append(file.getName()+"\r\n");	
		}		
	}
	public static void main(String[] args){
		new GUIdemo();
	}
}



程序运行显示结果如下:

六、对话框

       上个练习中,如果文件路径错误,要有处理方式,可以使用对话框,对话框Dialog与Frame同属于Window,子类有FileDialog,Dialog构造函数里要有Frame对象。编程时等到出现错误的时候再new 对话框,避免内存浪费。

      对话框是窗体,可以用add()方法添加组件,对话框构造函数中如果指定逻辑型参数为true,则该对话框为强制型对话框,用户不做出响应操作,将无法进行其他操作。

      对话框关闭事件内容一般设置对话框不可见。

      修改上例代码:

   

import java.awt.*;
import java.awt.event.*;
import java.io.*;
class GUIdemo{
	private Frame f;
	private Button b;
	private TextField t;
	private TextArea ta;
	private Dialog d;
	private Label l;
	public GUIdemo(){
		init();
		myevent();
	}
	public void init(){
		f=new Frame();
		f.setBounds(300,100,600,500);
                t=new TextField(30);
                ta=new TextArea(20,50);
		t.addKeyListener(new KeyAdapter(){
			public void keyPressed(KeyEvent e){
				if(e.getKeyCode()==KeyEvent.VK_ENTER){
					ta.setText("");
					String dir=t.getText();
					File file=new File(dir);
					if(file.exists() && file.isDirectory()){
						int level=0;
						show(file,ta,level);
					}
					else{
						d=new Dialog(f,"提示信息",true);
						d.setBounds(500,350,200,200);
						l=new Label("文件路径非法或不存在,请重新输入!");
						d.add(l);
						d.addWindowListener(new WindowAdapter(){
							public void windowClosing(WindowEvent e){
								d.setVisible(false);
							}
						});
						d.setVisible(true);		
					}
				}
			}
		});
		b=new Button("显示");
		b.addMouseListener(new MouseAdapter(){
			public void mouseClicked(MouseEvent e){
				ta.setText("");
				String dir=t.getText();
				File file=new File(dir);
				if(file.exists() && file.isDirectory()){
					int level=0;
					show(file,ta,level);
				}
				else{
					d=new Dialog(f,"提示信息",true);
					d.setBounds(500,350,200,200);
					l=new Label("文件路径非法或不存在,请重新输入!");
					d.add(l);
					d.addWindowListener(new WindowAdapter(){
						public void windowClosing(WindowEvent e){
							d.setVisible(false);
						}
					});
					d.setVisible(true);		
				}	
			}
		});
		f.add(t);
		f.add(b);
		f.add(ta);
		f.setLayout(new FlowLayout());
		f.setVisible(true);
	}
	public void myevent(){
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});	
	}
	private void show(File file,TextArea ta,int level){
		level++;	
		if(file.isDirectory()){
			for(int i=0;i<level-1;i++)
				ta.append("—");
			ta.append(file.getName()+"\r\n");
			File[] files=file.listFiles();
			for(File f:files)
				show(f,ta,level);
		}else{
			for(int i=0;i<level-1;i++)
				ta.append("—");
			ta.append(file.getName()+"\r\n");	
		}		
	}
	public static void main(String[] args){
		new GUIdemo();
	}
}


 程序运行结果如下:

七、菜单 

       MenuBar菜单条 ,用setMenuBar(MenuBar)可以为frame设置菜单,菜单条中可以添加菜单Menu,菜单Menu当中可以添加菜单项MenuItem或菜单(子菜单,Menu就是MenuItem的子类),Menu显示时右边有箭头,MenuItem没有,MenuItem可以添加活动监听器。

八、练习

       打开、保存文件,FileDialog有各种类型,模式FileDialog.LOAD指定打开系统的打开文件对话框,模式FileDialog.SAVE指定打开系统的保存文件对话框,不指定模式默认是打开文件对话框。文件对话框的getDirectory()和getFile()可分别获取选择的文件路径和文件名。

代码如下:

import java.awt.*;
import java.awt.event.*;
import java.io.*;
class GUIdemo2{
	private Frame f;
	private TextArea ta;
	private FileDialog fd;
	private MenuBar mb;
	private MenuItem item1,item2,quit;
	private Menu menu;
	public GUIdemo2(){
		init();
		myevent();
	}
	public void init(){
		f=new Frame();
		f.setBounds(300,100,600,500);
		mb=new MenuBar();
		menu=new Menu("文件");
		item1=new MenuItem("打开");
		item1.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				fd=new FileDialog(f,"打开",FileDialog.LOAD);
				fd.setVisible(true);
				String path=fd.getDirectory();
				String name=fd.getFile();
				if(path==null || name==null)
					return;
				ta.setText("");
				File file=new File(path,name);
				BufferedReader br=null;
				try{
					br=new BufferedReader(new FileReader(file));
				}catch(IOException e1){
					throw new RuntimeException(e1);
				}
				try{
					String buff=null;
					while((buff=br.readLine())!=null)
						ta.append(buff+"\r\n");
				}catch(IOException e2){
					throw new RuntimeException(e2);
				}
			}
		});
		item2=new MenuItem("保存");
		item2.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				fd=new FileDialog(f,"保存",FileDialog.SAVE);
				fd.setVisible(true);
				String path=fd.getDirectory();
				String name=fd.getFile();
				if(path==null || name==null)
					return;
				File file=new File(path,name);
				BufferedWriter bw=null;
				try{
					bw=new BufferedWriter(new FileWriter(file));
				}catch(IOException e1){
					throw new RuntimeException(e1);
				}
				try{
					bw.write(ta.getText());
					bw.close();
				}catch(IOException e2){
					throw new RuntimeException(e2);
				}
			}
		});
		quit=new MenuItem("退出");
		quit.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				System.exit(0);
			}
		});
		menu.add(item1);menu.add(item2);menu.add(quit);
		mb.add(menu);
                ta=new TextArea(20,50);
		f.add(ta);
		f.setMenuBar(mb);
		f.setVisible(true);
	}
	public void myevent(){
		f.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});	
	}
	public static void main(String[] args){
		new GUIdemo2();
	}
}

九、jar包双击运行

        带包编译命令格式:javac -d  包存放的路径  源文件 ,打成jar包命令格式: jar -cvf    jar包名 包名

        jar包打好后,要编辑jar包里的配置文件信息,新建一文本文件,输入内容Main-Class:包名.主函数所在的类名(Main-Class后有空格,最后有回车),再输入命令jar -cvfm jar包名 配置信息所在的文本文件名 包名,双击生成的jar文件,可直接运行。

        注意:要先在系统中注册jar文件,设置打开jar文件的应用程序javaw.exe -jar。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值