《JAVA:从入门到精通》part 15

十八、Swing程序设计(二)

1. 常用布局管理器

  • 在Swing中,每个组件在容器中都有一个具体的位置和大小,而在容器中摆放各种组件时很难判断其具体位置和大小。布局管理器提供了Swing组件安排、展示在容器中的方法以及基本的布局功能。使用布局管理器较程序员直接在容器中控制Swing组件的位置和大小方便得多,可以有效地处理整个窗体的布局。Swing提供的常用布局管理器包括流布局管理器、边界布局管理器以及网格布局管理器。

绝对布局

  • 在Swing中,除了使用布局管理器之外还可以使用绝对布局。绝对布局,就是硬性指定组件在容器中的位置和大小,可以使用绝对坐标的方式来指定组件的位置。使用绝对布局的步骤如下:
  • 使用Container.setLayout(null)方法取消布局管理器
  • 使用Component.setBounds()方法设置每个组件的大小和位置。
import java.awt.*;

import javax.swing.*;

public class AbsolutePosition extends JFrame {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public AbsolutePosition() {
        setTitle("本窗体使用绝对布局"); // 设置该窗体的标题
        setLayout(null); // 使该窗体取消布局管理器设置
        setBounds(0, 0, 200, 150); // 绝对定位窗体的位置与大小
        Container c = getContentPane(); // 创建容器对象
        JButton b1 = new JButton("按钮1"); // 创建按钮
        JButton b2 = new JButton("按钮2"); // 创建按钮
        b1.setBounds(10, 30, 80, 30); // 设置按钮的位置与大小
        b2.setBounds(60, 70, 100, 20);
        c.add(b1); // 将按钮添加到容器中
        c.add(b2);
        setVisible(true); // 使窗体可见
        // 设置窗体关闭方式
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new AbsolutePosition();
    }
}

运行结果:

  • 需要注意的是,在使用绝对布局之前需要调用setLayout(null)方法告知编译器,这里不再使用布局管理器。

流布局管理器

  • 流布局管理器是最基本的布局管理器,在整个容器中的布局正如其名,像“流”一样从左到右摆放组件,直到占据了这一行的所有空间,然后再向下移动一行。默认情况下,组件在每一行都是居中排列的,但是通过设置也可以更改组件在每一行上的排列位置。
  • FlowLayout类中具有以下常用的构造方法:
public FlowLayout()
public FlowLayout(int alignment)
public FlowLayout(int alignment,int horizGap,int vertGap)
  • 构造方法中alignment参数表示使用流布局管理器后组件在每一行的具体摆放位置。它可以被赋予以下3个值之一:
FlowLayout.LEFT=0;
FlowLayout.CENTER=1;
FlowLayout.RIGHT=2;
  • 上述3个值分别代表容器使用流布局管理器后组件在每一行中的摆放位置。例如将alignment设置为0时,每一行的组件将被指定按照左对齐排列;而将alignment设置为2时,每一行的组件将被指定为按照右对齐排列。
import java.awt.*;

import javax.swing.*;

public class FlowLayoutPosition extends JFrame {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public FlowLayoutPosition() {
        setTitle("本窗体使用流布局管理器"); // 设置窗体标题
        Container c = getContentPane();
        // 设置窗体使用流布局管理器,使组件右对齐,并且设置组件之间的水平间隔与垂直间隔
        setLayout(new FlowLayout(2, 10, 10));
        for (int i = 0; i < 10; i++) { // 在容器中循环添加10个按钮
            c.add(new JButton("button" + i));
        }
        setSize(300, 200); // 设置窗体大小
        setVisible(true); // 设置窗体可见
        // 设置窗体关闭方式
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }

    public static void main(String[] args) {
        new FlowLayoutPosition();
    }
}

运行结果:

  • 可以看到alignment的值设置为2,故组件右对齐排列,若将alignment的值改为1,则组件会居中对齐。

运行结果:

边界布局管理器

  • 在默认不指定窗体布局的情况下,Swing组件的布局模式是边界布局管理器。边界布局管理器将容器划分为东、南、西、北、中5个区域,可以将组件加入到这五个区域中。容器调用Container类的add()方法添加组件时可以设置此组件在边界布局管理器中的区域,区域的控制可以由BorderLayout类中的成员变量来决定,这些成员变量的具体含义如下表:
成员变量 含义
BorderLayout.NORTH 在容器中添加组件时,组件置于顶端
BorderLayout.SOUTH 在容器中添加组件时,组件置于底端
BorderLayout.EAST 在容器中添加组件时,组件置于右端
BorderLayout.WEST 在容器中添加组件时,组件置于左端
BorderLayout.CENTER 在容器中添加组件时,组件置于中间开始填充,直到与其他组件边界连接
import java.awt.*;

import javax.swing.*;

public class BorderLayoutPosition extends JFrame {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    // 定义组件摆放位置的数组
    String[] border = { BorderLayout.CENTER, BorderLayout.NORTH,
            BorderLayout.SOUTH, BorderLayout.WEST, BorderLayout.EAST };
    String[] buttonName = { "center button", "north button",
            "south button", "west button", "east button" };

    public BorderLayoutPosition() {
        setTitle("这个窗体使用边界布局管理器");
        Container c = getContentPane(); // 定义一个容器
        setLayout(new BorderLayout()); // 设置容器为边界布局管理器
        for (int i = 0; i < border.length; i++) {
            // 在容器中添加按钮,并设置按钮布局
            c.add(border[i], new JButton(buttonName[i]));
        }
        setSize(350, 200); // 设置窗体大小
        setVisible(true); // 使窗体可视
        // 设置窗体关闭方式
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }

    public static void main(String[] args) {
        new BorderLayoutPosition();
    }
}

运行结果:

网格布局管理器

  • 网格布局管理器将容器划分为网格,所以组件可以按行和按列进行排列。在网格布局管理器中,每一个组件的大小都相同,并且网格中空格的个数由网格的行数和列数决定,如一个两行两列的网格能产生4个大小相同的网格。组件从网格的左上角开始,按照从左到右,从上到下的顺序加入到网格中,而且每一个组件会填满整个网格,改变窗体的大小,组件的大小也会随之改变。
  • 网格布局管理器主要有以下两个常用的构造方法:
public GridLayout(int rows,int columns);
public GridLayout(int rows,int columns,int horizGap,int vertGap);
  • 在上述构造方法中,rows和columns参数代表网格的行数与列数,这两个参数只有一个参数可以为0,代表一行或一列可以排列任意多个组件;参数horizGap与vertGap指定网格之间的距离,其中horizGap参数指定网格之间的水平距离,vertGap参数指定网格之间的垂直距离。
package com.lzw;

import java.awt.*;

import javax.swing.*;

public class GridLayoutPosition extends JFrame {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public GridLayoutPosition() {
        Container c = getContentPane();
        // 设置容器使用网格布局管理器,设置7行3列的网格
        setLayout(new GridLayout(7, 3, 5, 5));
        for (int i = 0; i < 20; i++) {
            c.add(new JButton("button" + i)); // 循环添加按钮
        }
        setSize(300, 300);
        setTitle("这是一个使用网格布局管理器的窗体");
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new GridLayoutPosition();
    }
}

运行结果:

  • 可以看到组价在窗体中呈现出一个7行3列的网格,并且添加到该布局中的组件被放置在网格中。

网格组布局管理器综合案例:

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JButton;
import javax.swing.JFrame;

public class ExampleFrame_03 extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public static void main(String args[]) {
        ExampleFrame_03 frame = new ExampleFrame_03();
        frame.setVisible(true);
    }

    public ExampleFrame_03() {
        super();
        setTitle("使用网格组布局管理器");
        getContentPane().setLayout(new GridBagLayout());
        setBounds(100, 100, 500, 170);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JButton button = new JButton("A");
        final GridBagConstraints gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridy = 0;// 起始点为第1行
        gridBagConstraints.gridx = 0;// 起始点为第1列
        gridBagConstraints.weightx = 10;// 第一列的分布方式为10%
        gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
        getContentPane().add(button, gridBagConstraints);

        final JButton button_1 = new JButton("B");
        final GridBagConstraints gridBagConstraints_1 = new GridBagConstraints();
        gridBagConstraints_1.gridy = 0;
        gridBagConstraints_1.gridx = 1;
        // 设置组件左侧的最小距离
        gridBagConstraints_1.insets = new Insets(0, 5, 0, 0);
        gridBagConstraints_1.weightx = 20;// 第一列的分布方式为20%
        gridBagConstraints_1.fill = GridBagConstraints.HORIZONTAL;
        getContentPane().add(button_1, gridBagConstraints_1);

        final JButton button_2 = new JButton("C");
        final GridBagConstraints gridBagConstraints_2 = new GridBagConstraints();
        gridBagConstraints_2.gridy = 0;// 起始点为第1行
        gridBagConstraints_2.gridx = 2;// 起始点为第3列
        gridBagConstraints_2.gridheight = 2;// 组件占用两行
        gridBagConstraints_2.insets = new Insets(0, 5, 0, 0);
        gridBagConstraints_2.weightx = 30;// 第一列的分布方式为30%
        // 同时调整组件的宽度和高度
        gridBagConstraints_2.fill = GridBagConstraints.BOTH;
        getContentPane().add(button_2, gridBagConstraints_2);

        final JButton button_3 = new JButton("D");
        final GridBagConstraints gridBagConstraints_3 = new GridBagConstraints();
        gridBagConstraints_3.gridy = 0;
        gridBagConstraints_3.gridx = 3;
        gridBagConstraints_3.gridheight = 4;
        // 设置组件左侧和右侧的最小距离
        gridBagConstraints_3.insets = new Insets(0, 5, 0, 5);
        gridBagConstraints_3.weightx = 40;// 第一列的分布方式为40%
        gridBagConstraints_3.fill = GridBagConstraints.BOTH;
        getContentPane().add(button_3, gridBagConstraints_3);

        final JButton button_4 = new JButton("E");
        final GridBagConstraints gridBagConstraints_4 = new GridBagConstraints();
        gridBagConstraints_4.gridy = 1;
        gridBagConstraints_4.gridx = 0;
        gridBagConstraints_4.gridwidth = 2;// 组件占用两列
        // 设置组件上方的最小距离
        gridBagConstraints_4.insets = new Insets(5, 0, 0, 0);
        // 只调整组件的宽度
        gridBagConstraints_4.fill = GridBagConstraints.HORIZONTAL;
        getContentPane().add(button_4, gridBagConstraints_4);

        final JButton button_5 = new JButton("F");
        final GridBagConstraints gridBagConstraints_5 = new GridBagConstraints();
        gridBagConstraints_5.gridy = 2;// 起始点为第3行
        gridBagConstraints_5.gridx = 0;// 起始点为第1列
        gridBagConstraints_5.insets = new Insets(5, 0, 0, 0);
        gridBagConstraints_5.fill = GridBagConstraints.HORIZONTAL;
        getContentPane().add(button_5, gridBagConstraints_5);

        final JButton button_6 = new JButton("G");
        final GridBagConstraints gridBagConstraints_6 = new GridBagConstraints();
        gridBagConstraints_6.gridy = 2;
        gridBagConstraints_6.gridx = 1;
        gridBagConstraints_6.gridwidth = 2;// 组件占用两列
        gridBagConstraints_6.gridheight = 2;// 组件占用两行
        gridBagConstraints_6.insets = new Insets(5, 5, 0, 0);
        gridBagConstraints_6.fill = GridBagConstraints.BOTH;// 只调整组件的高度
//      gridBagConstraints_6.fill = GridBagConstraints.VERTICAL;// 只调整组件的高度
//      gridBagConstraints_6.ipadx = 30;// 增加组件的首选宽度
//      gridBagConstraints_6.anchor = GridBagConstraints.EAST;// 显示在东方
        getContentPane().add(button_6, gridBagConstraints_6);

        final JButton button_7 = new JButton("H");
        final GridBagConstraints gridBagConstraints_7 = new GridBagConstraints();
        gridBagConstraints_7.gridy = 3;
        gridBagConstraints_7.gridx = 0;
        gridBagConstraints_7.insets = new Insets(5, 0, 0, 0);
        gridBagConstraints_7.fill = GridBagConstraints.HORIZONTAL;
        getContentPane().add(button_7, gridBagConstraints_7);
        //
    }

}

运行结果:

2. 常用面板

  • 面板也是一个Swing容器,它可以作为容器容纳其他组件,但它也必须被添加到其他容器中。Swing中常用的面板包括JPanel面板和JScrollPane面板。

JPanel面板

  • JPanel面板可以聚集一些组件来布局。
package com.lzw;

import java.awt.*;

import javax.swing.*;

public class JPanelTest extends JFrame {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public JPanelTest() {
        Container c = getContentPane();
        // 将整个容器设置为2行1列的网格布局
        c.setLayout(new GridLayout(2, 1, 10, 10));
        // 初始化一个面板,设置1行3列的网格布局
        JPanel p1 = new JPanel(new GridLayout(1, 3, 10, 10));
        JPanel p2 = new JPanel(new GridLayout(1, 2, 10, 10));
        JPanel p3 = new JPanel(new GridLayout(1, 2, 10, 10));
        JPanel p4 = new JPanel(new GridLayout(2, 1, 10, 10));
        p1.add(new JButton("1")); // 在面板中添加按钮
        p1.add(new JButton("1"));
        p1.add(new JButton("2"));
        p1.add(new JButton("3"));
        p2.add(new JButton("4"));
        p2.add(new JButton("5"));
        p3.add(new JButton("6"));
        p3.add(new JButton("7"));
        p4.add(new JButton("8"));
        p4.add(new JButton("9"));
        c.add(p1); // 在容器中添加面板
        c.add(p2);
        c.add(p3);
        c.add(p4);
        setTitle("在这个窗体中使用了面板");
        setSize(420, 200);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }

    public static void main(String[] args) {
        new JPanelTest();
    }
}

运行结果:

  • 在这个实例中,首先设置整个窗体的布局为2行1列的网格布局,然后先后定义4个面板,分别为4个面板设置网格布局,行列数会有所不同,将按钮放置在每个面板中,最后将面板添加至容器中。

JScrollPane面板

  • 在设置界面时,可能会遇到在一个较小的容器窗体中显示一个较大部分的内容的情况,这时可以使用JScrollPane面板。JScrollPane面板是带滚动条的面板,它也是一种容器,但是JScrollPane只能放置一个组件,并且不可以使用布局管理器。如果需要在JScrollPane面板放置多个组件,需要将多个组件放在JPanel面板上,然后将JPanel面板作为一个整体组件添加在JScrollPane组件上。
package com.lzw;

import java.awt.*;

import javax.swing.*;

public class JScrollPaneTest extends JFrame {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public JScrollPaneTest() {
        Container c = getContentPane(); // 创建容器
        JTextArea ta = new JTextArea(20, 50); // 创建文本区域组件
        JScrollPane sp = new JScrollPane(ta); // 创建JScrollPane面板对象
        c.add(sp); // 将该面板添加到该容器中

        setTitle("带滚动条的文字编译器");
        setSize(200, 200);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }

    public static void main(String[] args) {
        new JScrollPaneTest();

    }

}

运行结果:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • java是面向过程的编程语言:Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越...
    Java小辰阅读 3,044评论 0 17
  • 面向对象主要针对面向过程。 面向过程的基本单元是函数。 什么是对象:EVERYTHING IS OBJECT(万物...
    sinpi阅读 1,046评论 0 4
  • 十七、Swing程序设计(一) 1. Swing概述 原来的AWT组件来自java.awt包,当含有AWT组件的j...
    十四12138阅读 321评论 0 0
  • 1.import static是Java 5增加的功能,就是将Import类中的静态方法,可以作为本类的静态方法来...
    XLsn0w阅读 1,217评论 0 2
  • 经典传承| 回归传统|唤醒良知| 正念正行 俗话说:欲成大事,先了心病。《道德经》就是一本根治心病的奇书,自古治愈...
    易鸣_1cc8阅读 336评论 0 0