深入學習GridBagLayout


  試着用用你會發現其實GridBagLayout真的能解決幾乎所有界面布局的問題,窗口大小的隨意改變也不會影響到整體布局,更重要的是它可以實現任何你想要的布局設計,只要你做到更有計划和更有耐心一點就行了。對於簡單的程序使用Boborderlayout和Gridlayout就綽綽有余了, 但如果要把程序提到實際應用上你就得考慮使用GridBagLayout。當然, 做復雜的應用程序時,一開始就使用GridBagLayout就會更有效率。一旦你決定使用GridBagLayout,接下來一步便是要找一些紙和鉛筆,只有你准確知道你的界面看上去需要成什么樣子,你就可以敲鍵盤。這就是說,你應該在編碼之前進行妥善規划。

  GridBagLayout從它的名字中你也可以猜到,它同GridLayout一樣,在容器中以網格形式來管理組件.但GridBagLayout功能要來得強大得多.
1、GridBagLayout管理的所有行和列都可以是大小不同的.
2、GridLayout把每個組件限制到一個單元格,而GridBagLayout並不這樣:組件在容器中可以占據任意大小的矩形區域,GridBagLayout通常由一個專用類來對他布局行為進行約束,該類叫GridBagConstraints.其中的所有成員都是public的, 因此要學好如何使用GridBagLayout首先要了解有那些約束變量,以及如何設置這些約束變量.以下是GridBagConstraints的公有成員變量:

構造函數:
    GirdBagLayout()建立一個新的GridBagLayout管理器。
    GridBagConstraints()建立一個新的GridBagConstraints對象。
    GridBagConstraints(int gridx,int gridy,
                                   int gridwidth,int gridheight,
                                   double weightx,double weighty,
                                   int anchor,int fill, Insets insets,
                                   int ipadx,int ipady)建立一個新的GridBagConstraints對象,並指定其參數的值。
參數說明:
 gridx,gridy    ——    設置組件的位置,
                       gridx設置為GridBagConstraints.RELATIVE代表此組件位於之前所加入組件的右邊。
                       gridy設置為GridBagConstraints.RELATIVE代表此組件位於以前所加入組件的下面。
                      建議定義出gridx,gridy的位置以便以后維護程序。gridx=0,gridy=0時放在0行0列。

 gridwidth,gridheight    ——    用來設置組件所占的單位長度與高度,默認值皆為1。
                           你可以使用GridBagConstraints.REMAINDER常量,代表此組件為此行或此列的最后一個組件,而且會占據所有剩余的空間。

 weightx,weighty    ——    用來設置窗口變大時,各組件跟着變大的比例。
                        當數字越大,表示組件能得到更多的空間,默認值皆為0。

 anchor    ——    當組件空間大於組件本身時,要將組件置於何處。
                  有CENTER(默認值)、NORTH、NORTHEAST、EAST、SOUTHEAST、WEST、NORTHWEST選擇。

 insets    ——    設置組件之間彼此的間距。
                它有四個參數,分別是上,左,下,右,默認為(0,0,0,0)。

ipadx,ipady    ——    設置組件間距,默認值為0。

   你應該能看到在草圖里有一些線,這些線是用來把總界面分成若干行和列的,這樣你就很清楚每一個組件放置的格子位置。這就是GridBagLayout里"格"的那一部分,而圖上的數字就是格的號碼。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridBagWindow extends JFrame {
  private JButton searchBtn;
  private JComboBox modeCombo;
  private JLabel tagLbl;
  private JLabel tagModeLbl;
  private JLabel previewLbl;
  private JTable resTable;
  private JTextField tagTxt;
 public GridBagWindow() {
   Container contentPane = getContentPane();
   GridBagLayout gridbag = new GridBagLayout();
   contentPane.setLayout(gridbag);
   GridBagConstraints c = new GridBagConstraints();
   //setting a default constraint value
   c.fill =GridBagConstraints.HORIZONTAL;
   tagLbl = new JLabel("Tags");
   c.gridx = 0; //x grid position
   c.gridy = 0; //y grid position
   gridbag.setConstraints(tagLbl, c); //associate the label with a constraint object 
   contentPane.add(tagLbl); //add it to content pane
   
   tagModeLbl = new JLabel("Tag Mode");
   c.gridx = 0;
   c.gridy = 1;
   gridbag.setConstraints(tagModeLbl, c);
   contentPane.add(tagModeLbl);
   tagTxt = new JTextField("plinth");
   c.gridx = 1;
   c.gridy = 0;
   c.gridwidth = 2;
   gridbag.setConstraints(tagTxt, c);
   contentPane.add(tagTxt);
   String[] options = {"all", "any"};
   modeCombo = new JComboBox(options);
   c.gridx = 1;
   c.gridy = 1;
   c.gridwidth = 1;
   gridbag.setConstraints(modeCombo, c);
   contentPane.add(modeCombo);
   searchBtn = new JButton("Search");
   c.gridx = 1;
   c.gridy = 2;
   gridbag.setConstraints(searchBtn, c);
   contentPane.add(searchBtn);
   resTable = new JTable(5,3);
   c.gridx = 0;
   c.gridy = 3;
   c.gridwidth = 3;
   gridbag.setConstraints(resTable, c);
   contentPane.add(resTable);
   previewLbl = new JLabel("Preview goes here");
   c.gridx = 0;
   c.gridy = 4;
   gridbag.setConstraints(previewLbl, c);
   contentPane.add(previewLbl);
  addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
     System.exit(0);
    }
  });
}
 public static void main(String args[]) {
  GridBagWindow window = new GridBagWindow();
  window.setTitle("GridBagWindow");
  window.pack();
  window.setVisible(true);
 }
}

 

構造方法前的代碼都不是很特殊,都是一些相當標准的import和變量定義。但是進入構造方法后,事情就變得有趣了。

Container contentPane = getContentPane();

GridBagLayout gridbag = new GridBagLayout();

contentPane.setLayout(gridbag);

    我們以GridBagWindow的內容面板作為開始來創建一個GridBagLayout對象,准確地說,這個方法與過去我們所創建GridLayout對象和BorderLayout對象的方法是一樣的。那么,現在我們就開始來設置GridBagLayout對象使它作為內容面板的布局。

GridBagConstraints c = new GridBagConstraints();

    然后我要提到這整個進程中的一個獨特的對象,那就是GridBagConstraints。這個對象在GridBagLayout中控制所有被安置在其中組件的約束。為了把一個組件增加到你的GridBagLayout中去,你首先必須將它與一個GridBagConstraints對象建立連接。

GridBagConstraints可以從11個方面來進行控制和操縱,也可以給你提供一些幫助。這些內容是:

  • Gridx——組件的橫向坐標
  • Girdy——組件的縱向坐標
  • Gridwidth——組件的橫向寬度,也就是指組件占用的列數,這與HTML的colspan類似
  • Gridheight——組件的縱向長度,也就是指組件占用的行數,這與HTML的rowspan類似
  • Weightx——指行的權重,告訴布局管理器如何分配額外的水平空間
  • Weighty——指列的權重,告訴布局管理器如何分配額外的垂直空間
  • Anchor——告訴布局管理器組件在表格空間中的位置
  • Fill——如果顯示區域比組件的區域大的時候,可以用來控制組件的行為。控制組件是垂直填充,還是水平填充,或者兩個方向一起填充
  • Insets——指組件與表格空間四周邊緣的空白區域的大小
  • Ipadx—— 組件間的橫向間距,組件的寬度就是這個組件的最小寬度加上ipadx值
  • ipady—— 組件間的縱向間距,組件的高度就是這個組件的最小高度加上ipady值

    可能對於一個組件的每一個實例你都需要為它建立一個單獨的GridBagConstraints;然而,這種方法我們並不推薦使用。最好的方法是,當你調用它的時候把對象設置為默認值,然后針對於每一個組件改變其相應的域。

    這個方法具有通用性,因為在一些域中,比如insets、padx、pady和fill這些域,對於每一個組件來說一般都是相同的,因此這樣對一個域進行設置就會更輕松了,也能更輕松的在另外的組件中改變某些域的值。

    如果在改變了某些域值之后,你想回到原始的域值的話,你應該在增加下一個組件之前進行改變。這種方法使你更容易明白你正在修改的內容,也能使你更容易明白在一連串對象中的這11個參數的作用。

    也許你現在對這些內容還是一知半解,不過事實上一旦你理解了GridBagConstraints,值得安慰的是你以后做再困難的工作都會游刃有余了。

所以,如果我們已經明白了GridBagConstraints的詳細用法了,那么現在就讓我們來看看在實際應用中應該如何來實現它:

tagLbl = new JLabel("Tags");
c.gridx = 0; //x grid position
c.gridy = 0; //y grid position
gridbag.setConstraints(tagLbl, c); //設置標簽的限制

contentPane.add(tagLbl); //增加到內容面板

我們所做的是示例我們的標簽、分配給它一個格位置,將它與一個約束對象聯系起來並把它增加到我們的內容面板中。

tagModeLbl = new JLabel("Tag Mode");
c.gridx = 0;
c.gridy = 1;
gridbag.setConstraints(tagModeLbl, c);

contentPane.add(tagModeLbl);

  請注意,雖然我們已經在我們的約束對象中把gridx的值設置為0,但是在這里我們仍然要對它進行重新設置——這樣做沒有其它原因,只是為了增加可讀性。

    下面,我們增加一個文本域以便能存儲我們希望能搜索到的關鍵字,再增加一個組合框以便用來搜索多個關鍵字。除了我們希望的文本域有兩列之外,這個概念其他的方面都與上面所說的是相同的,所以,我們需要在增加組合框之前重新設置文本域的值。

tagTxt = new JTextField("plinth");
c.gridx = 1;
c.gridy = 0;
c.gridwidth = 2;
gridbag.setConstraints(tagTxt, c);
contentPane.add(tagTxt);

String[] options = {"all", "any"};
modeCombo = new JComboBox(options);
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
gridbag.setConstraints(modeCombo, c);
contentPane.add(modeCombo);

      做了這些之后,我們再在內容面板中增加一些其余的簡單組件,這時候我們就能夠瀏覽它了;其余的代碼應該不會出現任何問題了。

到這個階段,我們應該已經得到了一個類似於我們先前所設計的界面了。

 最近正在修改《公交線路查詢系統》,做系統的時候都是用NULL布局,由於NULL布局調用windows系統的API,所以生成的程序無法在其他平台上應用,而且如果控件的數量很多,管理起來也比較麻煩,最近我發現一個非常強大的布局模式 :GridBagConstraints布局,先發一個實例:
gridx = 2; // X2
gridy = 0; // Y0
gridwidth = 1; // 橫占一個單元格
gridheight = 1; // 列占一個單元格
weightx = 0.0; // 當窗口放大時,長度不變
weighty = 0.0; // 當窗口放大時,高度不變
anchor = GridBagConstraints.NORTH; // 當組件沒有空間大時,使組件處在北部
fill = GridBagConstraints.BOTH; // 當格子有剩余空間時,填充空間
insert = new Insets(0, 0, 0, 0); // 組件彼此的間距
ipadx = 0; // 組件內部填充空間,即給組件的最小寬度添加多大的空間
ipady = 0; // 組件內部填充空間,即給組件的最小高度添加多大的空間
new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insert, ipadx, ipady);

GridBagLayout之變態玩法:
很多人抱怨GridBagLayout沒有XYLayout布局靈活,但是做為一個專業程序,所有組件必須隨着窗口大小改變而改變。其次,當僅僅簡單使用XYLayout時,需要包含一個大庫,對於一些場合這些多余的類超出了可接受范圍(例如Applet應用)
拿一個比較簡單的界面來作介紹 
1。首先建立一個JFrame,設定它的Layout為XYLayout 
2。在其上堆上控件,對齊好位置,否則轉換時會有較大調整 
3。完成創建控件后,設置Layout為GridBagLayout,這時所有控件基本保持原位,待下一步做精細調整 
4。選擇一個控件,點擊右邊屬性欄的"constraints" 對應的調整按鈕,彈出最重要的屬性調整界面 
5。將所有邊界和空白去掉,同時Grid大小也暫時去掉,因為這些邊距會影響我們的調整 
6。設置需要擴展的行和列 
7。粗輪廓完成后,可以設置組件邊距進行精細調整了 
8。精細調整完成,運行調試

JAVA布局模式:GridBagConstraints終極技巧



以下是GridBagLayout的詳解:
雖說GridBagLayout和GridLayout只有一點差別,它
的作用卻是出奇的大。這是因為GridBagLayout一改其他的外觀管理器的死板
模樣,具有很多的靈活性。它不再像其他的外觀管理器那樣,使得各個組件
的大小都一樣。 GridBagLayout通過類GridBagConstraints的幫助,按照
設計的意圖,改變組件的大小,把它們擺在設計者希望擺放的位置上。

在GridBagLayout中,每個組件都有一個GridBagConstraints 
對象來給出它的大小和擺放位置。我們在使用GridBagLayout的時候,最重 
要的就是學會使用這個類GridBagConstraints的使用方法,學會如何設置組
件的大小、位置等限制條件。

我們先看一個用GridBagLayout外觀管理器生成的窗口

JAVA布局模式:GridBagConstraints終極技巧



圖14.8程序14.5的執行結果


這個窗口里面的幾個按鈕有的大、有的小,其大小、位
置均不同,沒有一定的規律可循,這即是發揮了GridBagLayout外觀管理器
的靈活性。生成此窗口的程序為:

程序14.5

  importjava.awt.*;

      //輸入所有的java.awt 類

  publicclasswindow7extendsjava.applet.Applet

  {

   publicvoidinit() {

    resize(300,100);//設置窗口的大小

    GridBagConstraintsgbc=new GridBagConstraints(
);//使用類GridBagConstriants

    setLayout(newGridBagLayout());//設定外觀
管理器為 GridBagLayout外觀管理器 

    gbc.fill =GridBagConstraints.BOTH;//★
所有的按鈕都會把分配的剩余空間填滿

    gbc.gridwidth=1;//★設置第一個按鈕的大


    gbc.gridheight=1;// ★

    ButtonButton1=newButton("東 ");

    ((GridBagLayout)getLayout( )).setConstraints(Button1,gbc);

     add(Button1);

    gbc.gridwidth= GridBagConstraints.REMAINDER;
//★第二個按鈕填滿整行空間

    ButtonButton2=newButton("西 ");

    ((GridBagLayout)getLayout( )).setConstraints(Button2,gbc);

     add(Button2);

    gbc.gridheight=4;//設置第三個按鈕的大


    gbc.gridwidth= 1;

    ButtonButton3=newButton("南 ");

    ((GridBagLayout)getLayout( )).setConstraints(Button3,gbc);

     add(Button3);

    gbc.gridheight=2;//設置第四個按鈕的大


    gbc.gridwidth= 2;//GridBagConstraints.REMAINDER;

     ButtonButton4=newButton("北");

     ((GridBagLayout)getLayout( )).setConstraints(Button4,gbc);

     add(Button4);

    gbc.gridwidth= GridBagConstraints.REMAINDER;

    Button Button5=newButton("中");

     ((GridBagLayout)getLayout( )).setConstraints(Button5,gbc);

     add(Button5);

    gbc.insets=new Insets(5,6,7,8);//★設置第五個按鈕的位置

    ButtonButton6=newButton("好酒在張弓");

    ((GridBagLayout)getLayout( )).setConstraints(Button6,gbc);

     add(Button6);

           }

  }

  ★注釋:程序14.5里面有星號的語句都將做詳細的解釋


下面就詳細地解釋一下程序14.5,通過對這個小程序的分析可以從中了解GridBagLayout外觀管理器的工作原理和工作方法。



  GridBagLayout外觀管理器實際上是根據類GridBagConstraints所給
出的條件限制以及組件本身的一向特性條件(例如每個組件程序允許的最小
尺寸),來決定各個組件的外觀的。 


讓我們把程序14.5之中出現的新鮮的語句一條一條地看個明白吧:


1.gbc.fill=GridBagConstraints.BOTH;


每個組件有一定的原始大小,例如在類FlowLayout外
觀管理器的管理之下顯示的就都是組件的本身原始大小。如果我們分配給一
個組件的空間比它原本所需要的空間大時,就需要一定的方式方法來決定如
何處理這一部分多余的空間。這時就用到了fill值。Java根據人們給這個
fill設定的值來決定如何處理比組件原始空間大的那部分空間。 

fill可以取四種不同的值,它們分別代表了四種不同
的剩余空間處理方式:

GridBagConstraints.NONE

  不必理睬剩余空間的存在,讓它空着好了。

GridBagConstraints.BOTH

  不讓一點剩余空間存在,改變組件的大小,讓它填
滿分配給它的整個空間。

GridBagConstraints.HORIZONTAL

  調整組件的大小,把水平方向的空間填滿。

GridBagConstraints.VERTICAL

  調整組件的大小,把垂直方向的空間填滿,讓水平
方向的空間空着吧。


2.gbc.gridwidth=1;和 gbc.gridheight=1;

這兩句話像是一對孿生兄弟,應該同時給以同樣的重視
。它們一個負責組件的水平寬度(gridwidth),一個負責組件的垂直高度
(gridheight )。由此我們可以知道,組件的大小是可以變化的。

組件的形狀是不能改變的,永遠是矩形的。


  好了,這兩條語句的意義很簡單,就講到這里吧。

  喂!等一等,我看到下面有一條語句是:

    gbc.gridwidth= GridBagConstraints.REMAINDER;


這是什么意思?

怎么gridwidth的值不是一個數,而是“ GridBagConstraints.REMAINDER
”?

原來,這是Java精心為大家設計的一個特別有用的變
量,使用它就可以通知外觀管理器讓組件占據本行的所有剩余空間,而不必
去計算寬度值是多少,很自動化。

3.gbc.insets=newInsets(5,6,7,8);

這條語句里面提到了兩個拼寫幾乎完全相同的詞:insets
和 Insets,雖然只相差一個字母:一個是大寫I,一個是小寫i,但是它
們代表的意義可大不相同。

Insets是AWT里面一個類的名字,代表着類Insets,它的用途是用來定義組件容器周圍的空間大小,其中帶有四個參數:

Insets(第一個參數,第二個參數,第三個參數,第
四個參數 )

第一個參數代表距上面有幾個點的空白,第二個參數代
表距左邊有幾個點的空白,第三個參數代表距下邊有幾個點的空白區域,第
四個參數代表距右邊留幾個點的空白區域。

  形象一點的表示如圖 14.9:

JAVA布局模式:GridBagConstraints終極技巧



圖14.9參數的設定順序

insets是類GridBagConstraints的一個限定條件。

insets和Insets既然起的名字相同,兩者之間也一
定有相同之處,它們的相似之處就在於它們的用法和用途。insets用來設置
一個組件和其他的組件之間的距離的。所以在上面程序里的按鈕和其他的按
鈕不同,它和其他的按鈕之間都有一定的距離,而不是和其他的按鈕挨在一
起。

總之,使用外觀管理器給我們帶來了許多的方便之處,
使得我們可以輕輕松松地完成各種窗口的外觀處理工作。

使用外觀管理器除了使得程序設計變得方便以外,還
使得程序變得容易在各種不同的窗口環境下運行,從而協助實現了Java的多
平台之夢。

    小結:

學會使用各種各樣的外觀管理器會帶來事半功倍的編
程效果。

這一章里新學習的類有:

BorderLayout,CardLayout,FlowLayout,GridLayot 
,ridBagLayout,GridBagConstraints和Insets。

類GridBagLayout生成的外觀管理器是最具有靈活性
的外觀管理器。

類GridBagLayout需要通過類GridBagconstraints
來實現對程序窗口外觀的管理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM