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):负责监听事件源上发生的事件,并对各种事件做出相应处理的对象(对象中包含事件处理器)
-
上面提到的事件源、事件对象、监听器在整个事件处理过程中都起着非常重要的作用。
- 在上图中,事件源是一个组件,当用户进行一些操作时,如按下鼠标或者释放键盘等,都会触发相应的事件。如果事件源注册了监听器,则触发的相应事件将会被处理
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接口。监听器对象在监听动作时,不会像鼠标事件一样处理鼠标的移动和单击的细节,而是去处理类似于“按钮按下”这样“有意义”的事件。