文章目录
1 GUI简介
GUI的全称是Graphical User Interface,即图形用户界面。顾名思义,就是应用程序提供给用户操作的图形界面,包括窗口、菜单、按钮、工具栏和其他各种用户界面元素。Java中针对GUI设计提供了丰富的类库,这些类分别位于java.awt
和javax.swing
包中,简称为AWT和Swing。
其中AWT是SN公司最早推出的一套API,它需要利用本地操作系统所提供的图形库,属于重量级组件、不跨平台,它的组件种类有限,可以提供基本的GUI设计工具、却无法实现目前GUI设计所需要的所有功能。随后SUN公司对AWT进行了改进,提供了Swing组件,Swing组件由纯Java语言编写,属于轻量级组件,可跨平台。
Swing不仅实现了AWT中的所有功能,而且提供了更加丰富的组件和功能,足以满足GUI设计的一切需求。
2 AWT概述
AWT是用于创建图形用户界面的一个工具包,它提供了一系列用于实现图形界面的组件,如窗口、按钮、文本框、对话框等。在JDK中针对每个组件都提供了对应的Java类,这些类都位于java.awt
包中。
2.1 Componter&MenuComponent
由图可以看出,AWT中组件分为两大类,这两大类的基类分别是Componter
和MenuComponent
。其中MenuComponent
是所有与菜单相关组件的父类,Componter
则是除菜单外其他AWT组件的父类,它表示一个能以图形化方式显示出来并可与用户交互的对象。
Componter
类通常被称为组件,根据Component不同作用,可将其分为基本组件类
和容器类
。基本组件类是诸如按钮、文本框之类的图形界面元素,而容器类则是通过Component的子类Container实例化的对象。Container表示容器,它是一种特殊的组件,可以用来容纳其它组件,Container容器又分为两种类型,分别是Window和Panel。
2.2 Window
Window类是不依赖其它容器而独立存活的容器,它有两个子类Frame
和Dialog
。Frame
类用于创建一个具有标题栏的框架窗口,作为程序的主界面;Dialog
类用于创建一个对话框,实现与用户的信息交互。
2.3 Panel
Panel
也是一个容器但是它不能独立存在,只能存在于其他容器(Window或其子类)中,一个Panel对象代表了一个长方体区域,在这个区域里可以容纳其它组件,在程序中通常会使用Panel来实现一些特殊的布局。
2.4 创建一个简单的图形界面
import java.awt.*;
public class Example {
public static void main(String[] args) {
//建立新窗体(Frame用于创建一个具有标题栏的框架窗口)
Frame f=new Frame("我的窗体!");
//设置窗体的宽高
f.setSize(400, 300);
//设置窗体在屏幕中所处的位置(参数是左上角坐标)
f.setLocation(300,200);
//设置窗体可见
f.setVisible(true);
}
}
3 布局管理器
从上述分析,我们知道组件不能独立存在,必须放在相应的容器中,而组件在容器中的位置和尺寸是由布局管理器来决定的。在java.awt
包中提供了五种布局管理器,分别是FlowLayout(流式布局管理器)
、Border Layout(边界布局管理器)
、GridLayout(网格布局管理器)
、GridBagLayout(网格包布局管理器)
、CardLayout(卡片布局管理器)
。每个容器在创建时都会有一种默认的布局管理器,在程序中可以调用容器对象的setLayout()
方法设置布局管理器,通过布局管理器来自动进行组件的布局管理,例如把一个Frame窗体的布局管理器设置为FlowLayout,代码如下所示:
Frame frame=new Frame();
frame.setLayout(new FlowLayout);
3.1 FlowLayout
流式布局管理器
是最简单的布局管理器,在这种布局下,容器会将组件按照添加顺序从左向右放置,当容器到达边界时,会自动将组件放到下一行的开始位置,这些组件可以左对齐、居中对齐(默认对齐)、或右对齐的方式排列。FlowLayout对象有3个构造方法:
方法声明 | 功能描述 |
---|---|
FlowLayout() | 组件默认居中对齐、水平、垂直间距默认为5个单位 |
FlowLayout(int align) | 指定组件相对于容器的对方式、水平、垂直间距默认为5个单位 |
FlowLayout(int align,int hgap,int vgap) | 指定组件的对齐方式和水平、垂直间距 |
- 参数align决定组件在每行中相对于容器边界的对齐方式,可以使用该类中提供的常量作为参数传递给构造方法。FlowLayout.LEFT(左对齐)、FlowLayout.RIGHT(右对齐)、FlowLayout.CENTER(居中)
- 参数hgap、vgap分别设定组价之间的水平和垂直间隙,可以填入任意一个数值。
3.1.1 流式布局管理器的布局效果
package Example;
import java.awt.*;
public class Ex {
public static void main(String[] args) {
//Frame类用于创建一个具有标题栏的框架窗口
final Frame f = new Frame("FlowLayout");
//设置布局管理器,所有组件左对齐,水平间距为20,垂直间距为30
f.setLayout(new FlowLayout(FlowLayout.LEFT,20,30));
//设置窗体大小
f.setSize(400, 300);
//设置窗体显示的位置
f.setLocation(300, 200);
//添加6个按钮
f.add(new Button("第一个按钮"));
f.add(new Button("第二个按钮"));
f.add(new Button("第三个按钮"));
f.add(new Button("第四个按钮"));
f.add(new Button("第五个按钮"));
f.add(new Button("第六个按钮"));
//设置窗体可见
f.setVisible(true);
}
}
FlowLayout 布局管理器 的特点就是可以将所有的组件像流水一样依次进行排列,不需要用户明确的设定,但是在灵活性上相对差了点,若将上述窗体拉伸变宽,按钮的大小和按钮之间的间距将保持不变,但按钮相对于容器边界的距离会发生改变
。
3.2 BorderLayout
BorderLayout(边界布局管理器)是一种较为复杂的布局方式,它将容器划分为5个区域,分别是东(EAST)、南(SOUTH)、西(WEST)、北(NORTH)、中(CENTER)。组件可以被放置在这5个区域中的任何一个区域,BorderLayout布局效果图如图所示:
图中箭头是指改变容器大小时各个区域需要改变的方向,也就是说,在改变容器时,NORTH和SOUTH区域高度不变长度调整,EAST和WEST宽度不变高度调整,CENTER会相应的进行调整。
当向BorderLayout布局管理器的容器中添加组件时,需要使用add(Component comp,Object constaints)
方法,其中comp表示要添加的组件,constraints指定将组件添加到布局中的方式和位置的对象,它是一个Object对象,在传参时可以使用BorderLayout类提供的5个常量,它们分别是EAST、SOUTH、WEST、NORTH、CENTER。
3.2.1 边界布局管理器的布局效果
package Example;
import java.awt.*;
public class Ex {
public static void main(String[] args) {
//Frame类用于创建一个具有标题栏的框架窗口
final Frame f = new Frame("BorderLayout");
//设置布局管理器为边界布局管理器
f.setLayout(new BorderLayout());
//设置窗体大小
f.setSize(300, 300);
//设置窗体显示的位置
f.setLocation(300, 200);
//设置窗体可见
f.setVisible(true);
f.add(new Button("东部"),BorderLayout.WEST);
f.add(new Button("西部"),BorderLayout.EAST);
f.add(new Button("南部"),BorderLayout.SOUTH);
f.add(new Button("北部"),BorderLayout.NORTH);
f.add(new Button("中部"),BorderLayout.CENTER);
}
}
文件中,为Frame容器设置了BorderLayout(边界布局管理器)可以不用设置,因为Frame默认使用BorderLayout布局管理系统
,在容器的东南西北中5个区域放置了5个按钮。
BorderLayout的好处就是可以限定各区域的边界,当用户改变容器窗口大小时,各个组件的相对位置不变。但需注意的是,向BorderLayout的布局管理器添加组件时,如果不指定添加到哪个区域,则默认添加到CENTER区域,并且每个区域只能放置一个组件,如果向一个区域中添加多个组件时,后放入的组价会覆盖先放入的组件。
3.3 GridLayout
GridLayout(网格布局管理器)使用纵横线将容器分为n行m列大小相等的网络,每个网格中放置一个组件。添加到容器中的组件首先放置在第一行第一列(左上角)的网格中,然后在第一行的网格中从左至右依次放置其它组件。行满后,继续在下一行中从左至右放置组件。与FlowLayout不同的是,放置在GridLayout布局管理器中的组价将自动占据网格的整个区域。GridLayout的构造方法:
方法声明 | 方法描述 |
---|---|
GridLayout() | 默认只有一行,每个组件占1列 |
GridLayout(int rows,int cols) | 指定容器的行数和列数 |
GridLayout(int rows,int cols,int hgap,int vgap) | 指定容器的行数和列数以及组件之间水平、垂直间距 |
构造方法中,参数rows表示行数,cols表示列数,hgap和vgap规定水平和垂直方向的间隙。水平间隙指的是网格之间的水平距离,垂直间隙是指网格之间的垂直距离。
3.3.1 网格布局管理器的布局效果
package Example;
import java.awt.*;
public class Ex {
public static void main(String[] args) {
//Frame类用于创建一个具有标题栏的框架窗口
final Frame f = new Frame("GridLayout");
//设置布局管理器为边界布局管理器
f.setLayout(new GridLayout(3,3));
//设置窗体大小
f.setSize(300, 300);
//设置窗体显示的位置
f.setLocation(400, 300);
//循环放置9个按钮
for(int i=1;i<=9;i++)
{
f.add(new Button("bt"+i));
}
//设置窗体可见
f.setVisible(true);
}
}
GridLayout 布局管理系统的特点是:组件的相对位置不随区域的缩放而改变,但组件的大小会随之改变,组件始终占据网格的整个区域,缺点就是忽略组件的最佳大小,所有组件的宽高均相同。
3.4 GridBagLayout
GridBagLayout(网格包布局管理器)是最灵活、最复杂的布局管理器。与GridLayout布局管理器类似,不同的是,它允许组件大小各有不同,而且允许一个组件跨越一个或者多个网格。
使用网格包布局管理器的步骤如下:
- 创建GridBagLayout布局管理器,并使容器采用该布局管理器
GridBagLayout layout=new GridBagLayout();
container.setLayout(layout);
- 创建GridBagContraints对象(布局约束条件),并设置该对象的相关属性。
GridBagConstraints constraints = new GridBagConstraints ();
constraints.gridx=1;//设置网格的左上角横向索引
constraints.gridy=1;//设置网格的左上角纵向索引
constraints.gridwidth=1;//设置组件横向跨越的网络
constraints.gridheight=1;//设置组件纵向跨越的网络
- 调用GridBagLayout对象的setConstraints()方法建立GridBagConstraints对象和受控组件之间的关联
layout.setConstraints(component,constraints);
- 向容器中添加组件
container.add(conponent);
GridBagConstraints 对象可以重复使用,只需要改变它的属性即可。如果要向容器中添加多个组件,则重复步骤(2)、步骤(3)、步骤(4)。
从上面的步骤可以看出,使用GridBagLayout布局管理器的关键在于GridBagConstraints对象,它才是控制容器中每个组件布局的核心类,在GridBagConstraints类中有许多表示约束的属性,下面对GridBag Constraints类的一些常用属性进行介绍:
属性 | 作用 |
---|---|
gridx和gridy | 设置组件的左上角所在网络的横向和纵向索引(即所在的行和列)如果将gridx和gridy的值设置为GridBagConstraints.RELATIVE(默认值),表示当前组件紧跟在上一个组件后面 |
gridwidth和gridheight | 设置组件横向纵向跨越几个网格,两个属性的默认值都是1,如果把这两个属性的值设为GridBagConstraints.REMAINER ,表示当前组件在其行或列上为最后一个组件,如果把这两个属性的值设为GridBagConstraints.RELATIVE ,表示当前组件在其行或列上为倒数第二个组件 |
fill | 如果当组件的显示区域大于组件所需要的大小,设置是否以及如何改变组件大小,该属性接收以下几个属性值:1.NONE :默认,不改变组件大小 2.HORIZONTAL :使组件水平方向足够长以填充显示区域,但是高度不变 3. VERTICAL :使组件垂直方向足够高以填充显示区域,但是长度不变 4 BOTH :使组件足够大,以填充整个显示区域 |
weightx和weighty | 设置组件占领容器中多余的水平方向和垂直方向的空白比例(也称为权重)假设容器的水平方向设置三个组件,其中weightx为1,2,3,当容器宽度增加60个像素时,这三个容器分别增加10,20,30的像素 ,这两个属性默认值均为0,即不占领多余的空间 |
3.4.1 网格包布局管理器的布局效果
import java.awt.*;
class Layout extends Frame{
public Layout(String title)
{
//创建GridBagLayout布局管理器
GridBagLayout layout=new GridBagLayout();
GridBagConstraints c=new GridBagConstraints();
this.setLayout(layout);
//设置组件横向纵向可以拉伸
c.fill=GridBagConstraints.BOTH;
//设置横向权重为1,纵向权重为1
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);
//设置横向权重为0,纵向权重为0
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;
//设置组件的横向权重为2,纵向权重为2
c.weightx=2;
c.weighty=2;
this.addComponent("btn8", layout, c);
//添加组件是本行的最后一个组件
c.gridwidth=GridBagConstraints.REMAINDER;
//设置组件纵跨1个网络
c.gridheight=1;
this.addComponent("btn9", layout, c);
this.addComponent("btn10", layout, c);
this.setTitle("GridBagLayout");
this.pack();
this.setVisible(true);
}
private void addComponent(String name, GridBagLayout layout,
GridBagConstraints c) {
Button bt=new Button(name); //创建一个名为name的按钮
layout.setConstraints(bt, c);//设置GridBagConstraints和按钮的关联
this.add(bt);
}
}
public class Ex {
public static void main(String[] args) {
new Layout("GridBagLayout");
}
}
向GridBagLayout布局管理器中添加10个按钮,由于每次添加时都需要调用该布局队的setConstraints()方法,将GridBagConstraints 与按钮组件相关联,因此可以将这段关联的代码抽取到addCompenent()方法中,简化书写。
在添加按钮1~ 按钮4,按钮8~ 按钮10,都将权重weights和weighty的值设置为大于0,因此在拉伸窗口时,这些按钮会随着窗口变大。而在添加按钮5~ 按钮7时,都将权值设置为0,这样它们的高度在拉伸时没有变化,但是长度受上下组件的影响,还会随窗口变大。
3.5 CardLayout
在操作系统中经常会遇到通过选项卡按钮来切换程序的界面,这些界面就相当于一张张卡片,而管理这些卡片的布局管理器就是卡片布局管理器(CardLayout)。卡片布局管理器将界面看做是一系列卡片,在任何时候只要其中一张卡片是可见的,这张卡片占据容器的整个区域。
卡片布局管理中经常会用到的方法:
方法声明 | 功能描述 |
---|---|
void first(Containers parent) | 显示parent容器的第一张卡片 |
void last(Containers parent) | 显示parent容器的最后一张卡片 |
void previous(Containers parent) | 显示parent容器的前一张卡片 |
void next(Containers parent) | 显示parent容器的下一张卡片 |
void show(Containers parent,String name) | 显示parent容器中名为name的组件,如果不存在则不会发生任何操作 |
3.5.1 卡片布局管理器的布局效果
import java.awt.*;
import java.awt.event.*;
class Cardlayout extends Frame implements ActionListener{
//定义面板放置卡片
Panel cardPanel=new Panel();
//定义面板放置按钮
Panel controlpaPanel = new Panel();
Button nextButton,preButton;
CardLayout cardLayout =new CardLayout();
//设置卡片布局管理器的属性
public Cardlayout()
{
setSize(300,200);
setVisible(true);
//为窗口添加关闭事件监听器
this.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
Cardlayout.this.dispose();
}
});
cardPanel.setLayout(cardLayout);
//在cardPanel面板对象中添加3个文本文件
cardPanel.add(new Label("第一个界面",Label.CENTER));
cardPanel.add(new Label("第二个界面",Label.CENTER));
cardPanel.add(new Label("第三个界面",Label.CENTER));
//创建两个按钮对象
nextButton = new Button("下一张卡片");
preButton = new Button("上一张卡片");
//为按钮对象注册监听器
nextButton.addActionListener(this);
preButton.addActionListener(this);
//将按钮添加到controlpaPanel面板中
controlpaPanel.add(preButton);
controlpaPanel.add(nextButton);
//将cardPanel面板放置在窗口边界布局的中间,窗口默认为边界布局
this.add(cardPanel,BorderLayout.CENTER);
//将controlpaPanel面板放置在窗口边界布局的南区
this.add(controlpaPanel,BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==nextButton)
{
//切换到面板中的组件,若当前组价为最后一个组件,则显示第一个组件
cardLayout.next(cardPanel);
}
if(e.getSource()==preButton)
{
//切换到面板中的组件,若当前组件为第一个组件,则显示最后一个组件
cardLayout.previous(cardPanel);
}
}
}
public class Ex {
public static void main(String[] args) {
Cardlayout cardlayout=new Cardlayout();
}
}
文件中,在顶层Frame容器采用BordLayout布局,CENTER和SOUTH区域分别放置cardPanel和controlpaPanel面板,其中cardPanel采用CardLayout布局管理器,其中放置了三个Label标签代表三个卡片。controlpaPanel中放置了两个名为“上一张卡片”和“下一张卡片”按钮,通过单击这两个按钮,会触发按钮的时间监听器,条用cardLayout的previous()和next()方法对cardPanel面板中的卡片进行切换。
CardLayout的优点是可以使两个或者更多的界面共享一个显示空间,某一时刻只有一个界面可见。