38Java GUI(图形用户接口)---全解

1.Swing概述

  • Swing是一种轻量级组件,底层一AWT(抽象窗口工具包)为基础。在实际开发中,更多的是使用Swing进行图形用户界面开发。但是Swing并不是AWT的替代品,而是在原有的AWT的基础上进行了补充和改进。
  • Swing组件的所有类都继承自Container类,然后根据GUI开发的功能扩展了两个主要分支:容器分支(包括Window窗口和Panel面板)和组件分支。其中,容器分支就是为了实现图形用户界面窗口容器设计的,而组件分支则是为了实现向容器中填充数据、元素以及人际交互组件等功能。

2.Swing顶级容器

JFrame

  • 在Swing组件中,最常见的一个容器就是JFrame,它是一个独立存在的顶级容器(也叫窗口),不能放置在其他容器之中,JFrame支持通过窗口所有的基本功能,例如窗口最小化、设定窗口大小等。
package gui;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Example01 {
	private static void creatAndshowGUI() {
		//创建并设置JFrame容器窗口
		JFrame frame = new JFrame("JFrameTest");
		//设置关闭窗口时的默认操作
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//设置窗口尺寸
		frame.setSize(250, 150);
		//展示JFrame容器窗口
		frame.setVisible(true);

	}
	public static void main(String[] args) {
		//使用SwingUtilities工具类调用creatAndshowGUI()方法显示GUI程序
		SwingUtilities.invokeLater(Example01::creatAndshowGUI);
	}

}

JDialog

  • JDialog是Swing的另外一个顶级容器,通常用来表示对话框窗口。JDialog对话框可分为两种:模态对话框(用户需要等到处理完对话框后才能继续与其他窗口交互)和非模态对话框(允许用户在处理对话框的同时与其他窗口交互)
  • 对话框是模态或者是非模态,可以在创建JDialog对象时为构造方法传入参数来设置,也可以在创建JDialog对象后调用它的setModal()方法来进行设置,JDialog常用的构造方法如下
方法声明 功能描述
JDialog(Frame owner) 构造方法,用来创建一个非模态的对话框,owner为所有对话框所有者(顶级窗口JFrame)
JDialog(Frame owner,String title) 构造方法,创建一个具有指定标题的非模态对话框
JDialog(Frame owner,boolean modal) 创建一个指定模式的无标题对话框
  • 上表列举了JDialog三个常用的构造方法,在这三个构造方法中都需要接收一个Frame类型的对象,表示对话框所有者。第三个构造方法中,参数modal用来指定JDialog窗口是模态还是非模态,如果modal值设置为true,对话框就是模态对话框,反之则是非模态对话框,如果不设置modal的值,其默认值为false,也就是非模态对话框
package gui;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Example02 {
	private static void creatAndshowGUI() {
		//创建并设置JFrame容器窗口
		JFrame frame = new JFrame("JFrameTest");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(350, 150);
		frame.setVisible(true);
		//在JFrame窗口基础上创建并设置JDialog容器窗口
		JDialog dialog = new JDialog(frame,"JDialog对话框",true);
		dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
		dialog.setSize(200, 100);
		dialog.setVisible(true);
	}
	
	public static void main(String[] args) {
		//使用SwingUtilities工具类调用creatAndshowGUI()方法显示GUI程序
				SwingUtilities.invokeLater(Example02::creatAndshowGUI);
	}

}

  • 虽然JFrame和JDialog都可创建顶级容器窗口,但JDialog创建的窗口并没有放大和缩小功能。另外,由于创建JDialog容器对象时,设置的模态参数modal为true,所以在操作时,必须先关闭JDialog对话框后才可以与JFrame窗口进行交互

3.布局管理器

Swing组件不能单独存在,必须放置于容器当中,而组件在容器中的位置和尺寸是由布局管理器来决定的。Swing工具在AWT的基础上提供了8种布局管理器,分别为BorderLayout(边界布局管理器)、BoxBagLayout(箱式时布局管理器)、CardLayout(卡片布局管理器)、FlowLayout(流式布局管理器)、GridBagLayout(网格包布局管理器)、GridLayout(网格布局管理器)、GroupLayout(分组布局管理器)、SpringLayout(弹性布局管理器)

BorderLayout

  • BorderLayout(边界布局管理器)是一种较为复杂的布局方式,它将容器化分为5个区域,分别是页头(PAGE_START)、页尾(PAGE_END)、行首(LINE_START)、行尾(LINE_END)、中部(CENTER),组件可以被放置在这5个区域中的任意一个位置
  • 当向BorderLayout布局管理器的容器中添加组件时,需要使用add(Component comp, Object constraints)方法,其中参数comp表示要添加的组件,constraints指定将组件添加到布局中的位置,它是一个Object类型,再传参时可以使用页头(PAGE_START)、页尾(PAGE_END)、行首(LINE_START)、行尾(LINE_END)、中部(CENTER)设置组件位置
package gui;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Example03 {
	private static void creatAndShowGUI() {
		//创建一个名为BorderLayout的顶级容器窗口
		JFrame f = new JFrame("BorderLayout");
		//设置窗口中的布局管理器为BorderLayout
		f.setLayout(new BorderLayout());
		f.setSize(300, 300);
		f.setLocation(300, 200);
		//下面的代码是创建5个按钮组件
		JButton but1 = new JButton("PAGE_START");
		JButton but2 = new JButton("PAGE_END");
		JButton but3 = new JButton("LINE_START");
		JButton but4 = new JButton("LINE_END");
		JButton but5 = new JButton("CENTER");
		//下面的代码是将创建好的按钮添加到窗体中,并设置按钮所在的区域
		f.add(but1,BorderLayout.PAGE_START);
		f.add(but2,BorderLayout.PAGE_END);
		f.add(but3,BorderLayout.LINE_START);
		f.add(but4,BorderLayout.LINE_END);
		f.add(but5,BorderLayout.CENTER);
		//设置窗体可见
		f.setVisible(true);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
    public static void main(String[] args) {
    	//使用SwingUtilities工具类调用creatAndshowGUI()方法显示GUI程序
		SwingUtilities.invokeLater(Example03::creatAndShowGUI);
    }
}

  • 在使用add(Component comp.Object constraints)方法向容器区域中添加指定组件和位置时除了可以使用前面介绍的,还可以使用NORTH,SOUTH,EAST,WEST和CENTER

FlowLayout

FlowLayout(流式布局管理器)是最简单的布局管理器,在这种布局下,容器会将组件按照添加顺序从左向右放置,当达到容器边界时,会自动将组件放到下一行的开始位置,这些组件可以按左对齐、居中对齐(默认方式)或右对齐的方式排列。FlowLayout类有三个构造方法,如下所示

方法声明 功能描述
FlowLayout() 组件默认居中对齐,水平,垂直间距默认为5个单位
FlowLayout(int align) 指定组件相对于容器的对齐方式,水平、垂直间距默认为5个单位
FlowLayout(int align,int hgap,int vgap) 指定组件的对齐方式和水平、垂直间距
  • 上表中列出了FlowLayout的三个构造方法,其中参数align决定组件在每行中相对于容器边界的对齐方式,分别为左对齐,右对齐,居中对齐,可以使用该类中提供的常量FlowLayout.LEFT、FlowLayout.RIGHT、FlowLayout.CENTER表示。参数hgap和参数vgap分别设定组件之间的水平间距和垂直间距,可以填入一个任意数值
package gui;
import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Example04 {
	private static void creatAndShowGUI() {
		//创建一个名为FlowLayout的顶级容器窗口
		JFrame f = new JFrame("FlowLayout");
		//设置窗口中的布局管理器为FlowLayout
		//所有组件左对齐,水平间距为20,垂直间距位30
		f.setLayout(new FlowLayout(FlowLayout.LEFT,20,30));
		f.setSize(400, 200);
		f.setLocation(300, 200);
		//向容器中添加组件
		f.add(new JButton("第1个按钮"));
		f.add(new JButton("第2个按钮"));
		f.add(new JButton("第3个按钮"));
		f.add(new JButton("第4个按钮"));
		f.add(new JButton("第5个按钮"));
		//设置窗体可见
		f.setVisible(true);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
    public static void main(String[] args) {
    	//使用SwingUtilities工具类调用creatAndshowGUI()方法显示GUI程序
		SwingUtilities.invokeLater(Example04::creatAndShowGUI);
    }
}

GridLayout

GridLayout(网格布局管理器)使用纵横线将容器分割成n行m列大小相等的网格,每个网格中可以添加一个组件。添加到容器中的组件首先放置在第一行第一列(左上角)的网络中,然后再第一行的网格中从左向右依次放置其他组件,行满后,继续在下一行中从左到右放置组件。FlowLayout不同的是,放置在GridLayout布局管理器中的组件将自动占据网格的整个区域。GridLayout类有三个构造方法

方法声明 功能描述
GridLayout() 默认只有一行,每个组件占一列
GridLayout(int rows,int cols) 指定容器的行数和列数
GridLayout(int rows,int cols,int hgap,int vgap) 指定容器的行数和列数以及组件之间的水平、垂直间距
package gui;
import java.awt.Button;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Example05 {
	private static void creatAndShowGUI() {
		//创建一个名为GridLayout的窗体
		JFrame f = new JFrame("GridLayout");
		f.setLayout(new GridLayout(3,3));//设置该窗体为3*3的网格
		f.setSize(300, 300);
		f.setLocation(300, 200);
		//下面的代码是创建5个按钮组件
		JButton but1 = new JButton("PAGE_START");
		JButton but2 = new JButton("PAGE_END");
		JButton but3 = new JButton("LINE_START");
		JButton but4 = new JButton("LINE_END");
		JButton but5 = new JButton("CENTER");
		//下面的代码是循环添加9个按钮组件到GridLayout容器中
		for (int i = 0; i < 9; i++) {
			Button btn = new Button("btn"+i);
			f.add(btn);
		}
		//设置窗体可见
		f.setVisible(true);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
    public static void main(String[] args) {
    	//使用SwingUtilities工具类调用creatAndshowGUI()方法显示GUI程序
		SwingUtilities.invokeLater(Example05::creatAndShowGUI);
    }
}

4.事件处理

事件处理机制

  • Swing组件中的事件处理专门用于响应用户的操作,例如,响应用户的单击鼠标,按下键盘等操作。在Swing事件处理的过程中,主要是涉及三类对象:

     1>事件源(Event Source):时间发生的场所,通常就是产生事件的组件,例如窗口、按钮、菜单等。
     2>事件对象(Event):封装了GUI组件上发生的特定事件(通常就是用户的一次操作)
     3>监听器(Listener):负责监听事件源上发生的事件,并对各种事件做出相应处理的对象(对象中包含事件处理器)
    
  • 上面提到的事件源、事件对象、监听器在整个事件处理过程中都起着非常重要的作用。

2.触发事件源上的事件
3.产生并传送到事件对象
4.接收事件对象
1.将监听器注册到事件源
外部动作
事件源
事件对象
监听器
  • 在上图中,事件源是一个组件,当用户进行一些操作时,如按下鼠标或者释放键盘等,都会触发相应的事件。如果事件源注册了监听器,则触发的相应事件将会被处理
package gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

//自定义事件监听类
class MyListener11 implements ActionListener{

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("用户点击了JButton按钮");
		
	}
	
}
public class Example06 {
public static void main(String[] args) {
		
		//启动一个Frame
		SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				creatAndShowGUI();
			}
		});
		

	}
	private static void creatAndShowGUI() {
		JFrame f = new JFrame("JFrame窗口");
		f.setSize(200, 100);
		f.setLocationRelativeTo(null);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//创建一个按钮组件,作为事件源
		JButton btn = new JButton("按钮");
		//为按钮组件事件添加自定义监听器
		btn.addActionListener(new MyListener11());
		f.add(btn);
		f.setVisible(true);
		
	}
	
}

  • 从上面的程序可以看出,实现Swing事件处理的主要步骤如下

       (1)创建事件源。除了一些常见的按钮、键盘等组件也可以作为事件源外,包括JFrame窗口在内的顶级容器也可以作为事件源
       (2)自定义事件监听器。根据要监听的事件源创建指定类型的监听器进行时间处理,该监听器是一个特殊的JAVA类,必须实现XxxListener接口(根据组件触发的动作进行区分,如WindowListener用于监听窗口事件,ActionListener用于监听动作事件)
       (3)为事件源注册监听器。使用addXxxListener()方法为指定事件源添加特定类型的监听器。当事件源上发生监听的事件后,就会触发绑定的事监听器,然后由监听器中的方法进行相应的处理
    

Swing常用事件处理

在Swing中,提供了丰富的事件,这些事件可分为窗体事件(WindowEvent)、鼠标事件(MouseEvent)、键盘事件(KeyEvent)、动作事件(ActionEvent)等

  • 窗体事件:
    大部分GUI程序都需要使用Window窗体对象作为最外层的容器,可以说窗体对象是所有GUI应用程序的基础,应用程序中通常都是其他组件直接或间接地添加到窗体中。
    当对窗体进行操作时,例如窗体的打开、关闭、激活、停用等,这些动作都属于窗体事件,Java中提供了一个 WindowEvent 类用于表示窗体事件。在应用程序中,当对窗体事件行处理时,首先需要定义一个实现了WindowListener接口的类作为窗体监听器,然后通过addWindowListener()方法将窗体对象与窗体监听器进行绑定。
package gui;

import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Example07 {
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				creatAndShowGUI();
				
			}
		});
	}
	private static void creatAndShowGUI() {
		JFrame f = new JFrame("WindowEvent");
		f.setSize(400, 300);
		f.setLocationRelativeTo(null);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setVisible(true);
		//使用内部类创建WindowEvent实例对象,监听窗体事件
		f.addWindowListener(new WindowListener() {
			
			@Override
			public void windowOpened(WindowEvent e) {
				System.out.println("window---窗体打开事件");
				
			}
			
			@Override
			public void windowIconified(WindowEvent e) {
				System.out.println("windowIconified---窗体图标化事件");
				
			}
			
			@Override
			public void windowDeiconified(WindowEvent e) {
				System.out.println("windowDeiconified---窗体取消图标化事件");
				
			}
			
			@Override
			public void windowDeactivated(WindowEvent e) {
				System.out.println("windowDeactivated---窗体停用事件");
				
			}
			
			@Override
			public void windowClosing(WindowEvent e) {
				System.out.println("windowClosing---窗体正在关闭事件");
				
			}
			
			@Override
			public void windowClosed(WindowEvent e) {
				System.out.println(" windowClosed---窗体关闭事件");
				
			}
			
			@Override
			public void windowActivated(WindowEvent e) {
				System.out.println("windowActivated---窗体激活事件");
				
			}
		});
	}
}

通过WindowListener对操作窗口的窗体事件进行监听,当接收到特定的动作后,就将所触发事件的名称打印出来。接着窗体事件源进行事件操作,分别执行最小化、单击任务栏图标,单击关闭按钮时,窗口事件监听器就会对相应的操作进行监听并响应,结果如下示:

windowActivated- .-窗体激活事件
windowOpened---窗体打开事件
windowIconified---窗体图标化事件
windowDeactivated---窗体停用事件
windowDeiconified---窗体取消图标化事件
windowActivoted---窗体激活事件
windowClosing---窗体正在关闭事件
windoweactived---窗体停用事件
  • 鼠标事件
    在图形用户界面中,用户会经常使用鼠标来进行选择、切换界面等操作,这些操作被定义为鼠标事件,其中包括鼠标按下、鼠标松开、鼠标单击等。Java 中提供了一个MouseEvent类用于表示鼠标事件,几乎所有的组件都可以产生鼠标事件。处理鼠标事件时,首先需要通过实现MouseListener 接口定义监听器,也可以通过继承适配器MouseAdaper类来实现,然后调用addMouseListener()方法将监听器绑定到事件源对象。
package gui;

import java.awt.FlowLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Example08 {
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				creatAndShowGUI();
				
			}
		});
	}
	private static void creatAndShowGUI() {
		JFrame f = new JFrame("MouseEvent");
		f.setLayout(new FlowLayout());//为窗口设置布局
		f.setSize(400, 300);
		f.setLocationRelativeTo(null);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setVisible(true);
		JButton btn = new JButton("按钮"); //创建按钮对象
		f.add(btn);//在窗口添加按钮组件
		//为按钮添加鼠标事件监听器
		btn.addMouseListener(new MouseListener() {
			
			@Override
			public void mouseReleased(MouseEvent e) {
				System.out.println("mouseReleased---鼠标放开事件");
				
			}
			
			@Override
			public void mousePressed(MouseEvent e) {
				System.out.println("mousePressed---鼠标按下事件");
				
			}
			
			@Override
			public void mouseExited(MouseEvent e) {
				System.out.println("mouseExited---鼠标移出按钮区事件");
				
			}
			
			@Override
			public void mouseEntered(MouseEvent e) {
				System.out.println("mouseEntered---鼠标进入按钮区事件");
				
			}
			
			@Override
			public void mouseClicked(MouseEvent e) {
			  if (e.getButton()==MouseEvent.BUTTON1) {
				System.out.println("鼠标左击事件");
			}
			  if (e.getButton()==MouseEvent.BUTTON3) {
					System.out.println("鼠标右击事件");
				}
			  if (e.getButton()==MouseEvent.BUTTON2) {
					System.out.println("鼠标中键单击事件");
				}
				
			}
			
		});
		
		
	}
}

从上的代码可以看出,MouseEvent类中针对鼠标的案件都定义了对应的常量,可以通过MouseEvent对象的getButton()方法获取被操作按键的键值,从而判断是哪个按键的操作。另外鼠标的单击次数也可以通过MouseEvent对象的getClickCount()方法获取到。

  • 键盘事件
    键盘操作也是最常用的用户交互方式,例如键盘按下、释放等,这些操作被定义为键盘事件。Java 中提供了一个KeyEvent类表示键盘事件,处理KeyEvent事件的监听器对象需要实现KeyListener接口或者继承KeyAdapter类,然后调用addKeyListener()方法将监听器绑定到事件源对象。
package gui;

import java.awt.FlowLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class Example09 {
		public static void main(String[] args) {
			SwingUtilities.invokeLater(new Runnable() {
				
				@Override
				public void run() {
					creatAndShowGUI();
					
				}
			});
		}
		private static void creatAndShowGUI() {
			JFrame f = new JFrame("KeyEvent");
			f.setLayout(new FlowLayout());//为窗口设置布局
			f.setSize(400, 300);
			f.setLocationRelativeTo(null);
			JTextField tf = new JTextField(30);//创建文本框对象
			f.add(tf);//在窗口中添加文本框组件
			f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			f.setVisible(true);
			tf.addKeyListener(new KeyAdapter() {
				
				public void keyPressed(KeyEvent e) {
					//获取对应的键盘字符
					char keychar = e.getKeyChar();
					//获取对应的键盘字符代码
					int keyCode  = e.getKeyCode();
					System.out.println("键盘按下的字符内容为:"+keychar+"");
					System.out.println("键盘按下的字符代码为"+keyCode+"");
					
				}

				
			});
			
  }
}

  • 动作事件
    动作事件与前面三种事件有所不同,它不代表某类事件,只是表示一个动作发生了。例如,在关闭一个文件时,可以通过键盘关闭,也可以通过鼠标关闭。在这里不需要关心使用哪种方式对文件进行关闭,只要是对关闭按钮进行操作,即触发了动作事件。
    在Java中,动作事件用ActionEvent类表示,处理ActionEvent事件的监听器对象需委实现ActionListener接口。监听器对象在监听动作时,不会像鼠标事件一样处理鼠标的移动和单击的细节,而是去处理类似于“按钮按下”这样“有意义”的事件。

猜你喜欢

转载自blog.csdn.net/qq_44787898/article/details/103335831