GUI全称是Graphical User Interface,即图形用户界面或图型用户接口,就是应用程序提供给用户操作的图形界面,包括窗口、菜单、按钮、工具栏和其他各种图形界面元素。
Java中针对GUI设计提供了丰富的类库,这些类分别位于java.awt 和 javax.swing包中,简称为AWT和Swing。其中,AWT是SUN公司最早推出的一套API,他需要利用本地操作系统所提供的图形库,属于重量级组件,不跨平台,它的组件种类有限,可以提供基本的GUI设计工具,却无法实现目前GUI设计所需的所有功能。随后,SUN公司对AWT进行改进,提供了Swing组件,Swing组件有纯Java语言编写,属于轻量级组件,可跨平台,Swing不仅实现了AWT中的所有功能,而且提供了更加丰富的组件和功能,足以满足GUI设计的一切需求。
AWT适用于创建图形用户界面的一个工具包,它提供了一系类用于实现图形界面的组件,如窗口、按钮、文本框、对话框等。在JDK中针对每个组件都提供了对应的Java类,这些类都是位于java.awt包中,接下来通过一个图例来描述这些类的继承关系。
从上图继承关系可以看出,在AWT中组建分为两大类,这两类的基类分别是Component 和 MenuComponent。其中,MenuComponent是与菜单相关组件的父类,Component则是除菜单外其他AWT组件的父类,它表示一个能图形化方式显示出来并可与用户交互的对象。
Component类通常被成为组件,根据Component的不同作用,可将其分为基本组件类和容器类。基本组件类是诸如按钮(Button)、文本框(TextField)之类的图形界面元素,而容器类则是通过Component的子类Container实例化的对象。
组件是图形用户界面最基本的部分,也称为构件,是可以以图形化的方式显示在屏幕上,并能与用户进行交互的对象。组件不能独立的显示出来,必须将其放在一定的容器中才可以显示。
组件名称 | 构造方法 |
---|---|
按钮(Button) | Button b = new Button(“退出”); |
文本框(TextField) | TextField text = new TextField(); |
颜色(Color) | 非构造方法①setBackground(Color.BULE); ②setBackground(new Color(100, 100, 100)); |
字体(Font) | Font font = new Font(“宋体”, Font.BOLD, 10); |
Container类表示容器,它是一种特殊的组件,可以用来容纳其他组件。Container容器又分为两种类型,分别是Window(Frame)和Panel。
Window类是不依赖其他容器而独立存在的容器,它有两个子类,分别是Frame类和Dialog类。Frame类用于创建一个具有标题栏的框架窗口,作为程序的主页面。Dialog类用于创建一个对话框,实现用户信息交互。
要生成一个窗口,通常使用Window的子类进行实例化,而不是直接使用Window类,框架的外观就像平常Windows系统下的窗口,有标题、边框、菜单和大小等。
框架的构造方法:
Frame frm = new Frame("New Window");
Panel是一种透明的容器,没有标题和边框。与Frame不同,它不能作为最外层的容器单独存在,它首先必须作为一个组件放置在其他容器(Window或其子类)中,一个Panel对象代表一个长方形的区域,在这个区域中可以容纳其它组件。在java.swing中式JPanel。
面板的构造方法:
Panel panel = new Panel();
举例:创建一个简单的图形界面
import java.awt.*;
public class Test{
public static void main(String[] args){
// 建立一个新的窗体
Frame f = new Frame("新窗体");
// 设置窗体的宽和高
f.setSize(500, 300);
// 设置窗体在屏幕中所处的位置(参数是左上角坐标)
f.setLocation(300, 200);
// 设置窗体可见
f.setVisible(true);
}
}
运行后,结果如下,会出现一个“新窗体”的图形化界面。
下面分析一下上面代码所带的含义:
① 创建一个带有标题Frame窗体对象
Frame f = new Frame("新窗体");
② setSize()方法用于设置窗体对象的宽度和高度
f.setSize(500, 300);
③ setLocation()方法用于设置窗体对象在屏幕所处的坐标位置
f.setLocation(300, 200);
②③中的坐标全部为所处的左上角为(0,0)
④ setVisible(true)是用来设置创建的窗体是否隐藏状态
f.setVisible(true);
true为可见,false为不可见。
组件不能单独存在,必须放置与容器中,而组建在容器中的位置和尺寸是由布局管理器来决定的。在java.awt包中提供了5种布局管理器,分别是FlowLayout(流式布局管理器)、BorderLayout(边界布局管理器)、GridLayout(网格布局管理器)、GirdBagLayout(网格包布局管理器)和CardLayout(卡片布局管理器)。每个容器在创建是都会使用一种默认的布局管理器,在程序中可以通过调用容器对象的setLayout()方法设置布局管理器,通过布局管理器来自动进行组建的布局管理器。
最简单的布局,Panel的默认布局管理器。容器会将组件按照添加顺序从上到下、从左向右放置。当到达容器的边界是,会自动将组建放到下一行的开始位置。这些组件可以左对齐、居中对齐(默认方式)或右对齐的方式排列。
FlowLayout构造方法:
FlowLayout有3个构造方法。
方法声明 | 功能描述 |
---|---|
FlowLayout() | 组件默认居中对齐,水平、垂直间距默认为5个单位 |
FlowLayout(int align) | 制定组建相对于容器的对其方法,水平、垂直间距默认为5个单位 |
FlowLayout(int align, int hgap, int vgap) | 指定组件的对齐方式和水平、垂直间距 |
注意:
① 参数align决定组件在每行中相对于容器边界的对齐方式,可以使用该类中提供的常量作为参数传递给构造方法。
import java.awt.*;
public class Test{
public static void main(String[] args){
final Frame f = new Frame("Flowlayout"); //创建名为Flowlayout的窗体
//设置布局管理器为FlowLayout,所有组件左对齐,水平间距为20,垂直间距为30
f.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 30));
f.setSize(220, 300); //设置窗体大小
f.setLocation(300, 200); //设置窗体显示的位置
f.add(new Button("第一个按钮")); //把"第一个按钮"添加到f窗口
f.add(new Button("第二个按钮"));
f.add(new Button("第三个按钮"));
f.add(new Button("第四个按钮"));
f.add(new Button("第五个按钮"));
f.add(new Button("第六个按钮"));
f.setVisible(true); //设置窗体可见
}
}
运行结果如下所示:
特点:
① 所有组件像流水一样依次排列,不需要用户明确地设定,但灵活性上相对差。
② 窗体拉伸变宽,按钮的大小和按钮之间的间距保持不变,但按钮相对于容器边界的距离会发生变化。
复杂的布局,Frame的默认布局管理器。将容器划为5个区域,分别是东(EAST)、南(SOUTH)、西(WEST)、北(NORTH)、中(CENTER)。组件可以被放置在这5个区域中的任意一个。
注意:
① 箭头是指改变容器大小时各个区域需要改变的方向。
就是说,在改变容器时,NORTH和SOUTH区域高度不变,长度调整;WEST和EAST区域宽度不变,高度调整;CENTER会进行相应调整。
② 向BorderLayout布局管理器中添加组件是,需要使用add(Component comp, Object constraints)方法。
import java.awt.*;
public class Test{
public static void main(String[] args){
final Frame f = new Frame("BorderLayout");
f.setLayout(new BorderLayout());
f.setSize(300, 300);
f.setLocation(300, 200); //设置窗体大小
// 创建5个按钮
Button bt1 = new Button("东");
Button bt2 = new Button("西");
Button bt3 = new Button("南");
Button bt4 = new Button("北");
Button bt5 = new Button("中");
// 将创建好的代码添加到窗体中,并设置按钮所在的区域
f.add(bt1, BorderLayout.EAST);
f.add(bt2, BorderLayout.WEST);
f.add(bt3, BorderLayout.SOUTH);
f.add(bt4, BorderLayout.NORTH);
f.add(bt5, BorderLayout.CENTER);
f.setVisible(true);
}
}
运行结果如下所示:
特点:
① 可以限定各区域的边界,当用户改变容器窗口大小时,各个组件的相对位置不变。
② 向BorderLayout的布局管理器中添加组件是,如果不能指定添加到哪个区域,则默认添加到CENTER区域,并且每个区域只能放置一个组件,如果向一个区域中添加多个组件,后放入的组件会覆盖先放入的组件。
使用纵横线将容器分为n行m列大小相等的网络,每个网络中放置一个组件。添加到容器中的组件首先防止在第一个行第一列(左上角)的网络中,然后再第1行的网格中从左向右一次放置其它组件。行满后,继续在下一行中从左至右防止组件。与FlowLayout不同的是,放置在GridLayout布局管理器中的组件将会自动占据网格的整个区域。
GridLayout构造方法:
方法声明 | 功能描述 |
---|---|
GridLayout() | 默认只有一行,每个组件占一列 |
GridLayout(int rows, int cols) | 指定容器的行数和列数 |
GridLayout(int rows, int cols, int hgap, int vgap) | 指定容器的行数和列数以及组件之间水平、垂直间距 |
注意:
① 参数代表意义:
import java.awt.*;
public class Test{
public static void main(String[] args){
Frame f = new Frame("GridLayout"); //创建一个名为GridLayout的窗体
f.setLayout(new GridLayout(3, 3)); //设置该窗体为3*3的网络
f.setSize(300, 300); //设置窗体大小
f.setLocation(400, 300);
// 下面的代码是循环添加9个按钮到GridLayout中
for(int i = 0; i <= 9; i++)
{
Button bti = new Button("bt" + i);
f.add(bti); //向窗体中添加按钮
}
f.setVisible(true); //设置窗体可见
}
}
运行结果如下所示:
特点:
① 组件的相对位置不随区域的缩放而改变,但组件的大小会随之改变,组件始终占据网格的整个区域。
② 缺点是总忽略组件的最佳大小,所有组件的宽高都相同。
最灵活、最复杂的布局管理器。与GraiLayout布局管理器类似,不同的是,它允许网格中的组件大小各不相同,而且允许一个组件跨越一个或者多个网格。
使用GridLayout布局管理器的步骤如下:
① 创建GridLayout布局管理器,并使容器采用该布局管理器。
GridLayout layout = new GridLayout();
container.setLayout(gl);
② 创建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类中有许多表示约束的属性,下面对GridBagConstraints类中的一些常用属性进行介绍,
属性 | 作用 |
---|---|
gridx和gridy | 设置组件的左上角所在网格的横向和纵向索引(即所在的行和列)。如果将gridx和gridy的值设为GridBagConstraints.RELATIVE(默认值),表示当前组件紧跟在上一个组件后面 |
gridwidth和gridheight | 设置组件横向、纵向跨越几个网格,两个属性都是1.如果如果把这两个属性的值设为GridBagConstraints.REMAINER,表示当前组件其行或其列上为最后一个组件。如果把这两个属性的值设为GridBagConstraints.RELATIVE表示当前组件在其行或列上为倒数第2个组件 |
fill | 如果当组件的显示区域大于组件需要的大小,设置是否以及如何改变组件大小,该属性接受以下几个属性值。① NONE:默认,不改变组件大小 ② HORIZONTAL:使组件水平方向足够长以填充显示区域,但是高度不变 ③ VERTICAL:使组件垂直方向足够高以填充显示区域,但长度不变 ④ BOTH:使组件足够大,以填充整个显示区域 |
weightx和weighty | 设置组件占领容器中多于的水平方向和垂直方向空白的比例(也称为权重)。假设容器的水平方向放置3个组件,其weightx分别为1、2、3,当容器宽度为增加60个像素时,这3个容器分别增加10、20和30的像素。这两个属性的默认值是0,即不占领多余的空间 |
总结:
import java.awt.*;
class Layout extends Frame {
public Layout(String title)
{
GridBagLayout layout = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
this.setLayout(layout);
c.fill = GridBagConstraints.BOTH; //设置组件横向纵向可以拉伸
c.weightx = 1; //设置横向权重为1
c.weighty = 1; //设置纵向权重为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; //设置纵向权重
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; //设置横向权重为2
c.weighty = 2; //设置纵向权重为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); //设置窗体可见
}
//每次添加组件的时候都要调用setConstraints的方法,将GridBagConstraints对象与按钮组件相关联
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 Test{
public static void main(String[] args){
new Layout("GridBagLayout");
}
}
运行结果如下:
由上图我们可以看到,由于在添加btn5~btn7时,将权重weightx和weighty的值设为0,因此在高度拉伸时没有变化,但长度受上下组件的影响,还是会随着窗口变大。
在操作系统中经常会遇到通过选项卡按钮来切换程序的界面,这些界面就相当于一张张卡片,而管理这些卡片的布局管理器就是卡片布局管理器(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的组件,如果不存在则不会发生任何操作 |
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 Test {
public static void main(String[] args) {
Cardlayout cardlayout=new Cardlayout();
}
}
文件中,在顶层Frame容器采用BordLayout布局,CENTER和SOUTH区域分别放置cardPanel和controlpaPanel面板,其中cardPanel采用CardLayout布局管理器,其中放置了三个Label标签代表三个卡片。controlpaPanel中放置了两个名为“上一张卡片”和“下一张卡片”按钮,通过单击这两个按钮,会触发按钮的时间监听器,条用cardLayout的previous()和next()方法对cardPanel面板中的卡片进行切换。
特点: 是可以使两个或者更多的界面共享一个显示空间,某一时刻只有一个界面可见。
当一个容器被创建后,他们都会有一个默认的布局管理器。Window、Frame和Dialog的默认布局管理器是BorderLayou,Panel的默认布局管理器是FlowLayout。如果不希望通过布局管理器来对容器进行布局,也可以调用容器的setLayout(null)方法,将布局管理器都取消。在这种情况下,程序必须调用容器中每个组件的setSize()和setLocation()方法或者是setBounds()方法(这个方法接收4个参数,分别是左上角的x、y坐标和组件
import java.awt.*;
public class Test{
public static void main(String[] args){
Frame f = new Frame("hello");
f.setLayout(null); //取消frame的布局管理器
f.setSize(300, 150);
Button btn1 = new Button("press");
Button btn2 = new Button("pop");
btn1.setBounds(40, 60, 100, 30);
btn2.setBounds(140, 90, 100, 30);
//向窗口中添加按钮
f.add(btn1);
f.add(btn2);
f.setVisible(true);
}
}