复杂的GUI要求其中的每一个组件都放置到精确的位置。它们通常由多个面板组成,每个面板上的组件都按指定的顺序排列。Java利用布局管理器来帮助设计人员安排容器上的组件。
在Java中,将组件置于容器上的方式可能与GUI系统有所不同。首先,所有东西都是程序代码,没有所谓“资源”用来控制组件位置;其次,组件摆放在容器上的方式并不是通过绝对定位,而是通过“布局管理器(Layout Manager)”来安排。布局管理器会依据组件的加入顺序决定其摆放方式。组件的大小、形状和位置在不同的布局管理器下有显著的不同。此外,布局管理器会自动适应小程序或应用程序窗口的大小,所以如果某个窗口的大小改变了,那么其上各个组件的大小、形状和位置都有可能发生改变。
Java提供以下几种布局管理器:流布局(FlowLayout)、网格布局(GridLayout)、边界布局(BorderLayout)、卡片布局(CardLayout)和手工布局管理器。这里主要讲述流布局、网格布局、边界布局和卡片布局。可以利用容器类setLayout方法为容器设置布局管理器。
FlowLayout管理器是Panel和Applet 的默认布局管理器。其组件的放置规律是从上到下、从左到右,如果容器足够宽,第一个组件先添加到容器中第一行的最左边,后续的组件依次添加到上一个组件的右边,如果当前行已放置不下该组件,则放置到下一行的最左边。
FlowLayout类提供的构造方法主要有以下几个。
· public FlowLayout( ):创建居中对齐、水平和垂直间距为5像素的FlowLayout对象。
· public FlowLayout(int align):以指定的对齐方式创建水平和垂直间距为5像素的FlowLayout对象。
· public FlowLayout(int align, int hgap, int vgap):以指定的对齐方式、水平和垂直间距创建FlowLayout对象。
FlowLayout中的对齐方式有3种:FlowLayout.LEF(左对齐)、FlowLayout.RIGHT(右对齐)和FlowLayout.CENTER(中央对齐)。
【例10-1】本例中的MyFlowLayout类演示了对3个按钮的简单管理效果。程序文件名为MyFlowLayout.java。
import java.awt.*;
//定义处理窗口事件的类CloseFrame,实现WindowListener接口
class CloseFrame implements WindowListener
{
public void windowClosing(WindowEvent e) {
System.exit(1);
} //退出系统
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowOpened(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
}
class MyFlowLayout
{
public static void main(String args[])
{
Frame f = new Frame();
f.setLayout(new FlowLayout()); //设置窗体容器的布局管理器为流式管理器
Button button1 = new Button(" First");
Button button2 = new Button("Second");
Button button3 = new Button("Third");
f.add(button1);
f.add(button2);
f.add(button3);
f.addWindowListener(new CloseFrame());
f.setSize(300,100);
f.setVisible(true);
}
}
运行效果如图10-4所示。
当容器的大小发生变化时,用FlowLayout 管理的组件会发生变化,其变化规律是:组件的大小不变,但是相对位置会发生变化。例如图10-4中3个按钮都处于同一行,如果把该窗口变窄,窄到刚好只能够放下一个按钮,则第二个按钮将折到第二行,第三个按钮将折到第三行。
图10-4 流布局
GridLayout 是一种网格状的布局,各个组件平均占据容器的空间。在生成GridLayout管理器对象时,需指明行数和列数,同时也可以指明各个组件之间的间距。当改变容器的大小时,其中的组件相对位置不变而大小改变,各个组件的排列方式为:从上到下、从左到右依次排列。
创建网格布局管理器对象常用下面两种构造方法来实现。
· public GridLayout(int rows, int cols):以指定的行列数创建GridLayout对象。
· public GridLayout(int rows, int cols, int hgap, int vgap):以指定的行列数与水平垂直间距创建GridLayout对象。
如果要创建一个行数固定的GridLayout对象,可以设置列参数cols为0,同样;如果要创建一个列数固定的GridLayout对象,可以设置行参数rows为0。
【例10-2】一个GridLayout管理器的简单应用示例。
import java.awt.*;
public class MyGridLayout
{
public static void main(String args[])
{
Frame f = new Frame("GridLayout");
f.setLayout(new GridLayout(3,2));
f.add(new Button("1")); //第一行第一列
f.add(new Button("2")); //第一行第二列
f.add(new Button("3")); //第二行第一列
f.add(new Button("4")); //第二行第二列
f.add(new Button("5")); //第三行第一列
f.add(new Button("6")); //第三行第二列
f.addWindowListener(new CloseFrame()); //closeFrame类参见例10-6
图10-5 网格布局
|
f.setVisible(true);
}
}
运行结果如图10-5所示。
BorderLayout管理器是Window、Frame和Dialog的默认布局管理器。BorderLayout管理器把容器分成5个区域:North、South、East、West和Center,每个区域只能放置一个组件。
BorderLayout 类提供的构造方法主要有两个。
· public BorderLayout( ):创建水平和垂直间距都为零的BorderLayout 对象。
· public BorderLayout(int hgap, int vgap):以指定的水平和垂直间距来创建BorderLayout对象。
【例10-3】本例中的MyBorderLayout 类演示了水平和垂直间距都为零时的布局管理效果。程序文件名为MyBorderLayout.java。
import java.awt.*;
class MyBorderLayout
{
public static void main(String args[])
{
Frame f = new Frame("BorderLayout");
f.setLayout(new BorderLayout()); //设置窗体容器的布局管理器
//在不同方位加入不同的按钮
图10-6 边界布局
|
f.add("South", new Button("南"));
f.add("East", new Button("东"));
f.add("West", new Button("西"));
f.add("Center", new Button("中间"));
f.addWindowListener(new CloseFrame());
f.setSize(200,200);
f.setVisible(true);
}
}
运行结果如图10-6所示。
CardLayout管理器把容器分成许多层,每层的显示空间占据整个容器的大小,但是每层只允许放置一个组件。当然每层都可以利用Panel 来实现复杂的用户界面,形成同一显示空间上的多层显示的效果。可以想像共享成员之间就像扑克牌一样摞在一起,只有最上面的成员是可见的,CardLayout管理器处理这些成员时就像在换牌:可以定义每张牌的名字,通过牌的名字来选择;也可以顺着牌序向前或向后翻牌;或者直接选择第一张或者最后一张。
CardLayout类提供了两个构造方法来创建CardLayout对象。
· public CardLayout( ):创建一个间距为0的CardLayout对象。
· public CardLayout(int hgap, int vgap):以指定的间距创建一个CardLayout对象。
CardLayout类也提供了一些常用的方法来管理布局和组件,如表10-5所示。
表10-5 CardLayout类中常用的方法
方 法 |
说 明 |
public int getHgap() |
获取水平间距 |
public int getVgap() |
获取垂直间距 |
public void first(Container parent) |
指定当前组件为第一个加入的组件 |
public void next(Container parent) |
指定当前组件为下一个加入的组件 |
续上表
方 法 |
说 明 |
public void previous(Container parent) |
指定当前组件为上一个加入的组件 |
public void last(Container parent) |
指定当前组件为最后一个加入的组件 |
public void setHgap(int hgap) |
重置水平间距 |
public void setVgap(int vgap) |
重置垂直间距 |
【例10-4】本例的MycardLayout.java程序采用两个面板,一个面板以FlowLayout管理器来管理按钮,另一个则以CardLayout管理器管理20个画布组件,根据按钮来显示不同的画布组件,窗体则以BorderLayout管理器来管理两个面板组件。
import java.awt.*;
import java.awt.event.*;
class MyCardLayout implements ActionListener
{
static CardLayout myCard=new CardLayout(); //创建布局管理器
static Panel p1=new Panel();
public static void main(String args[])
{
int i;
MyCanvas my[]=new MyCanvas[21]; //创建数据元素为MyCanvas对象的数组
p1.setLayout(myCard); //设置CardLayout管理器
for(i=1;i<=20;i++)
{
my[i]=new MyCanvas(i,i); //创建一个画布,半径为i,i
p1.add("i am"+i,my[i]);
}
Panel p2=new Panel();
p2.setLayout(new FlowLayout()); //设置流式布局管理器
Button b1=new Button("第一张");
Button b2=new Button("下一张");
Button b3=new Button("最后一张");
p2.add(b1);
p2.add(b2);
p2.add(b3);
//对各个按钮注册监听器
b1.addActionListener(new MyCardLayout());
b2.addActionListener(new MyCardLayout());
b3.addActionListener(new MyCardLayout());
Frame f=new Frame("请看我的画图效果!");
f.setLayout(new BorderLayout());
f.add(p1,"Center");
f.add(p2,"South");
f.setBounds(0,0,260,200);
f.addWindowListener(new CloseFrame()); //closeFrame类参见例10-6
f.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand()=="第一张")
myCard.first(p1); //显示第一张
if (e.getActionCommand()=="下一张")
myCard.next(p1); //显示下一张
if (e.getActionCommand()=="最后一张")
myCard.last(p1); //显示最后一张
}
}
// 类MyCanvas设计:在画布上画一个圆
class MyCanvas extends Canvas
{
int x,y; //椭圆的纵横半径
MyCanvas(int x,int y) //确定大小参数以及画布的大小
{
this.x=x;
this.y=y;
this.getSize();
}
public void paint(Graphics g) //重绘信息
{
g.setColor(Color.red); //设置颜色
g.drawString("我是第"+x,20,20); //绘制字符串信息
g.fillOval(50,50,4*x,4*y); //填充圆
}
public Dimension getPreferredSize()
{
return new Dimension(200,200);
}
}
该程序的运行结果如图10-7所示。
图10-7 卡片布局