JavaGUI(一)——布局

AWT编程

AWT简介

当JDK1.0发布时,Sun公司提供了一套基本的GUI类库,这个GUI类库希望可以在所有平台下都能运行,这套基本类库被称为“抽象窗口工具集(Abstract Window Toolkit)”,它为Java应用程序提供了基本的图形组件。AWT是窗口框架,它从不同平台的窗口系统中抽取出共同组件,当程序运行时,将这些组件的创建和动作委托给程序所在的平台。简而言之,当AWT编写图形界面应用时,程序仅指定了界面组件的位置和行为,并未提供真正的实现,JVM调用操作系统本地图形界面来创建和平台一致的对等体。
使用AWT创建的图形界面应用和所在的运行平台有相同的界面风格,比如在Windows操作系统上,它表现出Windows风格;在UNIX操作系统上,它就表现出UNIX风格,Sun希望采用这种方式来实现“Write Once,Run Anywhere”的目标。


AWT继承体系

所有和AWT编程相关的类都放在java.awt包以及它的子包中,AWT编程中有两个基类:Component和MenuComponent。

  • Component:代表一个能以图形化方式显示出来,并可与用户交互对象,例如Button代表一个按钮,TextField代表一个文本框等;
  • MenuComponent:则代表图形界面的菜单组件,包括MenuBar(菜单条)。MenuItem(菜单项)等子类。

其中Container是一种特殊的Component,它代表一种容器,可以盛装普通的Component。
AWT中还有一个非常重要的接口叫LayoutManager,如果一个容器中有多个组件,那么容器就需要使用LayoutManager来管理这些组件的布局方式。


Comtainer继承体系

image

  • Window是可以独立存在的顶级窗口,默认使用BorderLayout管理其内部组件布局;
  • Panel可以容纳其他组件,但不能独立存在,它必须内嵌其他容器中使用,默认使用FlowLayout管理其内部组件布局;
  • ScrollPane是一个带滚动条的容器,它也不能独立存在,默认使用BorderLayout管理其内部组件布局;

常见API

Component作为基类,提供了如下常用的方法来设置组件的大小、位置、可见性等。

方法签名 方法功能
setLocation(int x,int y) 设置组件的位置
setSize(int width,int height) 设置组件的大小。
setBounds(int x, int y , int width, int height) 同时设置组件的位置、大小
setVisible(Boolean b) 设置该组件的可见性

Container作为容器根类,提供了如下方法来访问容器中的组件

方法签名 方法功能
Component add(Component comp); 向容器中添加其他组件(该组件既可以是普通组件,也可以是容器),并返回被添加的组件。
Component getComponentAt(int x,int y); 返回指定点的组件。
int getComponentCount(); 返回该容器内组件的数量。
Component[] getComponents(); 返回该容器内的所有组件。

LayoutMannager布局管理器

之前,我们学习了Component中有一个方法setBounds()可以设置当前容器的位置和大小,但是我们需要明确一件事,如果我们手动地位组件设置位置和大小的话,就会造成程序的不通用性,例如:

Label label = new Label("HelloWorld!");

创建了一个label组件,很多情况下,我们需要让label组件的宽高和“HelloWorld!”这个字符串自身的宽高一致,这种大小称为最佳大小。由于操作系统存在差异,例如在windows上,我们要达到这样的效果,需要把该Label组件的宽和高设置为100px,20px,但是在Linux操作系统上,可能需要把Label组件的宽和高分别设置为120px,24px,才能达到同样的效果。

如果要让我们的程序在不同的操作系统下,都有相同的使用体验,那么手动设置组件的位置和大小,无疑是一种灾难,因为有太多的组件,需要分别设置不同操作系统下的大小和位置。为了解决这个问题,java提供了LayoutManager布局管理器,可以根据运行平台来自动调整组件大小,程序员不同再手动设置组件的大小和位置了,只需要为容器选择合适的布局管理器即可。


FlowLayout

在FlowLayout布局管理器中,组件像水流一样向某方向流动(排列),遇到障碍(边界)就折回,重头开始排列。在默认情况下,FlowLayout布局管理器从左向右排列所有组件,遇到边界就会折回下一行重新开始。

构造方法 方法功能
FlowLayout() 使用默认的对齐方式及默认的垂直间距、水平间距创建FlowLayout布局管理器。
FlowLayout(int align) 使用指定的对齐方式及默认的垂直间距、水平间距创建FlowLayout布局管理器。
FlowLayout(int align,int hgap,int vgap) 使用指定的对齐方式及指定的垂直间距、水平间距创建FLowLayout布局管理器。

FlowLayout中组件的排列方向从左向右、从右向左、从中间向两边等),该参数应该使用FlowLayout类的静态常量:FlowLayout.LEFT、FlowLayout.CENTER、FlowLayout.RIGHT,默认是左对齐。

FlowLayout中组件中间通过整数设置,单位是像素,默认是5个像素。


BorderLayout

BorderLayout将容器分为EAST、SOUTH、WEST、NORTH、CENTER五个区域,普通组件可以被放置在这5个区域的任意一个中。

当改变使用BorderLayout的容器大小时,NORTH、SOUTH和CENTER区域水平调整,而EAST、WEST和CENTER区域垂直调整。使用BorderLayout有如下两个注意点:

  1. 当向使用BorderLayout布局管理器的容器中添加组件时,需要指定要添加到哪个区域中。如果没有指定添加到哪个区域中,则默认添加到中间区域中;
  2. 如果向同一个区域中添加多个组件时,后放入的组件会覆盖先放入的组件;
构造方法 方法功能
BorderLayout() 使用默认的水平间距、垂直间距创建BorderLayout布局管理器。
BorderLayout(int hgap,int vgap) 使用指定的水平间距、垂直间距创建BorderLayout布局管理器。

示例代码:

public class Demo04 {
    public static void main(String[] args){
        Frame frame = new Frame();

        frame.setLayout(new BorderLayout(20,20));
        frame.add(new Button("Top"),BorderLayout.NORTH);
        frame.add(new Button("Left"),BorderLayout.WEST);
        frame.add(new Button("Right"),BorderLayout.EAST);
        frame.add(new Button("Bottom"),BorderLayout.SOUTH);
        frame.add(new Button("Center"),BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}

GridLayout

GridLayout布局管理器将容器分隔成纵横线分隔的网格,每个网格所占的区域大小相同。当向使用GridLayout布局管理器的容器中添加组件时,默认从左向右、从上向下一次添加到每个网格中。与FlowLayout不同的是,放置在GridLayout布局管理器中的各组件的大小由组件所处的区域决定(每个组件将自动占满整个区域)。

构造方法 方法功能
GridLayout(int rows,int cols) 采用指定的行数、列数,以及默认的横向间距、纵向间距将容器分割成多个网格
GridLayout(int rows,int cols,int hgap,int vgap) 采用指定的横向间距、纵向间距将容器分隔成多个网格。

示例代码:

public class Demo05 {
    public static void main(String[] args){
        Frame frame = new Frame("计算器");

        Panel p = new Panel();
        p.add(new TextField(30));
        frame.add(p,BorderLayout.NORTH);
        Panel p2 = new Panel();
        p2.setLayout(new GridLayout(3,5,0,0));
        for(int i = 0; i<10;i++){
            p2.add(new Button(String.valueOf(i)));
        }
        p2.add(new Button("+"));
        p2.add(new Button("-"));
        p2.add(new Button("*"));
        p2.add(new Button("/"));
        p2.add(new Button("."));
        frame.add(p2);

        frame.pack();
        frame.setVisible(true);
    }
}

GridBagLayout

GridBagLayout 布局管理器的功能最强大,但也最复杂,与GridLayout布局管理器不同的是,在GridBagLayout布局管理器中,一个组件可以跨越一个或多个网格,并可以设置各网格的大小互不相同,从而增加了布局的灵活性。当窗口的大小发生变化时,GridBagLayout布局管理器也可以准确地控制窗口各部分的拉伸。

由于在GridBagLayout布局中,每个组件可以占用多个网格,此时,我们往容器中添加组件的时候,就需要具体地控制每个组件占用多少个网格,java提供的GridBagConstaints类,与特定的组件绑定,可以完成具体大小和跨越性的设置。

该布局虽然功能强大,但实现起来及其复杂,在Swing中有更好的类进行替代

CardLayout

CardLayout布局管理器以事件而非空间来管理它里面的组件,它将加入容器的所有组件看成一叠卡片(每个卡片其实就是一个组件),每次只有最上面的那个Component才可见。就好像一副扑克牌,它们叠在一起,每次只有最上面的一张扑克牌才可见。

方法名称 方法功能
CardLayout 创建默认的CardLayout布局管理器。
CardLayout(int hgp,int vgap) 通过指定卡片与容器左右边界的间距(hgap)、上下边界(vgap)的间距来创建CardLayout布局管理器
first(Container target) 显示target容器中的第一张卡片
last(Container target) 显示target容器中的最后一张卡片
previous(Container target) 显示target容器中的前一张卡片
show(Container target,String name) 显示target容器中指定名字的卡片

BoxLayout

为了简化开发,Swing引入了一个新的布局管理器:BoxLayout。BoxLayout可以在垂直和水平两个方向上摆放GUI组件,BoxLayout提供了如下一个简单的构造器:

方法名称 方法功能
BoxLayout(Container target ,int axis) 指定创建基于target容器的BoxLayout布局管理器,该布局管理器里的组件按axis方法排列。其中axis有BoxLayout.X_AXIS(横向)和BoxLayout.Y_AXIS(纵向)两个方向。

示例代码:

public class Demo06 {
    public static void main(String[] args) {
        Frame frame = new Frame();
        BoxLayout boxLayout = new BoxLayout(frame,BoxLayout.Y_AXIS);

        frame.add(new Button("one"));
        frame.add(new Button("tow"));
        frame.add(new Button("three"));

        frame.setLayout(boxLayout);

        frame.pack();
        frame.setVisible(true);
    }
}

在java.swing包中,提供了一个新的容器Box,该容器的默认布局管理器就是BoxLayout,大多数情况下,使用Box容器去容纳多个GUI组件,然后再把Box容器作为一个组件,添加到其他的容器中,从而形成整体窗口布局。

方法名称 方法功能
static Box createHorizontalBox() 创建一个水平排列组件的Box容器。
static BoxcreateVerticalBox() 创建一个垂直排列组件的Box容器。

示例代码:

public class Demo01 {
    public static void main(String[] args){
        Frame frame = new Frame();

        Box hBox =  Box.createHorizontalBox();
        Box vBox = Box.createVerticalBox();

        hBox.add(new Button("h btn"));
        hBox.add(new Button("h btn"));

        vBox.add(new Button("v btn"));
        vBox.add(new Button("v btn"));

        frame.add(hBox,BorderLayout.NORTH);
        frame.add(vBox);

        frame.pack();
        frame.setVisible(true);
    }
}

通过之前的两个BoxLayout演示,我们会发现,被它管理的容器中的组件之间是没有间隔的,不是特别美观,但之前学习的几种布局,组件之间都会有一些间距,那使用BoxLayout如何给组件设置间距呢?

其实很简单,我们只需要在原有的组件需要间隔的地方,添加间隔即可,而每个间隔可以是一个组件,只不过该组件没有内容,仅仅起到一种分隔的作用。

Box类中,提供了五个方便的静态方法来生成这些间隔组件:

方法名称 功能方法
static Component createHorizontalGlue() 创建一条水平Glue(可以在两个方向上同时拉伸个间距)
static Component createVerticalGlue() 创建一条垂直Glue(可在两个方向上同时拉伸间距)
static Component createHorizontalStrut(int width) 创建一条指定宽度(宽度固定了,不能拉伸)的水平Strut(可在垂直方向上拉伸的间距)
static Component createVerticalStrut(int height) 创建一条指定高度(高度固定了,不能拉伸)的垂直Struct(可在水平方向上拉伸的间距)
posted @ 2022-09-07 22:29  maplerain  阅读(408)  评论(0编辑  收藏  举报