Java 入門指南 - GridBagLayout

GridBagLayout 的作法是把視窗分成一個一個的格子 (grid) ,然後把小工具 (widget) 放到選定的格子中,可依視窗元件的大小設定佔用的格子數




當視窗設定為 GridBagLayout 的排版方式後,視窗物件利用 add() 方法加入視窗元件時,必須額外提供 GridBagConstraints 類別 (class) 的參數 (parameter) ,因為實際的設定是由 GridBagConstraints 型態的物件 (object) 來完成的。


以下這些 GridBagConstraints 型態物件的屬性 (field) 是我們需要設定的
gridx行數
gridy列數
gridwidth行寬
gridheight列高
weightx行權值
weighty列權值
fill填滿方式
anchor定位點


直的為行 (column) ,橫的為列 (row) ,行與列的起始值都是 0 。例如,我們要在第 1 行,第 0 列放一個 JTextField ,佔用 1 列,跨 6 行,因此屬於該 JTextField 的 GridBagConstraints 型態物件的屬性 gridx 設定為 1 , gridy 為 0 , gridwidth 為 6 , gridheight 為 1 。


有關行權值與列權值部份,我們的範例中設定為 0 即可。


填滿方式有底下數種
GridBagConstraints.BOTH垂直水平都填滿
GridBagConstraints.VERTICAL垂直填滿
GridBagConstraints.HORIZONTAL水平填滿
GridBagConstraints.NONE不填滿


定位點也有底下數種
GridBagConstraints.CENTER中央對齊
GridBagConstraints.EAST向右對齊
GridBagConstraints.SOUTHEAST右下對齊
GridBagConstraints.SOUTH向下對齊
GridBagConstraints.SOUTHWEST左下對齊
GridBagConstraints.WEST向左對齊
GridBagConstraints.NORTHWEST左上對齊
GridBagConstraints.NORTH向上對齊
GridBagConstraints.NORTHEAST右上對齊


填滿方式與定位點就是依需求來設定囉!好了,我們來看看實際的 EncryptorGUI.java 吧!
import java.awt.*;
import javax.swing.*;

public class EncryptorGUI {
    private JFrame frame;
    private String[] name;
    
    public EncryptorGUI() {
        frame = new JFrame();
        String n[] = {"Input", 
                      "Output", 
                      "hint...", 
                      "New", 
                      "Load", 
                      "Save", 
                      "Encode", 
                      "Decode", 
                      "Clear", 
                      "Copy"};
        name = n;
    }
    
    public void run() {
        frame.setSize(600, 160);
        frame.setLayout(new GridBagLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         
        JLabel n0 = new JLabel(name[0]);
        GridBagConstraints c0 = new GridBagConstraints();
        c0.gridx = 0;
        c0.gridy = 0;
        c0.gridwidth = 1;
        c0.gridheight = 1;
        c0.weightx = 0;
        c0.weighty = 0;
        c0.fill = GridBagConstraints.NONE;
        c0.anchor = GridBagConstraints.WEST;
        frame.add(n0, c0);
        
        JLabel n1 = new JLabel(name[1]);
        GridBagConstraints c1 = new GridBagConstraints();
        c1.gridx = 0;
        c1.gridy = 1;
        c1.gridwidth = 1;
        c1.gridheight = 1;
        c1.weightx = 0;
        c1.weighty = 0;
        c1.fill = GridBagConstraints.NONE;
        c1.anchor = GridBagConstraints.WEST;
        frame.add(n1, c1);
        
        JLabel n2 = new JLabel(name[2]);
        GridBagConstraints c2 = new GridBagConstraints();
        c2.gridx = 0;
        c2.gridy = 3;
        c2.gridwidth = 7;
        c2.gridheight = 1;
        c2.weightx = 0;
        c2.weighty = 0;
        c2.fill = GridBagConstraints.BOTH;
        c2.anchor = GridBagConstraints.WEST;
        frame.add(n2, c2);

        JTextField n3 = new JTextField();
        GridBagConstraints c3 = new GridBagConstraints();
        c3.gridx = 1;
        c3.gridy = 0;
        c3.gridwidth = 6;
        c3.gridheight = 1;
        c3.weightx = 0;
        c3.weighty = 0;
        c3.fill = GridBagConstraints.BOTH;
        c3.anchor = GridBagConstraints.WEST;
        frame.add(n3, c3);
        
        JTextField n4 = new JTextField();
        GridBagConstraints c4 = new GridBagConstraints();
        c4.gridx = 1;
        c4.gridy = 1;
        c4.gridwidth = 6;
        c4.gridheight = 1;
        c4.weightx = 0;
        c4.weighty = 0;
        c4.fill = GridBagConstraints.BOTH;
        c4.anchor = GridBagConstraints.WEST;
        frame.add(n4, c4);
               
        for (int i = 0; i < 7; i++) {
            JButton n5 = new JButton(name[i + 3]);
            GridBagConstraints c5 = new GridBagConstraints();
            c5.gridx = i;
            c5.gridy = 2;
            c5.gridwidth = 1;
            c5.gridheight = 1;
            c5.weightx = 0;
            c5.weighty = 0;
            c5.fill = GridBagConstraints.BOTH;
            c5.anchor = GridBagConstraints.CENTER;
            frame.add(n5, c5);
        }
        
        frame.setVisible(true);
    }
}
    
/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:EncryptorGUI.java
    功能:示範 Java 程式 
    作者:張凱慶
    時間:西元 2011 年 4 月 */


實際操作 EncryptorGUI 由 EncryptorGUIDemo.java 來進行
public class EncryptorGUIDemo {
    public static void main(String[] args) {
        EncryptorGUI gui = new EncryptorGUI();
        gui.run();
    }
}    
/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:EncryptorGUIDemo.java
    功能:示範 Java 程式 
    作者:張凱慶
    時間:西元 2011 年 4 月 */


記得,兩個都是新類別檔案,所以各自都要先編譯,才可以執行



結果如下



是的,這就是我們要的 GUI 外觀了,不過除了按鈕都在同一列,所以可以用一個迴圈 (loop) 設定外,其他的視窗元件都得個別設定有點麻煩,可不可以簡單一點呢?可以的,但是我們得先把視窗元件的參考變數都放到 ArrayList 中!


中英文術語對照
格子grid
小工具widget
類別class
參數parameter
物件object
屬性field
column
row
迴圈loop


您可以繼續參考
GUI 篇


相關目錄
回 Java 入門指南
回 Java 教材目錄
回首頁


參考資料
The JavaTM Tutorials: Getting Started
The JavaTM Tutorials: Learning the Java Language
The JavaTM Tutorials: Essential Classes
The Java Language Specification, Third Edition


本文於 2013 年 1 月訂正

4 則留言:

symis 提到...

請問#10~#20為何不能簡化為:
name = {...陣列內容 ?
感謝指教!

Kaiching Chang 提到...

因為 name 先被宣告為屬性,所以要實際建立 name ,就要用 new 來建立,例如
name = new String[10];
name[0] = "Input";
//以下略

大括弧屬於陣列的字面常數,用法是宣告後直接建立陣列物件中的初值。這裡是在建構子中建立區域的字串物件 n 後,再把 n 的參考給 name ,相對用 new 而言算是較簡化的寫法。

symis 提到...

再請教觀念問題:
1. 是否可把#5. 和#9. 合併為:public JFrame frame = new JFrame(); 然後放在#5 ?

2. 關於陣列,是否以下的a均相同?
(a) int[] a = {1,2};
(b) int a[] = {1,2};
(c) int a[];
a = new int[2];
a[0] = 1;
a[1] = 2;
(d) int a[] = new int[2];
a[0] = 1;
a[1] = 2;
(e) int a[];
a = new int[]{1,2};
(f) int[] a = new int[]{1,2};
(g) int a[];
int b[] = {1,2};
a = b;
以上是我參考下面的 (原來new是有省略用法的?)
http://mis.hwai.edu.tw/~kevin/MISProject/JAVAProject/chapter4/c4-2.htm

3. 您的程式是否屬於2.的(g)此類?
若是,那就可改寫為像2.的(e)那樣囉?

謝謝教導!

Kaiching Chang 提到...

1. 可以,不過我們的目的是把屬性的初始化放在建構子中,因此採取以上寫法;

2. 只要通過編譯,也就是編譯器沒有挑出錯誤就是支援的寫法;

3. 是的,可以這樣改寫。

至於陣列的中括弧應統一放在型態名稱後或是識別字後,我這裡的 String n[] 應該改成 String[] n 比較一致。