《疯狂Java讲义(第4版)》-----第11章【AWT编程】(AWT容器、布局管理器)
AWT(Abstract Window Toolkit):Sun公司最早提供的GUI(Graphics User Interface)库。Swing在AWT基础上,完善了图形用户界面编程组件。所有和AWT编程相关的类都放在java.awt包及他的子包里。
AWT容器
窗口就是容器里面放了一些组件拼成的。AWT主要提供两种容器类型:Window和Panel。Window是可以独立存在的顶级窗口。Panel可作为容器容纳其他组件,但不能独立存在,必须添加到其他容器中。
Frame创建第一个窗口
下面程序用Frame创建了一个窗口,单击窗口的X关闭不了窗口,在命令行下可以用Ctrl+C强制退出程序,就关闭窗口了。后续可以给窗口写事件实现X关闭窗口。
//Frame是常用窗口,默认使用BorderLayout作为布局管理器
import java.awt.Frame;
public class Hello{
public static void main(String[] args) throws Exception{
Frame f = new Frame("第一个AWT创建的Frame窗口");
//设置窗口位置、大小
f.setBounds(50,50,900,670);
f.setVisible(true);//默认窗口是隐藏的,需要手动设置是可见的
}
}
Panel创建窗口
Panel容器的特点:
- 作为容器盛装其他组件
- 不可单独存在,必须放置到其他容器中
- 默认使用FlowLayout作为其布局管理器
import java.awt.Frame;
import java.awt.Panel;
import java.awt.Button;
import java.awt.TextField;
public class Hello{
public static void main(String[] args) throws Exception{
Frame f = new Frame("测试窗口");
Panel p = new Panel();
p.add(new TextField(10));
p.add(new Button("提交"));
f.add(p);//Panel必须放入其他容器
//设置窗口位置、大小
f.setBounds(50,50,300,90);
f.setVisible(true);//默认窗口是隐藏的,需要手动设置是可见的
}
}
ScrollPanel创建窗口
ScrollPanel是一个带滚动条的容器,不能独立存在,必须添加到其他容器中。盛装其他组件,当组件占用空间过大时,ScrollPanel自动产生滚动条,当然可以在定义的时候向构造器中传入参数默认使用滚动条。默认使用BorderLayout作为其布局管理器。
import java.awt.Frame;
import java.awt.ScrollPane;
import java.awt.Button;
import java.awt.TextField;
public class Hello{
public static void main(String[] args) throws Exception{
Frame f = new Frame("测试窗口");
ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);//传入总是带有滚动条的参数
sp.add(new TextField(10));
sp.add(new Button("提交"));
f.add(sp);//Panel必须放入其他容器
//设置窗口位置、大小
f.setBounds(50,50,300,90);
f.setVisible(true);//默认窗口是隐藏的,需要手动设置是可见的
}
}
发现文本框不见了!!据说这和布局管理器BorderLayout有关!!!往下看…
布局管理器(LayoutManager)
该节开始,该书作者举个非常好的例子,说一个存字符串“Hello Java”的标签,有一个最佳的大小刚好存放这个字符串,但是在Windows平台和Unix平台上标签刚好的大小是不一样的,布局管理器就是解决这个问题的!让Java写出的图形界面程序有良好的平台无关性!
所有的AWT容器都有默认的布局管理器,要为容器指定一个布局管理器的话,可以这么做:c.setLayout(new XxxLayout());
AWT提供了FlowLayout、BorderLayout、GridLayout、GridBagLayout、CardLayout5个常用的布局管理器。
FlowLayout布局管理器
默认情况下,FlowLayout布局管理器从左向右排列所有组件,遇到边界就折回从下一行重新开始。
import java.awt.Frame;
import java.awt.Button;
import java.awt.FlowLayout;
public class Hello{
public static void main(String[] args) throws Exception{
Frame f = new Frame("测试窗口");
f.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 5));
for(int i = 0; i < 10; i++){
f.add(new Button("按钮" + i));
}
//f.pack();//Window的一个方法,设置窗口的最佳尺寸
f.setVisible(true);//默认窗口是隐藏的,需要手动设置是可见的
}
}
BorderLayout布局管理器
BorderLayout把容器分成NORTH、SOUTH、WEST、EAST、CENTER五个部分。如果不指定添加组件的区域,默认添加到CENTER区域,当添加多个组件时,后添加的组件会覆盖掉先添加的组件。可以使用BorderLayout的静态常量(NORTH、SOUTH、WEST、EAST、CENTER等)指定添加的区域。如果五个区域中有区域没有放内容,该区域会被其他区域占据。
Frame、Dialog、ScrollPane默认使用BorderLayout布局管理器。
import java.awt.Frame;
import java.awt.Button;
import java.awt.BorderLayout;
import static java.awt.BorderLayout.*;
public class Hello{
public static void main(String[] args) throws Exception{
Frame f = new Frame("测试窗口");
f.setLayout(new BorderLayout(30, 5));
f.add(new Button("东"), EAST);
f.add(new Button("西"), WEST);
f.add(new Button("南"), SOUTH);
f.add(new Button("北"), NORTH);
f.add(new Button("中"), CENTER);
f.pack();//Window的一个方法,设置窗口的最佳尺寸
f.setVisible(true);//默认窗口是隐藏的,需要手动设置是可见的
}
}
GridLayout布局管理器
GridLayout布局管理器把容器分成表格,默认从左到右,从上到下把组件添加到表格中。
import java.awt.Frame;
import java.awt.Button;
import java.awt.BorderLayout;
import static java.awt.BorderLayout.*;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.GridLayout;
public class Hello{
public static void main(String[] args) throws Exception{
Frame f = new Frame("计算器");
f.setLayout(new BorderLayout(30, 5));
Panel p1 = new Panel();
p1.add(new TextField(30));
f.add(p1, NORTH);
Panel p2 = new Panel();
p2.setLayout(new GridLayout(3, 5, 5, 3));
String[] s = {"0", "1", "2", "3", "4", "5", "6", "7", "8",
"9", "+", "-", "*", "/", "."};
for(String str : s){
p2.add(new Button(str));
}
f.add(p2, CENTER);
f.pack();//Window的一个方法,设置窗口的最佳尺寸
f.setVisible(true);//默认窗口是隐藏的,需要手动设置是可见的
}
}
GridBagLayout布局管理器
是最复杂的布局管理器!!!
GridBagLayout可以设置一个组件跨越一个或多个网格,可以设置各网格的大小。使用GridBagLayout布局管理器的关键在于GridBagConstraints(它才是精确控制每个GUI组件的核心类)。
步骤:
(1)创建容器(窗口)与GridBagLayout布局管理器
(2)创建GridBagConstraints对象
(3)调用GridBagLayout的setConstraints方法,建立GridBagConstraints对象和受控制组件之间的关联
(4)添加组件到容器
关键是通过GridBagConstraints设置组件的大小、跨网格数等。设置的常见属性:gridwidth/gridheight(横向、纵向跨网格数,默认0)、fill(横向、纵向扩充与否)、anchor(组件在自己格子中的定位方式,如左上角、中间等)、weightx/weighty(扩大时的该组件的权重比例)。具体见官方文档及该书400~401页。下面是该书也是官方文档上的一个例子
import java.awt.Frame;
import java.awt.Button;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
public class Hello{
private Frame f = new Frame("测试窗口");
private GridBagLayout gb = new GridBagLayout();
private GridBagConstraints gbc = new GridBagConstraints();
private Button[] buttons = new Button[10];
public void init(){
f.setLayout(gb);
for(int i = 0; i < 10; i++){
buttons[i] = new Button("按钮" + i);
}
gbc.fill = GridBagConstraints.BOTH;//所有组件都可以纵横扩大
gbc.weightx = 1;
addButton(buttons[0]);
addButton(buttons[1]);
addButton(buttons[2]);
gbc.gridwidth = GridBagConstraints.REMAINDER;//设置为横向最后一个组件
addButton(buttons[3]);
gbc.weightx = 0;//虽设置横向不扩大,但受上一行的影响
addButton(buttons[4]);
gbc.gridwidth = 2;//跨越两个网格
addButton(buttons[5]);
gbc.gridwidth = 2;
gbc.gridwidth = GridBagConstraints.REMAINDER;
addButton(buttons[6]);
gbc.gridwidth = 1;
gbc.gridheight = 2;
gbc.weighty = 1;
addButton(buttons[7]);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridheight = 1;
addButton(buttons[8]);
addButton(buttons[9]);
f.pack();
f.setVisible(true);
}
private void addButton(Button button){
gb.setConstraints(button, gbc);
f.add(button);
}
public static void main(String[] args) throws Exception{
new Hello().init();
}
}
CardLayout布局管理器
A CardLayout object is a layout manager for a container. It treats each component in the container as a card. Only one card is visible at a time, and the container acts as a stack of cards. The first component added to a CardLayout object is the visible component when the container is first displayed.
书上说的常用的五个方法如下(官方文档截图):
该书上的示例代码:
import java.awt.Frame;
import java.awt.Panel;
import java.awt.CardLayout;
import java.awt.Button;
import java.awt.event.ActionListener;
import java.awt.BorderLayout;
public class Hello{
Frame f = new Frame("测试窗口");
String[] names = {"第一张", "第二张", "第三张", "第四张", "第五张"};
Panel p1 = new Panel();
public void init(){
final CardLayout c = new CardLayout();
p1.setLayout(c);
for(int i = 0; i < names.length; i++){
p1.add(names[i], new Button(names[i]));//注意两个参数,组件名字+组件
//没有名字的话,找不到具体哪一张,c.show方法失效
}
Panel p2 = new Panel();
ActionListener listener = e->{
switch(e.getActionCommand()){
case "上一张":
c.previous(p1);
break;
case "下一张":
c.next(p1);
break;
case "第一张":
c.first(p1);
break;
case "最后一张":
c.last(p1);
break;
case "第三张":
c.show(p1, "第三张");
break;
}
};
Button previous = new Button("上一张");
previous.addActionListener(listener);
Button next = new Button("下一张");
next.addActionListener(listener);
Button first = new Button("第一张");
first.addActionListener(listener);
Button last = new Button("最后一张");
last.addActionListener(listener);
Button third = new Button("第三张");
third.addActionListener(listener);
p2.add(previous);
p2.add(next);
p2.add(first);
p2.add(last);
p2.add(third);
f.add(p1);
f.add(p2, BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) throws Exception{
new Hello().init();
}
}
绝对定位
setLayout(null),然后设置大小位置。使得Java的GUI界面失去跨平台特性。
import java.awt.Frame;
import java.awt.Button;
public class Hello{
Frame f = new Frame("测试窗口");
Button b1 = new Button("按钮A");
Button b2 = new Button("按钮B");
public void init(){
f.setLayout(null);
b1.setBounds(30, 40, 100, 30);
b2.setBounds(35, 60, 100, 30);
f.add(b1);
f.add(b2);
f.setBounds(100, 200, 260, 120);
f.setVisible(true);
}
public static void main(String[] args) throws Exception{
new Hello().init();
}
}
BoxLayout布局管理器
GridBagLayout布局管理器的功能强大,但太复杂了!Swing引入BoxLayout,保留了GridBagLayout的许多优点,但简单了很多。
axis可以传入这两个参数:
【示例代码1】
import java.awt.Frame;
import java.awt.Button;
import javax.swing.BoxLayout;
public class Hello{
Frame f = new Frame("测试窗口");
public void init(){
f.setLayout(new BoxLayout(f, BoxLayout.Y_AXIS));
f.add(new Button("按钮A"));
f.add(new Button("按钮B"));
f.pack();
f.setVisible(true);
}
public static void main(String[] args) throws Exception{
new Hello().init();
}
}
【示例代码2】
BoxLayout常常与Box容器结合起来使用。Box容器提供了一些静态方法如下:
上面这些方法中,有两个返回的是Box容器对象,其他几个返回的是Component对象,就是间距,在示例代码3中会演示。
import java.awt.Frame;
import java.awt.Button;
import java.awt.BorderLayout;
import javax.swing.BoxLayout;
import javax.swing.Box;
public class Hello{
private Frame f = new Frame("测试窗口");
private Box horizontal = Box.createHorizontalBox();
private Box vertical = Box.createVerticalBox();
public void init(){
horizontal.add(new Button("水平按钮A"));
horizontal.add(new Button("水平按钮B"));
vertical.add(new Button("垂直按钮A"));
vertical.add(new Button("垂直按钮B"));
f.add(horizontal, BorderLayout.NORTH);
f.add(vertical);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) throws Exception{
new Hello().init();
}
}
【示例代码3】
就是用Box容器提供的一些方法,设置不同组件之间的间距。
import java.awt.Frame;
import java.awt.Button;
import java.awt.BorderLayout;
import javax.swing.BoxLayout;
import javax.swing.Box;
public class Hello{
private Frame f = new Frame("测试窗口");
private Box horizontal = Box.createHorizontalBox();
private Box vertical = Box.createVerticalBox();
public void init(){
horizontal.add(new Button("水平按钮A"));
horizontal.add(Box.createHorizontalGlue());
horizontal.add(new Button("水平按钮B"));
horizontal.add(Box.createHorizontalStrut(20));
horizontal.add(new Button("水平按钮C"));
vertical.add(new Button("垂直按钮A"));
vertical.add(Box.createVerticalGlue());
vertical.add(new Button("垂直按钮B"));
vertical.add(Box.createVerticalStrut(30));
vertical.add(new Button("垂直按钮C"));
f.add(horizontal, BorderLayout.NORTH);
f.add(vertical);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) throws Exception{
new Hello().init();
}
}