图形界面之布局设计

    |     2015年6月4日   |   图形界面(GUI)   |     0 条评论   |    1384

界面设计里,一个容器要放许多组件。为了美观,给组件安排在容器中的位置,就是布局设计。java.awt 定义了多种布局类,每种对应一种策略。

常用布局:FlowLayout 依次放置;BorderLayout 放在边界上;CardLayout 像扑克牌叠放,每次只显示一张;GridLayout 按行列划成相等格子;GridBagLayout 划成许多小矩形单元,一个组件可占一格或多格。GridBagLayout 能精细控制也最复杂,本教程暂不讨论。

每个容器都有布局管理器,决定如何安排组件。布局管理器是实现 LayoutManager 接口的类。

一、FlowLayout(JApplet、JPanel、JScrollPane 默认)

按加入顺序从左到右排,一行满了换下一行,每行组件居中。最简便,适合组件不多的情况;组件多时会高低不平、各行长短不一。

构造方法:

  • FlowLayout():默认居中,间隙 5 像素
  • FlowLayout(int alignment):对齐方式为 LEFT / CENTER / RIGHT(原文 aligment 为拼写笔误)
  • FlowLayout(int alignment, int horz, int vert):同时设定水平间距 horz 和垂直间距 vert

用超类 Container 的 setLayout() 设定布局,例如 setLayout(new FlowLayout())。加入组件用 add(组件名)。

二、BorderLayout(JWindow、JFrame、JDialog 默认)

把容器分成东 East、西 West、南 South、北 North、中 Center 五个区域。加入时要指明区域,一个位置一个组件。某位置要放多个组件时,先放进另一个容器,再把该容器加到这个位置。

构造:BorderLayout() 默认无间隙;BorderLayout(int horz, int vert) 设定水平、垂直间距。设定方法 setLayout(new BorderLayout())。加入用 add(组件名, 位置),不指定位置则默认为“中”。

【例 11-5】五个标签分别放在窗口东、西、南、北、中:

import javax.swing.*;
import java.awt.*;
public class J505 {
    public static void main(String[] args) {
        JLabel label1, label2, label3, label4, label5;
        JFrame mw = new JFrame("我是一个窗口"); // 创建一个窗口容器对象
        mw.setSize(250, 200);
        Container con = mw.getContentPane();
        con.setLayout(new BorderLayout());
        label1 = new JLabel("东标签"); // 默认左对齐
        label2 = new JLabel("南标签", JLabel.CENTER);
        label3 = new JLabel("西标签");
        label4 = new JLabel("北标签", JLabel.CENTER);
        label5 = new JLabel("中标签", JLabel.CENTER);
        con.add(label1, "East");
        con.add(label2, "South");
        con.add(label3, "West");
        con.add(label4, "North");
        con.add(label5, "Center");
        mw.setVisible(true);
    }
}

三、GridLayout

把容器划成若干行、列网格,行数和列数由程序控制,组件放在格子里,定位比较精确。每个网格形状大小相同,要求组件也保持相同大小。

  • GridLayout():单列,默认无间隙
  • GridLayout(int row, int col):指定行、列
  • GridLayout(int row, int col, int horz, int vert):再加水平、垂直间距

以行为基准:组件超额时自动增加列,太少则减少列,行数不变,按行优先排列。每个网格必须填组件,空白处可用空标签 add(new Label()) 顶替。

【例 11-6】若干按钮和标签放入 JPanel,再放入 JScrollPane,最后放入窗口。滚动面板可视范围小于面板实际大小,可拖滑块看原先不可见区域:

import java.applet.*;
import javax.swing.*;
import java.awt.*;
class MyWindow extends JFrame {
    public MyWindow(int w, int h) {
        setTitle("滚动面板实例");
        Container con = getContentPane();
        con.setPreferredSize(new Dimension(w, h));
        con.setLayout(new BorderLayout());
        JPanel p = new JPanel();
        p.setLayout(new GridLayout(6, 6));
        for (int i = 0; i < 6; i++) {
            p.add(new JLabel());
            for (int j = 1; j <= 2; j++) {
                p.add(new JButton("按钮" + (2 * i + j)));
                p.add(new JLabel("标签" + (2 * i + j)));
            }
            p.add(new JLabel());
        }
        p.setBackground(Color.blue);
        p.setPreferredSize(new Dimension(w + 60, h + 60));
        JScrollPane scrollPane = new JScrollPane(p);
        scrollPane.setPreferredSize(new Dimension(w - 60, h - 60));
        add(scrollPane, BorderLayout.CENTER); // 添加滚动面板
        setVisible(true);
        pack();
    }
}
class ScrollPane extends JScrollPane {
    public ScrollPane(Component p) {
        super(p);
        setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    }
}
public class J506 extends Applet {
    MyWindow myWindow;
    public void init() {
        myWindow = new MyWindow(400, 350);
    }
}

GridLayout 要求组件大小一致,界面可能不好看。补救:小组件先合并进一个容器,再把该容器当作组件放入 GridLayout,即容器嵌套。例如容器 A 用 GridLayout;B、C 各放若干组件后再加入 A。B、C 也可以是 GridLayout 或其他布局,外观上各组件大小就有了差异。

四、CardLayout

容器可容纳多个组件,但它们共用同一显示空间,某一时刻只显示一个,像一叠扑克每次只露最上面一张,该组件占满容器。步骤:先创建 CardLayout 对象,再用 setLayout() 设置,最后 add()。加入方式是 add(组件代号, 组件),代号是另给的字符串,与组件名无关。

CardLayout myCard = new CardLayout(); // 创建 CardLayout 布局对象
JPanel p = new JPanel();               // 创建 Panel 对象
p.setLayout(myCard);

显示某一组件有两种方式:

  • show(容器名, 组件代号),例如 myCard.show(p, k)
  • 按加入顺序:first / last / next / previous,例如 myCard.first(p)

【例 11-7】面板 p 用 CardLayout 放 10 个标签;窗口 4 个按钮分别显示第一个、最后一个、前一个、后一个:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyPanel extends JPanel {
    int x;
    JLabel label1;
    MyPanel(int a) {
        x = a;
        getSize();
        label1 = new JLabel("我是第" + x + "个标签");
        add(label1);
    }
    public Dimension getPreferredSize() {
        return new Dimension(200, 50);
    }
}
public class J507 extends Applet implements ActionListener {
    CardLayout mycard;
    MyPanel myPanel[];
    JPanel p;
    private void addButton(JPanel pan, String butName, ActionListener listener) {
        JButton aButton = new JButton(butName);
        aButton.addActionListener(listener);
        pan.add(aButton);
    }
    public void init() {
        setLayout(new BorderLayout()); // 小程序的布局是边界布局
        mycard = new CardLayout();
        this.setSize(400, 150);
        p = new JPanel();
        p.setLayout(mycard); // p 的布局设置为卡片式布局
        myPanel = new MyPanel[10];
        for (int i = 0; i < 10; i++) {
            myPanel[i] = new MyPanel(i + 1);
            p.add("A" + i, myPanel[i]);
        }
        JPanel p2 = new JPanel();
        addButton(p2, "第一个", this);
        addButton(p2, "最后一个", this);
        addButton(p2, "前一个", this);
        addButton(p2, "后一个", this);
        add(p, "Center");
        add(p2, "South");
    }
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("第一个")) mycard.first(p);
        else if (e.getActionCommand().equals("最后一个")) mycard.last(p);
        else if (e.getActionCommand().equals("前一个")) mycard.previous(p);
        else if (e.getActionCommand().equals("后一个")) mycard.next(p);
    }
}

五、null 布局与 setBounds

空布局就是把容器布局设为 null。用 setBounds(int x, int y, int width, int height) 设置组件大小和位置:组件区域是矩形,x、y 是左上角坐标,width、height 是宽和高。步骤:先 add() 添加组件,再 setBounds()。相关方法:

getSize().width
getSize().height
setVgap(int vgap)
setHgap(int hgap);
布局 默认用在 特点
FlowLayout JApplet / JPanel / JScrollPane 从左到右流式,一行满换行
BorderLayout JWindow / JFrame / JDialog 东南西北中五区,一区一组件
GridLayout 需整齐网格时 行列等大格子,行数固定列可增减
CardLayout 向导、选项卡式切换 同一空间一次只显示一个组件
null + setBounds 绝对定位 自己算坐标,窗口缩放不会自动重排

一句话总结:容器靠布局管理器摆组件:流式、边界、网格、卡片各管一类场景;精细到像素再用 null 加 setBounds,嵌套容器可以混用多种策略。

转载请注明来源:图形界面之布局设计
本文链接地址:https://ai.zhousir.top/?p=764
回复 取消