Swing图形界面之布局

Swing常用容器

  AWTSwing都提供了容器。Swing是在AWT基础上引入的成分,并且比AWT功能上强。这里我们说一些常用的容器。

框架

  JFrame是一种独立存在的容器,是Frame类的子类,他的对象包含边框。他的构造函数如下:
- public JFrame()是创建一个框架。
- public JFrame(String title)是创建一个带标题的框架。

通过Swing创建的框架一开始是不可见的,必须调用Window类的show()方法或Component类的setVisible()方法来显示框架。

例如定义一个JFrame子类:

import javax.swing.*;

class subJFrame extends JFrame{
    public subJFrame(){}
    public subJFrame(String title){
        super(title);
    }
    protected void frameInit(){
        super.frameInit();
        // shut down the Frame
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
}

需要注意的是我们点击窗口(框架)上的关闭按钮时,并不会关闭程序,需要自己写代码来实现关闭窗口setDefaultCloseOperation(EXIT_ON_CLOSE)
# 并且我们把这段代码创建单独subJFrame.java文件。以后需要每次使用,并且要放在同一个package中。

布局管理器

  为了保持GUI程序的平台独立性,也为了使基本组件的排列更加有规范,Java提供了布局管理器来完成这个任务。

FlowLayout布局

  该布局将组件按加入的先后顺序从左至右排列,一行满了换行继续排。默认下,将组件放置在每行中央居中显示。对齐方式有三种:
- align 对齐方式
- hor 水平间隔
- ver 垂直间隔

  该布局的构造函数如下:
- public FlowLayout() 生成一个默认对象,居中对齐,垂直和水平间隔为5。
- public FlowLayout(int align) 生成指定对齐方式的对象,垂直和水平间隔为5。
- public FlowLayout(int align, int hor, int ver) 生成指定对齐方式,垂直和水平间隔的对象。

实验效果

import java.awt.*;
import javax.swing.*;

public class FlowLayoutTest {
    JFrame frame;
    Container contentPane;
    JPanel jp;
    FlowLayout layout;

    public static void main(String[] AUG){
        FlowLayoutTest obj = new FlowLayoutTest();
        obj.testFlow();
        obj.changeAlign();
    }

    private void changeAlign() {
        for (int i = 0; i < 100; i++) {
            try{
                Thread.sleep(500); // Freshing layout every 0.5s
            }catch(Exception e){
                e.printStackTrace();
            }
            switch (i % 3){
                case 0:
                    layout.setAlignment(FlowLayout.LEFT);
                    break;
                case 1:
                    layout.setAlignment(FlowLayout.CENTER);
                    break;
                case 2:
                    layout.setAlignment(FlowLayout.RIGHT);
                    break;
            }
            layout.layoutContainer(contentPane);

        }
    }

    private void testFlow() {
        frame = new subJFrame("FlowLayoutTest");
        contentPane = frame.getContentPane();
        jp = new JPanel();
        layout = new FlowLayout();
        fillComponent(jp);
        contentPane.add(jp);
        layout = new FlowLayout(FlowLayout.CENTER, 20, 50);
        contentPane.setLayout(layout);
        frame.setSize(400, 200);
        frame.setVisible(true);
    }

    private static void fillComponent(Container c) {
        for (int i = 0; i < 3; i++) {
            c.add(new JButton("Button" + i));

        }
    }
}

运行实例:
FlowLayout

BorderLayout布局

  该布局通过划分空间(即窗口)来将组件添加至里面,划分为西6个方位。当窗口缩放时,中间的组件缩放变化最大,其他组件只是在需要时改变来填充窗口。
  同样,该布局构造函数如下:
- public BorderLayout() 生成默认对象,其中组件垂直和水平间隔为0.
- public BorderLayout(int hgap, int vgap) 生成指定组件的垂直和水平间隔的对象。

需要注意的是,放入窗口时,需要指定组件的方位,如 add(position, object)

实验效果

import java.awt.*;
import javax.swing.*;

public class BorderLayoutTest {
    JFrame frame;
    Container contentPanel;
    BorderLayout layout;
    JButton buttons[];
    String names[] = {"North", "South", "East", "West", "Center"};

    private void fillComponent(Container c){
        buttons = new JButton[names.length];
        for (int i = 0; i < names.length; i++) {
            buttons[i] = new JButton(names[i]);
        }

        // add Buttons to the position.
        c.add(buttons[0], BorderLayout.NORTH);
        c.add(buttons[1], BorderLayout.SOUTH);
        c.add(buttons[2], BorderLayout.WEST);
        c.add(buttons[3], BorderLayout.EAST);
        c.add(buttons[4], BorderLayout.CENTER);
    }

    public void testBorder(){
        frame = new subJFrame("BorderLayoutTest");
        contentPanel = frame.getContentPane();
        layout = new BorderLayout(5, 5);
        contentPanel.setLayout(layout);
        fillComponent(contentPanel);
        frame.setSize(600, 400);
        frame.setVisible(true);
    }

    public void hidenButton(){
        for (int i = 0; i < names.length; i++) {
            try{
                Thread.sleep(500);  // Freshing layout every 0.5s
            }catch(Exception e){
                e.printStackTrace();
            }
            buttons[i].setVisible(false);
            layout.layoutContainer(contentPanel);
        }
    }

    public void showButton(){
        for (int i = names.length-1; i >= 0; i--) {
            try{
                Thread.sleep(500);
            }catch(Exception e){
                e.printStackTrace();
            }
            buttons[i].setVisible(true);
            layout.layoutContainer(contentPanel);
        }
    }

    public static void main(String[] AUG){
        BorderLayoutTest obj = new BorderLayoutTest();
        obj.testBorder();
        while(true) {
            obj.hidenButton();
            obj.showButton();
        }
    }
}

运行实例:
BorderLayout

GridLayout布局

  该容器将容器空间划分为网格状,各组件占据大小相同的区域。其构造函数如下:
- public GridLayout() 生成默认的对象,行数为1。
- public GridLayout(int rows, int cols) 生成指定行数和列数的对象。
- public GridLayout(int rows, int cols, int hgap, int vgap) 生成指定行数、列数、水平和垂直间隔的对象。

在填写rows或者cols时,当其中一项为0时,表示任意数量的行或列。但两者不能同时为0

实验效果

import java.awt.*;
import javax.swing.*;

public class GridLayoutTest {
    JFrame frame;
    Container contentPane;
    GridLayout grid_1, grid_2;
    JButton buttons[];
    String names[] = {"One", "Two", "Three", "Four", "Five", " Six"};
    boolean change;    // setting a signal

    public GridLayoutTest(){
        frame = new subJFrame("GridLayoutTest");
        contentPane = frame.getContentPane();
        // setting a 2 rows and 3 clos layout
        grid_1 = new GridLayout(2,3,5,5);
        // setting a 3 rows and 2 clos layout
        grid_2 = new GridLayout(3,2);
        contentPane.setLayout(grid_1);
        fillComponent(contentPane);
        change = true;
        frame.setSize(500, 400);
        frame.setVisible(true);
    }

    private void fillComponent(Container c){
        buttons = new JButton[names.length];
        for (int i = 0; i < names.length; i++) {
            buttons[i] = new JButton(names[i]);
            c.add(buttons[i]);
        }
    }

    public void GridTest(){
        while(true){
            try{
                Thread.sleep(500);  // Freshing layout every 0.5s
            }catch(Exception e){
                e.printStackTrace();
            }
            if(change){
                contentPane.setLayout(grid_1);
            }else{
                contentPane.setLayout(grid_2);
            }
            change = !change;  // Reverse signal
            contentPane.validate();  // Make the changed layout effective
        }
    }

    public static void main(String[] AUG) {
        GridLayoutTest obj = new GridLayoutTest();
        obj.GridTest();
    }
}

运行实例:
GridLayout

CardLayout布局

  有时候需要多种组件,但限于屏幕大小有限,不能同时显示,那就把组件分为,每组放在一个面板中,按照该布局的方式放置在窗口中。这样窗口的同一显示区放置多个不同组件,而每一刻只显示其中一组。但该组件比较复杂
1. 创建一个布局对象和一个承载该对象的面板。
2. 采用该对象设置面板的布局管理器。
3. 调用 add()方法将组件添加到面板对象中。

其常用方法如下:
- public CardLayout() 生成默认对象,各卡片之间垂直和水平间隔为0
- public CardLayout(int hgap, int vgap) 生成指定卡片之间的垂直和水平间隔的对象
- public void first(Container parent) 显示第一张卡片
- public void last(Container parent) 显示最后一张卡片
- public void next(Container parent) 显示下一张卡片(可循环)
- public void previous(Container parent) 显示前一张卡片(可循环)

实验效果

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class CardLayoutTest implements ActionListener{
    Frame frame;
    Container contentPanel;
    JPanel deck;
    CardLayout cardManager;
    JButton buttons[];
    String names[] = {"First", "Next", "Previous", "Last"};

    public CardLayoutTest(){
        frame = new subJFrame("CardLayoutTest");
        contentPanel = ((subJFrame) frame).getContentPane();
        deck = new JPanel();
        cardManager = new CardLayout(); // define a layout manager
        deck.setLayout(cardManager);  // setting a layout of content

        // setting card_1
        JPanel card_1 = new JPanel();
        JLabel lab_1 = new JLabel("No.1 Card");
        card_1.add(lab_1);
        deck.add(card_1, lab_1.getText());

        // setting card_2
        JPanel card_2 = new JPanel();
        JTextField field = new JTextField("No.2 Card");
        card_2.add(field);
        deck.add(card_2, field.getText());

        // setting card_3
        JPanel card_3 = new JPanel();
        JLabel lab_3 = new JLabel("No.3 Card");
        card_3.setLayout(new BorderLayout());
        card_3.add(new JButton("North"), BorderLayout.NORTH);
        card_3.add(new JButton("South"), BorderLayout.SOUTH);
        card_3.add(new JButton("West"), BorderLayout.WEST);
        card_3.add(new JButton("East"), BorderLayout.EAST);
        card_3.add(lab_3, BorderLayout.CENTER);
        deck.add(card_3, lab_3.getText());

        // setting controlPanel
        JPanel controls = new JPanel();
        controls.setLayout(new GridLayout(2, 2));
        buttons = new JButton[names.length];
        for (int i = 0; i < names.length; i++) {
            buttons[i] = new JButton(names[i]);
            buttons[i].addActionListener(this);
            controls.add(buttons[i]);
        }

        // add to the deck
        contentPanel.add(controls, BorderLayout.WEST);
        contentPanel.add(deck, BorderLayout.EAST);
        frame.setSize(600, 400);
        frame.setVisible(true);
    }

    public void actionPerformed(ActionEvent e){
        if(e.getSource() == buttons[0])  // show the first card
            cardManager.first(deck);
        else if(e.getSource() == buttons[1])  // show the next card
            cardManager.next(deck);
        else if(e.getSource() == buttons[2])  // show the previous card
            cardManager.previous(deck);
        else if(e.getSource() == buttons[3])  // show the last card
            cardManager.last(deck);
    }

    public static void main(String[] AUG) {
        new CardLayoutTest();
    }
}

运行实例:
CardLayout

你们看到这里说明那你是个优秀的读者,你能仔细看完,那就是你的财富。


爱狂笑的孩子运气不会差