第11章 GUI
11.1 Swing概述
Swing介绍:Swing是Java语言开发图形化界面的一个工具包。它以抽象窗口工具包(AWT)为基础,使跨平台应用程序可以使用可插拔的外观风格。Swing拥有丰富的库和组件,使用非常灵活,开发人员只用很少的代码就可以创建出优雅的用户界面
在Java中,所有的Swing组件都保存在javax.swing包中,为了有效的使用Swing组件,必须了解Swing包的层次结构和继承关系
Swing组件的继承关系:
从上图可以看出,Swing组件的所有类都继承自Container类
根据 GUI开发的功能扩展了两个主要分支:
- 容器分支(包括Window窗口和Panel面板),为了实现图形化用户界面窗口的容器而设计的
在容器分支中,Swing组件类中有三个组件是继承的AWT的Window类,而不是继承自JComponent类,这三个组件是Swing中的顶级容器类,它们分别是JWindow、JFrame、和JDialog
- 组件分支,为了实现向容器中填充数据、元素以及交互组件等功能
Jcomponent类几乎是所有Swing组件的公共超类,Jcomponent类的所有子类都继承了它的全部公有方法
Jcomponent的常用子类:
11.2 Swing顶级容器
11.2.1 JFrame
JFrame容器简介:在Swing组件中,最常见的一个容器就是JFrame,它是一个独立存在的顶级容器(也叫窗口),不能放置在其他容器之中。JFrame支持通用窗口所有的基本功能,例如,窗口最小化、设定窗口大小等
JFrame类的常用操作方法:
方法 | 类型 | 功能描述 |
---|
public JFrame**() throws** HeadlessException | 构造方法 | 创建一个普通窗体对象 | public JFrame**(String title) throws** HeadlessException | 构造方法 | 创建一个窗体对象,并指定标题 | public void setSize(int width,int height) | 普通方法 | 设置窗体大小 | public void setSize**(**Dimention d) | 普通方法 | 通过Dimention设置窗体大小 | public void Background(Color c) | 普通方法 | 设置窗体的背景颜色 |
方法 | 类型 | 功能描述 |
---|
public void setLocation**(**int x,int y) | 普通方法 | 设置组件的显示位置 | public void setLocation(Point p) | 普通方法 | 通过Point设置组件的显示位置 | public void setVisiable(boolean b) | 普通方法 | 显示或隐藏组件 | public Component add(Component comp) | 普通方法 | 向容器中增加组件 | Public setLayout(Component comp) | 普通方法 | 设置布局管理器,如果设置为null表示不使用 | public void pack() | 普通方法 | 调整窗口大小,以适合其子组件的首选大小和布局 | public Comntainer getContentPane() | 普通方法 | 返回此窗体的容器对象 |
实例:
package eleven;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class test01 extends JFrame{
private static void createAndShowGUI() {
JFrame frame = new JFrame("JFrameTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("JFrameTest");
frame.setSize(350, 300);
frame.setLocation(300,200);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(test01::createAndShowGUI);
}
}
第6行代码通过JFrame类创建了一个窗体对象frame,并在创建窗体对象的同时定义了窗体对象的标题为“JFrameTest”;
第8行代码通过调用JFrame类的setDefaultCloseOperation()方法设置了窗体对象关闭时的默认操作;
第10行代码通过调用JFrame类的setTitle()方法设置了窗口标题;
第12行代码通过调用JFrame类的setSize()方法设置了窗口尺寸;
第14行代码通过调用JFrame类的setLocation()方法设置了窗口的显示位置;
第16行代码通过调用JFrame类的setVisible()方法设置让组件显示;最后在main()方法中,调用javax.swing包中的SwingUtilities(封装有一系列操作Swing的方法集合工具类)工具类的invokeLater()方法执行了GUI程序。需要注意的是,invokeLater()方法需要传入一个接口作为参数。
11.2.2 JDialog
JDialog简介:JDialog是Swing的另外一个顶级容器,它和Dialog一样都表示对话框窗口。
JDialog对话框可分为两种:
- 模态对话框,所谓模态对话框是指用户需要处理完当前对话框后才能继续与其他窗口交互的对话框
- 非模态对话框,非模态对话框是允许用户在处理对话框的同时与其他窗口交互的对话框
对话框是模态或者非模态,可以在创建JDialog对象时为构造方法传入参数进行设置,也可以在创建JDialog对象后调用它的setModal()方法进行设置。JDialog常见的构造方法如下
方法声明 | 功能描述 |
---|
JDialog(Frame owner) | 用于创建一个非模态的对话框。参数owner为对话框所有者(顶级窗口JFrame)。 | JDialog(Frame owner**,**String title) | 创建一个具有指定标题的非模态对话框。 | JDialog(Frame owner**,**boolean modal) | 创建一个有指定模式的无标题对话框。 |
上表列举了JDialog三个常用的构造方法,这三个构造方法都需要接收一个Frame类型的对象,表示对话框所有者。如果该对话框没有所有者,参数owner可以传入null。第3个构造方法中,参数modal用来指定JDialog窗口是模态还是非模态
如果modal值设置为true,对话框就是模态对话框,反之则是非模态对话框,如果不设置modal的值,默认为false,也就是非模态对话框
实例:
package GUI_test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Modal {
public static void main(String[] args) {
JButton btn1 = new JButton("模态对话框");
JButton btn2 = new JButton("非模态对话框");
JFrame jf = new JFrame("JDialog_Test");
jf.setSize(300,250);jf.setLocation(300,200);
jf.setLayout(new FlowLayout());
jf.add(btn1);jf.add(btn2);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
final JDialog dialog = new JDialog(jf,"Dialog");
dialog.setSize(220,150);dialog.setLocation(350,250);
dialog.setLayout(new FlowLayout());
final JButton btn3 = new JButton("确定");
dialog.add(btn3);
final JLabel label = new JLabel();
btn1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.setModal(true);
if(dialog.getComponents().length==1){
label.setText("模式对话框,单击关闭!");
dialog.setVisible(true);
}
}
});
btn2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.setModal(false);
if(dialog.getComponents().length==1){
label.setText("非模式对话框,单击关闭!");
dialog.setVisible(true);
}
}
});
btn3.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
}
}
11.3 布局管理器
布局管理器简介:组件在容器中的位置和尺寸是由布局管理器决定的,每当需要重新调整屏幕大小时,都要用到布局管理器。Swing常用的布局管理器有4种,分别是FlowLayout(流式布局管理器)、BorderLayout(边界布局管理器)、GridLayout(网格布局管理器)、GridBagLayout(网格包布局管理器)。
Swing容器在创建时都会使用一种默认的布局管理器,在程序中可以通过调用容器对象的setLayout()方法设置布局管理器,通过布局管理器自动进行组件的布局管理。
11.3.1 FlowLayout
FlowLayout属于流式布局管理器,是最简单的布局管理器。在这种布局下,容器会将组件按照添加顺序从左向右放置。当到达容器的边界时,自动将组件放到下一行的开始位置。这些组件可以左对齐、居中对齐(默认方式)或右对齐的方式排列
FlowLayout类的常用方法及变量:
方法及常量 | 类型 | 功能描述 |
---|
public FlowLayout() | 构造方法 | 组件默认居中对齐,水平、垂直间距默认为5个单位 | public FlowLayout(int align) | 构造方法 | 指定组件相对于容器的对齐方式,水平、垂直间距默认为5个单位 | public FlowLayout(int align,int hgap,int vgap) | 构造方法 | 指定组件的对齐方式和水平、垂直间距 | public static final int CENTER | 常量 | 居中对齐 | public static final int LEADING | 常量 | 与容器的开始端对齐方式一样 | public static final int LEFT | 常量 | 左对齐 | public static final int RIGHT | 常量 | 右对齐 |
实例:
package eleven;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class test03 {
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Hello World!");
frame.setLayout(new FlowLayout(FlowLayout.CENTER,3,3));
JButton btn1 = null;
for(int i=0;i<9;i++) {
btn1 = new JButton("按钮"+i);
frame.add(btn1);
}
frame.setSize(280,250);
frame.setVisible(true);
}
}
11.3.2 BorderLayout
BorderLayout(边界布局管理器)是一种较为复杂的布局方式,它将窗体划分为五个区域,分别是东(EAST)、南(SOUTH)、西(WEST)、北(NORTH)、中(CENTER)。组件可以被放置在这五个区域中的任意一个区域中
当向BorderLayout管理的窗体中添加组件时,需要调用add(Component comp,Object constraints)方法,其中,参数comp表示要添加的组件,参数constraints是一个Object类型的对象,用于指定组件添加方式以及添加位置。向add()方法传参时,可以使用BorderLayout类提供的5个常量,它们分别是EAST、SOUTH、WEST、NORTH和CENTER
BorderLayout的常用方法及常量:
方法及常量 | 类型 | 功能描述 |
---|
public BorderLayout() | 构造方法 | 构造没有间距的布局器 | public BorderLayout(int align,int hgap,int vgap) | 构造方法 | 构造有水平和垂直间距的布局器 | public static final String EAST | 常量 | 将组件设置在东区域 | public static final String WEST | 常量 | 将组件设置在西区域 | public static final String SOUTH | 常量 | 将组件设置在南区域 | public static final String NORTH | 常量 | 将组件设置在北区域 | public static final String CENTER | 常量 | 将组件设置在中区域 |
实例:
package eleven;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;
public class test04 extends JFrame{
public test04() {
setLayout(new BorderLayout(5,5));
setFont(new Font("Hello Java!",Font.PLAIN,14));
getContentPane().add("North",new JButton(BorderLayout.NORTH));
getContentPane().add("East",new JButton(BorderLayout.EAST));
getContentPane().add("West",new JButton(BorderLayout.WEST));
getContentPane().add("Center",new JButton(BorderLayout.NORTH));
}
public static void main(String [] args) {
test04 f = new test04();
f.setTitle("边界布局");
f.pack();
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
}
}
BorderLayout的优点就是可以限定各区域的边界,当用户改变容器窗口大小时,各个组件的相对位置不变
注意:向BorderLayout管理的容器添加组件时,如果不指定添加到哪个区域,则默认添加到CENTER区域,并且只能放置一个组件,如果向一个区域中添加多个组件时,后放入的组件会覆盖先放入的组件
11.3.3 GridLayout
GridLayout布局管理器是以网格的形式管理容器中组件布局的。GridLayout使用纵横线将容器分成n行m列大小相等的网格,每个网格中放置一个组件。添加到容器中的组件首先放置在第1行第1列(左上角)的网格中,然后在第1行的网格中从左向右依次放置其他组件。一行放满之后,继续在下一行中从左到右放置组件
GridLayout管理方式与FlowLayou类似,但与FlowLayout不同的是,使用GridLayout管理的组件将自动占据网格的整个区域
GridLayout的常用构造方法:
方法声明 | 功能描述 |
---|
GridLayout() | 默认只有一行,每个组件占一列 | GridLayout(int rows,int cols) | 指定容器的行数和列数 | GridLayout(int rows,int cols,int hgap,int vgap) | 指定容器的行数和列数以及组件之间的水平、垂直间距 |
实例:
package GUI_test;
import javax.swing.*;
import java.awt.*;
public class GridLO {
public static void main(String[] args) {
JFrame f = new JFrame("GridLayout");
f.setLayout(new GridLayout(3,3));
f.setSize(300,300);
f.setLocation(400,300);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
for(int i=0;i<9;i++){
Button bt = new Button("btn"+i);
f.add(bt);
}f.setVisible(true);
}
}
11.3.4 GridBagLayout
GridBagLayout是最灵活、最复杂的布局管理器。GridBagLayout与GridLayout布局管理器类似,不同的是,GridBagLayout允许网格中的组件大小各不相同,而且允许一个组件跨越一个或者多个网格
使用GridBagLayout布局管理器的步骤如下:
1.创建GridBagLayout布局管理器,设置容器采用该布局管理器
GridBagLayout layout = new GridBagLayout();
container.setLayout(layout);
2.创建GridBagContraints对象,并设置该对象的相关属性(设置布局约束条件)
GridConstraints constrains = new GridConstrains();
constrains.gridx = 1;
constrains.gridy= 1;
constrains.gridwidth = 1;
constrains.gridheight = 1;
3.调用GridBagLayout对象的setConstrains()方法,建立GridBagLayout对象和受控组件之间的关系
layout.setConstrains(component,constrains);
4.向容器中添加组件
属性 | 作用 |
---|
fill | 如果组件的显示区域大于组件需要的大小,设置组件改变方式,该属性接收以下几个属性值:NONE:默认,不改变组件大小。HORIZONTAL:使组件水平方向足够长以填充显示区域,但是高度不变,VERTICAL:使组件垂直方向足够高以填充显示区域,但长度不变。BOTH:使组件足够大,以填充整个显示区域。 | weightx和weighty | 设置组件占领容器中水平方向和垂直方向多余空白的比例(也称为权重)。假设容器的水平方向放置三个组件,组件的weightx属性值分别为1、2、3,当容器宽度增加60个像素时,这三个容器分别增加10、20、和30的像素。weightx和weighty属性的默认值是0,即不占领多余的空间。 |
如果希望组件的大小随着容器的增大而增大,必须同时设置GridBagConstraints对象的fill属性和weightx、weighty属性
实例:
package GUI_test;
import java.awt.*;
class Layout extends Frame {
public Layout(String title){
GridBagLayout layout = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
this.setSize(600,700);
this.setLocation(300,400);
this.setLayout(layout);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;c.weighty = 1;
this.addComponent("btn1",layout,c);
this.addComponent("btn2",layout,c);
this.addComponent("btn3",layout,c);
c.gridwidth = GridBagConstraints.REMAINDER;
this.addComponent("btn4",layout,c);
c.weightx = 0;c.weighty = 0;
this.addComponent("btn5",layout,c);
c.gridwidth = 1;
this.addComponent("btn6",layout,c);
c.gridwidth = GridBagConstraints.REMAINDER;
this.addComponent("btn7",layout,c);
c.gridheight = 2;c.gridwidth = 1;
c.weightx = 2;c.weighty = 2;
this.addComponent("btn8",layout,c);
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = 1;
this.addComponent("btn9",layout,c);
this.addComponent("btn10",layout,c);
this.setTitle(title);
this.pack();
this.setVisible(true);
}
private void addComponent(String name,GridBagLayout layout,GridBagConstraints c){
Button bt = new Button(name);
layout.setConstraints(bt,c);
this.add(bt);
}
}
public class GBL{
public static void main(String[] args) {
new Layout("GridBagLayout");
}
}
代码解释:
- 在10-30行代码通过this.addComponent()方法添加了10个按钮
- 在上面对GridBagLayout布局管理器的使用进行介绍时,说明了每添加一个组件都要重复2,3,4方法(2.创建GridBagContraints对象并设置其该对象的相关属性;3.调用GridBagLayout方法的setConstraints()方法,建立GridBagLayout对象与受控组件之间的关系;4.通过add()方法添加组件)
- 但是由于每次添加组件都要经历这三个阶段,且会重复地调用GridBagLayout的setConstraints()方法,因此可以将此方法写在addComponent方法中避免代码复写
- 将button1-4和button8-10的横向纵向权重weightx/y都设置为0,因此在拉伸窗口时这些按钮会随窗口大小的变化而变化
11.4 事件处理机制
11.4.1 事件处理机制简介
Swing组件中的事件处理专门用于响应用户的操作,例如,响应用户的鼠标单击、按下键盘等操作
在Swing事件处理的过程中,主要涉及到三类对象:
- 事件源(Event Source):事件发生的场所,通常是产生事件的组件,如窗口、按钮、菜单等
- 事件对象(Event):封装了GUI组件上发生的特定事件(通常就是用户的一次操作)
- 监听器(Lisener):负责监听事件源上发生的事件,并对各种事件作出相应处理(监听对象中包含事件处理器)
上面提到的事件源、事件对象、监听器在整个事件处理过程中都起着非常重要的作用,它们彼此之间有着非常紧密的联系
处理事件时事件源、事件对象、监听器的工作流程:
事件源是一个组件,当用户进行一些操作时,例如,按下鼠标或者释放键盘等,都会触发相应的事件,如果事件源注册了监听器,则触发的相应事件将会被处理
实例:
package GUI_test;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class MyListener implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.println("用户点击了JButton按钮");
}
}
public class Event1 {
public static void createAndShow(){
JFrame f = new JFrame("JFrame窗口");
f.setSize(200,100);
JButton btn = new JButton("按钮");
btn.addActionListener(new MyListener());
f.add(btn);f.setVisible(true);f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(Event1::createAndShow);
}
}
代码解析:
- 定义一个JButton组件并将其添加到JFrame窗口
- 实现监听器方法,对事件进行监听(与控制台有关)
- 使用addActionListener()方法为JButton按钮组件添加了一个自定义事件监听器
实现Swing事件处理的主要步骤:
(1)创建事件源:除了一些常见的按钮、键盘等组件可以作为事件源外,还可以使用JFrame窗口在内的顶级容器作为事件源
(2)自定义事件监听器:根据要监听的事件源创建指定类型的监听器进行事件处理。监听器是一个特殊的Java类,必须实现XxxListener接口。根据组件触发的动作进行区分,例如,WindowListener用于监听窗口事件,ActionListener用于监听动作事件
(3)为事件源注册监听器:使用addXxxListener()方法为指定事件源添加特定类型的监听器。当事件源上发生监听事件后,就会触发绑定的事件监听器,由监听器中的方法对事件进行相应处理。
11.4.2 Swing常用事件处理
11.4.2.1 窗体事件
窗体事件简介:大部分GUI应用程序都需要使用Window窗体对象作为最外层的容器,可以说窗体对象是所有GUI应用程序的基础,应用程序中通常都是将其他组件直接或者间接地添加到窗体中。
当对窗体进行操作时,例如,窗体的打开、关闭、激活、停用等,这些动作都属于窗体事件。Java提供了一个WindowEvent类用于表示窗体事件。在应用程序中,当对窗体事件进行处理时,首先需要定义一个实现了WindowListener接口的类作为窗体监听器,然后通过addWindowListener()方法将窗体对象与窗体监听器进行绑定
实例:
package GUI_test;
import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class WindowEvent0 {
private static void createAndShowGUI(){
JFrame f = new JFrame("WindowEvent");
f.setSize(400,300);f.setLocation(300,200);
f.setVisible(true);f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.addWindowListener(new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
System.out.println("windowOpened——窗体打开事件");
}
@Override
public void windowClosing(WindowEvent e) {
System.out.println("windowClosing——窗体正在关闭事件");
}
@Override
public void windowClosed(WindowEvent e) {
System.out.println("windowClosed——窗体关闭事件");
}
@Override
public void windowIconified(WindowEvent e) {
System.out.println("windowIconified——窗体图标化事件");
}
@Override
public void windowDeiconified(WindowEvent e) {
System.out.println("windowDeiconified——窗体取消图标化事件");
}
@Override
public void windowActivated(WindowEvent e) {
System.out.println("windowActivated——窗体激活事件");
}
@Override
public void windowDeactivated(WindowEvent e) {
System.out.println("windowDeactivated——窗体停用事件");
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(WindowEvent0::createAndShowGUI);
}
}
11.4.2.2 鼠标事件
鼠标事件简介:在图形用户界面中,用户会经常使用鼠标进行选择、切换界面等操作,这些操作被定义为鼠标事件,包括鼠标按下、鼠标松开、鼠标单击等。Java提供了一个MouseEvent类描述鼠标事件。处理鼠标事件时,首先需要通过实现MouseListener接口定义监听器(也可以通过继承适配器MouseAdapter类定义监听器),然后调用addMouseListener()方法将监听器绑定到事件源对象
实例:
package GUI_test;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MouseEvent {
private static void createAndShowGUI() {
JFrame f = new JFrame("MouseEvent");
f.setLayout(new FlowLayout());
f.setSize(300, 200);
f.setLocation(300, 200);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton but = new JButton("Button");
f.add(but);
but.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(java.awt.event.MouseEvent e) {
System.out.println("mouseClicked-鼠标完成单击事件");
}
@Override
public void mousePressed(java.awt.event.MouseEvent e) {
System.out.println("mousePressed-鼠标按下事件");
}
@Override
public void mouseReleased(java.awt.event.MouseEvent e) {
System.out.println("mouseReleased-鼠标放开事件");
}
@Override
public void mouseEntered(java.awt.event.MouseEvent e) {
System.out.println("mouseEntered—鼠标进入按钮区域事件");
}
@Override
public void mouseExited(java.awt.event.MouseEvent e) {
System.out.println("mouseExited—鼠标移出按钮区域事件");
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(MouseEvent::createAndShowGUI);
}
}
11.4.2.3 键盘事件
键盘事件简介:键盘操作也是最常用的用户交互方式,例如,键盘按下、释放等,这些操作被定义为键盘事件。Java提供了一个KeyEvent类表示键盘事件,处理KeyEvent事件的监听器对象需要实现KeyListener接口或者继承KeyAdapter类,然后调用**addKeyListener()**方法将监听器绑定到事件源对象
实例:
package GUI_test;
import javax.swing.*;
import java.awt.event.KeyAdapter;
public class KeyEvent {
private static void createAndShowGUI() {
JFrame f = new JFrame("KeyEvent");
f.setSize(300,400);f.setLocation(300,400);
JTextField tf = new JTextField(30);
f.add(tf);f.setVisible(true);f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tf.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
char keyChar = e.getKayChar();
int keyCode = e.getKeyCode();
System.out.print("键盘按下的字符内容为:" + keyChar+" ");
System.out.println("键盘按下的字符代码为:" + keyCode);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(KeyEvent::createAndShowGUI);
}
}
11.4.2.4 动作事件
动作事件简介:动作事件与前面3种事件有所不同,它不代表某类事件,只是表示一个动作发生了。例如,在关闭一个文件时,可以通过键盘关闭,也可以通过鼠标关闭。在这里读者不需要关心使用哪种方式关闭文件,只要是对关闭按钮进行操作,就会触发动作事件。
在Java中,动作事件用ActionEvent类表示,处理ActionEvent事件的监听器对象需要实现ActionListener接口。监听器对象在监听动作时,不会像鼠标事件一样处理鼠标的移动和单击的细节,而是去处理类似于“按钮按下”这样“有意义”的事件
11.5 Swing常用组件
11.5.1 面板组件
Swing组件中不仅具有JFrame和JDialog这样的顶级容器,还提供了一些面板组件(也称之为中间容器)。面板组件不能单独存在,只能放置在顶级窗口容器中。最常见的面板组件有两种,分别是JPanel和JScrollPane
JPanel面板组件是一个无边框,不能被移动、放大、缩小或者关闭的面板,它的默认布局管理器是FlowLayout。也可以使用JPanel带参数的构造函数JPanel(LayoutManager layout)或者setLayout()成员方法设置JPanel布局管理器。 JPanel面板组件类并没有包含多少特殊的组件操作方法,大多数都是从父类(如Container)继承过来的,使用也非常简单
JScrollPane是一个带有滚动条的面板,面板上只能添加一个组件。如果想向JScrollPane面板中添加多个组件,应该先将这多个组件添加到某个组件中,然后再将这个组件添加到JScrollPane中
JScrollPane的常用构造方法:
方法声明 | 功能描述 |
---|
JScrollPane() | 创建一个空的JScrollPane面板。 | JScrollPane**(Component view)** | 创建一个显示指定组件的JScrollPane面板,一旦组件的内容超过视图大小就会显示水平或垂直滚动条。 | **JScrollPane(Component view,**int vsbPolicy,int hsbPolicy) | 创建一个显示指定容器、并具有指定滚动条策略的JScrollPane。参数vsbPolicy和hsbPolicy分别表示垂直滚动条策略和水平滚动条策略。 |
如果在构造方法中没有指定显示组件和滚动条策略,可以调用JScrollPane提供的成员方法进行设置,JScrollPane设置面板滚动策略的方法如下表
方法声明 | 功能描述 |
---|
void setHorizontalBarPolicy**(**int policy) | 指定水平滚动条策略,即水平滚动条何时显示在滚动面板上。 | void setVerticalBarPolicy(int policy) | 指定垂直滚动条策略,即垂直滚动条何时显示在滚动面板上。 | void setViewportView(Component view) | 设置在滚动面板显示的组件。 |
ScrollPaneConstants接口声明了多个常量属性,可以用来设置不同的滚动策略
方法声明 | 功能描述 |
---|
VERTICAL_SCROLLBAR_AS_NEEDED | 当填充的组件视图超过客户端窗口大小时,自动显示水平和竖直滚动条(JscrollPane组件的默认值)。 | HORIZONTAL_SCROLLBAR_AS_NEEDED | | VERTICAL_SCROLLBAR_ALWAYS | 无论填充的组件视图大小,始终显示水平和竖直滚动条。 | HORIZONTAL_SCROLLBAR_ALWAYS | | VERTICAL_SCROLLBAR_NEVER | 无论填充的组件视图大小,始终不显示水平和竖直滚动条。 | HORIZONTAL_SCROLLBAR_NEVER | |
实例:
import java.awt.*;
import javax.swing.*;
public class Example11 {
private static void createAndShowGUI() {
JFrame f = new JFrame("PanelDemo");
f.setLayout(new BorderLayout());
f.setSize(350, 200);
f.setLocation(300, 200);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setHorizontalScrollBarPolicy
(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy
(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
JPanel panel = new JPanel();
panel.add(new JButton("按钮1"));
panel.add(new JButton("按钮2"));
panel.add(new JButton("按钮3"));
panel.add(new JButton("按钮4"));
scrollPane.setViewportView(panel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(Example11::createAndShowGUI);
}
}
11.5.2 文本组件
文本组件用于接收用户输入的信息,包括文本框(JTextField)、文本域(JTextArea)等。文本组件都有一个共同父类JTextComponent,JTextComponent类是一个抽象类,它提供了文本组件常用的方法
方法声明 | 功能描述 |
---|
String getText() | 返回文本组件中所有的文本内容 | String getSelectedText() | 返回文本组件中选定的文本内容 | void selectAll() | 在文本组件中选中所有内容 | void setEditable() | 设置文本组件为可编辑或者不可编辑状态 | void setText(String text) | 设置文本组件的内容 | void replaceSelection(String content) | 用给定的内容替换当前选定的内容 |
由于JTextField和JTextArea这两个文本组件继承了JTextComponent类,因此它们都具有上表中的方法。但是在使用上,JtextField和JTextArea还有一定的区别
JTextField称为文本框,它只能接收单行文本的输入。 JTextField常用的构造方法如下表
方法声明 | 功能描述 |
---|
JTextField**()** | 创建一个空的文本框,初始字符串为null | JTextFiled**(**int columns) | 创建一个具有指定列数的文本框,初始字符串为null | JTextField(String text) | 创建一个显示指定初始字符串的文本框 | JTextField(String text,int column) | 创建一个具有指定列数、并显示指定初始字符串的文本框 |
JTextField有一个子类JPasswordField,表示密码框,JpasswordField文本框也是只能接收用户的单行输入,但是文本框中不显示用户输入的真实信息,而是通过显示指定的回显字符作为占位符,新创建的密码框默认的回显字符为“*”。JPasswordField和JTextField的构造方法相似
JTextArea称为文本域,它能接收多行文本的输入,使用JTextArea构造方法创建对象时可以设定区域的行数、列数。 JTextArea常用的构造方法如下表
方法声明 | 功能描述 |
---|
JTextArea() | 创建一个空的文本域 | JTextArea(String text) | 创建显示指定初始字符串的文本域 | JTextArea(int rows,int columns) | 创建具有指定行和列的空文本域 | JTextArea(String text,int rows,int columns) | 创建显示指定初始文本并指定了行列的文本域 |
实例:
package GUI_test;
import javax.swing.*;
import java.awt.*;
public class Text {
public static void create(){
JFrame f = new JFrame("聊天窗口");
f.setSize(400,300);f.setLocation(300,200);
f.setLayout(new BorderLayout());f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea show = new JTextArea(12,34);
JScrollPane scr = new JScrollPane(show);
show.setEditable(false);
JTextField input = new JTextField(20);
JButton btn = new JButton("发送");
btn.addActionListener(e->{
String content = input.getText();
if(content!=null && !content.trim().equals("")){
show.append("输入信息"+content+"\n");
}else{
show.append("!ERROR:不能发送空文本!"+"\n");
}
input.setText("");
});
JPanel panel =new JPanel();
JLabel label = new JLabel("聊天信息");
panel.add(label);panel.add(input);panel.add(btn);
f.add(scr,BorderLayout.PAGE_START);
f.add(panel,BorderLayout.PAGE_END);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(Text::create);
}
}
11.5.3 标签组件
标签组件也是Swing中很常见的组件。常用的Swing标签组件是JLabel,JLabel组件可以显示文本、图像,还可以设置标签内容的垂直和水平对齐方式
JLabel的构造方法如下表:
方法声明 | 功能描述 |
---|
JLabel() | 创建无标题的JLabel实例 | JLabel(Icon image) | 创建具有指定图像的JLabel实例 | JLabel(Icon image, int horizontalAlignment) | 创建具有指定图像和水平对齐方式的JLabel实例 | JLabel**(String text)** | 创建具有指定文本的JLabel实例 | JLabel**(String text, Icon** icon**,** int horizontalAlignment**)** | 创建具有指定文本、图像和水平对齐方式的 JLabel 实例 | JLabel(String text, int horizontalAlignment) | 创建具有指定文本和水平对齐方式的 JLabel 实例 |
实例:
package GUI_test;
import java.awt.*;
import javax.swing.*;
public class lable_test {
private static void creat2() {
JFrame f = new JFrame("PanelDemo");
f.setLayout(new BorderLayout());
f.setSize(300, 200);
f.setLocation(300, 200);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label1 = new JLabel();
ImageIcon icon = new ImageIcon("src//image//bizhi.png");
Image img = icon.getImage();
img = img.getScaledInstance(300,150,Image.SCALE_DEFAULT);
icon.setImage(img);
label1.setIcon(icon);
JPanel p = new JPanel();
JLabel label2 = new JLabel("Hello !SCP...",JLabel.CENTER);
p.add(label2);
f.add(label1, BorderLayout.PAGE_START);
f.add(p, BorderLayout.PAGE_END);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(lable_test::creat2);
}
}
11.5.4 按钮组件
Swing常用的按钮组件有JButton、JCheckBox、JRadioButton等,它们都是抽象类AbstractButton类的直接或间接子类。AbstractButton的常用方法如下表
方法声明 | 功能描述 | |
---|
Icon getIcon() | 获取按钮的图标 | | void setIcon**(Icon icon)** | 设置按钮的图标 | | String getText() | 获取按钮的文本 | | void setText(String text) | 设置按钮的文本 | | void setEnable(boolean b) | 设置按钮是否可用 | | boolean setSelected(boolean b) | 设置按钮是否为选中状态 | | boolean isSelected() | 返回按钮的状态(true为选中,反之为未选中) | |
JCheckBox组件被称为复选框组件,它有选中和未选中两种状态。通常复选框会有多个,用户可以选中其中一个或者多个。JCheckBox的常用构造方法如下表
方法声明 | 功能描述 |
---|
JCheckBox**()** | 创建一个没有文本信息,初始状态未被选中的复选框 | JCheckBox(String text) | 创建一个带有文本信息,初始状态未被选定的复选框 | JCheckBox(String text,boolean selected) | 创建一个带有文本信息,并指定初始状态(选中/未选中)的复选框 |
实例:
package GUI_test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CB {
private static void creat23() {
JFrame f = new JFrame("PanelDemo");
f.setLayout(new BorderLayout());
f.setSize(300, 200);
f.setLocation(300, 200);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Hello ! Hero...",JLabel.CENTER);
label.setFont(new Font("宋体",Font.PLAIN,20));
JPanel panel = new JPanel();
JCheckBox one = new JCheckBox("ITALIC");
JCheckBox two = new JCheckBox("BOLD");
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int mode = 0;
if(one.isSelected()) mode+=Font.BOLD;
if (two.isSelected()) mode+=Font.ITALIC;
label.setFont(new Font("宋体",mode,20));
}
};
one.addActionListener(listener);two.addActionListener(listener);
panel.add(one);panel.add(two);
f.add(label);f.add(panel,BorderLayout.PAGE_END);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(CB::creat23);
}
}
JRadioButton组件被称为单选按钮组件,单选按钮只能选中一个,就像收音机上的电台控制按钮,当按下一个按钮,先前按下的按钮就会自动弹起。 对于JRadioButton按钮来说,当一个按钮被选中时,先前被选中的按钮就需要自动取消选中,但是JRadioButton组件本身并不具备这种功能,若想实现JRadioButton按钮之间的互斥,需要使用javax.swing.ButtonGroup类。ButtonGroup是一个不可见的组件,不需要将其添加到容器中显示,只是在逻辑上表示一个单选按钮组。将多个JRadioButton按钮添加到同一个单选按钮组中就能实现JRadioButton按钮的单选功能
JRadioButton的常用构造方法如下表
方法声明 | 功能描述 |
---|
JRadioButton () | 创建一个没有文本信息、初始状态未被选中的单选框 | JRadioButton (String text) | 创建一个带有文本信息、初始状态未被选定的单选框 | JRadioButton (String text,boolean selected) | 创建一个具有文本信息,并指定初始状态(选中/未选中)的单选框。 |
实例:
package GUI_test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class JRB {
private static void creat23() {
JFrame f = new JFrame("PanelDemo");
f.setLayout(new BorderLayout());
f.setSize(300, 200);
f.setLocation(300, 200);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Hello ! World !",JLabel.CENTER);
label.setFont(new Font("宋体",Font.PLAIN,20));
JPanel panel = new JPanel();
ButtonGroup group = new ButtonGroup();
JRadioButton one = new JRadioButton("斜体");
JRadioButton two = new JRadioButton("加粗");
group.add(one);group.add(two);
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int mode = 0;
if(one.isSelected()) mode+=Font.ITALIC;
if(two.isSelected()) mode+=Font.BOLD;
label.setFont(new Font("宋体",mode,20));
}
};
one.addActionListener(listener);two.addActionListener(listener);
panel.add(one);panel.add(two);
f.add(label);f.add(panel,BorderLayout.PAGE_END);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(JRB::creat23);
}
}
11.5.5 下拉框组件
JComboBox组件被称为下拉框或者组合框,它将所有选项折叠在一起,默认显示的是第一个添加的选项。当用户单击下拉框时,会出现下拉式的选择列表,用户可以从中选择其中一项并显示
JComboBox下拉框组件分为可编辑和不可编辑两种形式,对于不可编辑的下拉框,用户只能选择现有的选项列表。对于可编辑的下拉框,用户既可以选择现有的选项列表,也可以自己输入新的内容。需要注意的是,用户自己输入的内容只能作为当前项显示,并不会添加到下拉框的选项列表中
JComboBox的常用构造方法
方法声明 | 功能描述 |
---|
JComboBox**()** | 创建一个没有可选项的下拉框 | JComboBox(Object[] items) | 创建一个下拉框,将Object数组中的元素作为下拉框的下拉列表选项 | JComboBox(Vector items) | 创建一个下拉框,将Vector集合中的元素作为下拉框的下拉列表选项 |
JComboBox还提供了很多成员方法,JcomboBox常用的成员方法如下表
方法声明 | 功能描述 |
---|
void addItem(Object anObject) | 为下拉框添加选项 | void insertItemAt**(Object** anObject,int index) | 在指定的索引处插入选项 | Objct getItemAt(int index) | 返回指定索引处选项,第一个选项的索引为0 | int getItemCount**()** | 返回下拉框中选项的数目 | Object getSelectedItem() | 返回当前所选项 | void removeAllItems() | 删除下拉框中所有的选项 | void removeItem(Object object) | 从下拉框中删除指定选项 | void removeItemAt(int index) | 移除指定索引处的选项 | void setEditable(boolean aFlag) | 设置下拉框的选项是否可编辑,aFlag为true则可编辑,反之则不可编辑 |
应用实例:
package GUI_test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class JCB {
private static void creat23() {
JFrame f = new JFrame("PanelDemo");
f.setLayout(new BorderLayout());
f.setSize(350, 200);
f.setLocation(300, 200);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel jPanel = new JPanel();
JComboBox<String> comboBox = new JComboBox<>();
comboBox.addItem("请选择出生地");comboBox.addItem("诺克萨斯");
comboBox.addItem("皮尔特沃夫");comboBox.addItem("德玛西亚联邦");
comboBox.addItem("班德尔城");
JTextField textField = new JTextField(20);
comboBox.addActionListener(e-> {
String item = (String)comboBox.getSelectedItem();
if("请选择城市".equals(item)){
textField.setText("");
}else{
textField.setText("已选择出生地 "+item);
}
});
jPanel.add(comboBox);jPanel.add(textField);
f.add(jPanel,BorderLayout.PAGE_START);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(JCB::creat23);
}
}
11.5.6 下拉式菜单与弹出式菜单:
在GUI程序开发中,菜单是很常见的组件,利用Swing提供的菜单组件可以创建出多种样式的菜单,其中最常用的就是下拉式菜单和弹出式菜单,接下来对这两个菜单进行介绍
11.5.6.1 下拉式菜单
算机中很多文件的菜单都是下拉式的,如记事本的菜单。Swing提供了三个组件用于创建下拉式菜单,这三个组件分别是JmenuBar(菜单栏)、Jmenu(菜单)和JmenuItem(菜单项)
(1) JMenuBar:JMenuBar表示一个水平的菜单栏,用来管理一组菜单,不参与用户的交互式操作。菜单栏可以放在容器的任何位置,但通常情况下会使用顶级容器(如JFrame、Jdialog)的setJMenuBar()方法将菜单栏放置在顶级容器的顶部
JMenuBar有一个无参构造方法,创建菜单栏时,只需要使用new关键字创建JMenubar对象即可。创建完菜单栏对象后,通过对象调用**add(JMenu c)**方法为菜单栏添加JMenu菜单
(2) JMenu:JMenu表示一个菜单,它用来整合管理菜单项。菜单可以是单一层次的结构,也可以是多层次的结构。通常情况下,使用构造函数JMenu(String text)创建JMenu菜单,参数text表示菜单上的文本内容
Jmenu的常用方法如下表
方法声明 | 功能描述 |
---|
JMenuItem add(JMenuItem menuItem) | 将菜单项添加到菜单末尾,返回此菜单项 | void addSeparator() | 将分隔符添加到菜单的末尾 | JMenuItem getItem**(int pos)** | 返回指定索引处的菜单项,第一个菜单项的索引为0 | int getItemCount() | 返回菜单上的项数,菜单项和分隔符都计算在内 | JMenuItem insert(JmenuItem menuItem,int pos) | 在指定索引处插入菜单项 | void insertSeparator(int pos) | 在指定索引处插入分隔符 | void remove(int pos) | 从菜单中移除指定索引处的菜单项 | void remove(JMenuItem menuItem) | 从菜单中移除指定的菜单项 | void removeAll() | 从菜单中移除所有的菜单项 |
(3) JMenuItem:JMenuItem表示一个菜单项,它是下拉式菜单系统中最基本的组件。在创建JMenuItem菜单项时,通常使用构造方法**JMenumItem(String text)**为菜单项指定文本内容
JMenuItem继承自AbstractButton类,因此可以把它看成是一个按钮。如果使用无参构造方法创建了一个菜单项,则可以调用从AbstractButton类继承的setText(String text)方法和setIcon()方法为其设置文本和图标
实例:
package GUI_test;
import javax.swing.*;
import java.awt.*;
public class J_Menu {
private static void GUItest(){
JFrame f = new JFrame("JFrame窗口");
f.setLayout(new BorderLayout());
f.setSize(350, 200);
f.setLocation(300, 200);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar menuBar = new JMenuBar();
JMenu menu01 = new JMenu("文件(F)");
JMenu menu02 = new JMenu("帮助(H)");
menuBar.add(menu01);menuBar.add(menu02);
JMenuItem item01 = new JMenu("新建(N)");
JMenuItem item02 = new JMenu("退出(X)");
menu01.add(item01);menu01.addSeparator();menu01.add(item02);
item01.addActionListener(e->{
JDialog dialog = new JDialog(f,"无标题",true);
dialog.setSize(200,100);
dialog.setLocation(300,200);dialog.setVisible(true);
dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
});
item02.addActionListener(e->System.exit(0));
f.setJMenuBar(menuBar);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(J_Menu::GUItest);
}
}
11.5.6.2 弹出式菜单
对于弹出式菜单,相信大家也不陌生,在Windows桌面单击鼠标右键会弹出一个菜单,这就是弹出式菜单。在Swing组件中,弹出式菜单可以用JPopupMenu实现
JPopupMenu弹出式菜单和下拉式菜单一样,都通过调用add()方法添加JMenuItem菜单项,但JpopupMenu默认是不可见的,如果想要显示出来,必须调用它的show(Component invoker,int x,int y)方法。show()方法中的参数invoker用于显示JPopupMenu菜单的参考组件,x和y表示invoker组件坐标,表示的是以JPopupMenu菜单左上角为原点的坐标
实例:
package GUI_test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class JPM {
private static void GUItest3(){
JFrame f = new JFrame("JFrame窗口");
f.setLayout(new BorderLayout());
f.setSize(350, 200);
f.setLocation(300, 200);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem item01 = new JMenuItem("查看");
JMenuItem item02 = new JMenuItem("刷新");
popupMenu.add(item01);popupMenu.addSeparator();
popupMenu.add(item02);
f.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3);{
popupMenu.show(e.getComponent(),e.getX(),e.getY());
}
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(JPM::GUItest3);
}
}
|