本章目標: 在第9章中,我們學習了許多用來構建GUI程序的部件,不過到現在爲止,我們還無法讓其“聽話”的按照我們的意圖擺放這些部件。在本章中,我們要學習如何進行部件的佈局,也就是讓部件能夠“聽話”地擺放在我們想放的位置上。我們將學會通過邊框、網格、組合和GridBagLayout四種方式進行部件的佈局管理。
10.1 邊框佈局 傳授新知
我們回顧一下在第9章中,我們在程序中總是使用以下兩條語句定義了一個容器: JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new FlowLayout()); 憑着我們現在所積累的閱讀程序的功夫,應該能夠很快地知道我們通過第一條語句創建了一個容器JPanel類的panel1。 而接下來,我們則調用了panel1.setLayout(new FlowLayout()),在上一章中,我們一直沒有對它進行相應的分析。現在該是揭開它的面紗的時候了。 單詞layout的中文意思是“佈局”、“佈置”,setLayout就是設置佈局格式。也就是說,容器panel1的方法setLayout是用來設置佈局格式的。那麼,我們一直用的是什麼模式呢?對,就是後面括號裏的FlowLayout()。顧名思義,也就是流佈局方式。這是一種順其自然的方式:從左到右,一個個對象地擺放,擺不下,就擺到下一行。所以,我們就無法去控制它。 從本章開始,我們就要學習一種控制佈局的方法。在Java語言中,提供了各種佈局管理器,以便大家能夠達到這一目的。 通常我們最常使用的佈局管理器是:Border Layout(邊框佈局管理器),如下圖所示,邊框佈局管理器將一個屏幕分成了五個部分:東、南、西、北、中。
圖10-1 邊框佈局管理示意圖
如果要使用這種邊框佈局管理進行佈局控制,我們必須先將“容器”設置爲“邊框佈局控制模式”,具體來說,就是當調用setLayout方法爲容器設置佈局控制模式時,參數設置爲BorderLayout。例如: JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new BorderLayout()); 然後,我們就可以在使用容器的add方法添加部件時,附加上位置參數,使得該部件顯示在指定的位置上。位置參數分別是: BorderLayout.NORTH 位置爲北 BorderLayout.SOUTH 位置爲南 BorderLayout.EAST 位置爲東 BorderLayout.WEST 位置爲西 BorderLayout.NORTH 位置爲中心
實例說明
下面,我們就來試一試,使用按鈕排出五個方向!請創建一個testBorder.java,輸入以下源程序: 源程序:useTextArea.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testBorder extends JApplet { public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new BorderLayout()); JButton north=new JButton("North"); JButton south=new JButton("South"); JButton east=new JButton("East"); JButton west=new JButton("West"); JButton center=new JButton("Center");
panel1.add(north,BorderLayout.NORTH); panel1.add(south,BorderLayout.SOUTH); panel1.add(east,BorderLayout.EAST); panel1.add(west,BorderLayout.WEST); panel1.add(center,BorderLayout.CENTER); } }
然後,我們使用javac編譯這個程序,然後編輯一個顯示這個Java Applet的HTML頁面。最後調用appletviewer來觀察這個頁面,如下圖所示:
圖10-2 程序testBorder.java的輸出(1)
圖10-3 程序testBorder.java的輸入(2)
爲了試一下,如果並沒有在每個位置都安排一個部件,那麼會怎麼樣呢?我們修改一下程序,將panel1.add(west,BorderLayout.WEST);這一行註釋掉(就是在前面加上“//”號),也就是不顯示西邊的按鈕,看一下結果如何。正如上圖(圖10-3)所示,西邊由於沒有部件,因此“中”就朝西靠,“佔領”了它的位置。 而同樣的,如果沒有了南邊北邊,正如下圖(10-4)所示,其它部件就會佔領其位置:
圖10-4 程序testBorder.java的輸出(3)
圖10-5 程序testBorder.java的輸入(4)
而如果我們修改一下程序,讓中間的按鈕不顯示的話,就會出現如圖10-5的樣子,中間的區域並未並佔領,而是空在那裏了!這是與其它位置不同的地方,大家一定要記住。
一些提示: 其實這很好理解,如果中間的那一塊的位置被其它位置上的部件佔領的話,就會使得分不清“東”、“南”、“西”、“北”了。倒成了“左上角”、“左下角”、“右上角”、“右下角”了。
自測練習 1) 使用____________位置參數,能夠使一個部件位於容器的頂部。 a. Layout.TOP b. BorderLayout.TOP c. Layout.NORTH d. BorderLayout.NORTH 2) 使用____________位置參數,能夠使一個部件位於容器的右邊。 a. BorderLayout.WEST b. BorderLayout.RIGHT c. BorderLayout.EAST d. BorderLayout.NORTH 3) 如果在東面沒有放置部件,其它位置都有放置部件,那麼中間的部件將靠向______。 a.左邊 b.上面 c.右邊 d.下面 4) 在第9章中,我們使用的佈局管理器是_____________。 a.雜亂管理器 b.流管理器 c.沒有使用佈局管理器 d.順序佈局管理器 5) 邊框佈局管理器將一個“容器”分成了__________個位置。 a.9個 b.3個 c.4個 d.5個 6) 編寫一個程序,使其界面如下圖:
圖10-6 練習題圖(1)
而且,當我們擴大這個窗體的寬度時,OK按鈕並不會出現在文本框之後,而是產生如下圖之輸出結果:
圖10-7 練習題圖(2)
練習答案
1)d 在邊框佈局管理器中,頂部是北,所以選擇BorderLayout.NORTH。 2)c 在邊框佈局管理器中,右邊是東,所以選擇BorderLayout.EAST。 3)c 東在右邊,所以東邊沒有部件,其它部件就擠向右邊,佔領了右邊。 4)b 雖然a、d從字面意義上特別象我們得到的結果,而c則從感覺上比較象,但這些都不是正確答案。這種佈局管理器稱爲流管理器。 5)d 當然是“東”、“西”、“南”、“北”、“中”5個部分了! 6) 以下是一個程序實例:
源程序:lianxi10_1.java
import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_1 extends JApplet { Label comment; JTextField username; JButton buttonOK;
public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new BorderLayout()); comment=new Label("Please enter you name:"); username=new JTextField(); buttonOK=new JButton("OK");
panel1.add(comment,BorderLayout.NORTH); panel1.add(username,BorderLayout.CENTER); panel1.add(buttonOK,BorderLayout.SOUTH); }
}
10.2 網格佈局 實例說明 下面,我們來看一個新的程序!首先創建一個testGrid.java文件,並輸入以下源程序: 源程序:testGrid.java
import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testGrid extends JApplet { String buttonLabels[]={"No.1","No.2","No.3","No.4","No.5", "No.6","No.7","No.8","No.9"};
public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(3,3)); for (int x=0; x<buttonLabels.length;x++) panel1.add(new JButton(buttonLabels[x])); } }
然後,我們使用javac編譯這個程序,然後編輯一個顯示這個Java Applet的HTML頁面。最後調用appletviewer來觀察這個頁面,如下圖所示:
圖10-8 程序testGrid.java的輸出
傳授新知
由於在本章中,我們主要是關心如何擺放各個部件,而不是如何構建一個程序。所以,正如本例中的按鈕一下,這一章中的所有部件都是一個樣子,沒有任何作用。這樣也使得程序儘可能地變短了,更易於大家閱讀和理解程序。 下面,我們就一起來看一下上面的這個程序。 1) String buttonLabels[]={"No.1","No.2","No.3","No.4","No.5", "No.6","No.7","No.8","No.9"} 我想大家都能很輕鬆地讀懂這條語句,我們在此定義了一個字符串數組buttonLabels,它有9個字符串成員,也就是我們後面定義的9個按鈕的標籤文本。 值得注意的是,大家一定要知道,buttonLabels[1]表示哪個字符串!如果您的答案是“No.1”的話,就錯了!正確的答案是“No.2”,這是因爲在數組中索引值是從0開始的,也就是說如果要使用“No.1”的話,應該使用buttonLabels[0]。這對更好地理解後面的程序十分重要,也是基本功之一。 2) JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(3,3)); 在這兩行程序中,我們首先定義了一個容器部件panel1。然後調用setLayout方法設置佈局管理器。這裏我們使用了一個新的佈局管理器:GridLayout,網格佈局管理器。 我們注意到GridLayout的後面帶了兩個參數:3,3。這有什麼用呢?我們一起來看一下GridLayout方法的定義: public GridLayout (int rows,int cols) 我們看一下這兩個參數,首先它們都是int型—整型的。那麼它們分別起到什麼作用呢?我們還是採用顧名思義法吧!row的中文意思是行,col的中文意思是列,後面加上一個s,是這兩個單詞的複數形式。 好,我們現在串起來想一下,我們定義了一個網格佈局,然後定了它的行、列數!這不就畫出了這個網格了嗎?如果我們在語句是使用GridLayout(5,5)的話,就會把整個容器分成25個單元,如下圖所示:
圖10-9 GridLayout(5,5)
圖10-10 GridLayout(3,3)
而我們在程序中使用的是GridLayout(3,3),所以它就將整個容器分成了如上圖所示的9個部分(圖10-10)。
注意: 這種劃分是一種邏輯上的,暗藏式的劃分,而不會把格子給劃出來。另外,我們這裏舉的兩個例子行、列都相等,其實完全可以不等。
3) for (int x=0; x<buttonLabels.length;x++) panel1.add(new JButton(buttonLabels[x])); 這是一個循環結構的程序。我們先看循環語句,循環的初值是“x=0”,繼續執行循環的條件語句是“x<buttonLabels.length”,每做一次循環,執行“x++”。 buttonLabels.length就是用來請得字符串數組buttonLabels的長度!也就是這個字符串數組中有多少個字符串?我們知道,我們在該數組中定義了9個。 從程序中,我們可以獲知,當x=buttonLabels.length時,循環就將結束,應爲它不滿足條件x<buttonLabels.length。那不是少了一個嘛! 別忘了,我們使用buttonLabels[0]表示第一個字符串,buttonLabels[1]表示第二個字符串……,那麼最後一個字符串就應該是buttonLabels[buttonLabels.length-1]嘛。 在循環中,我們使用容器提供的add方法,將新定義的按鈕部件添加進去。 有時,我們可能想獲得象下圖所示的佈局效果!讓各個部件之間存在一些間隙。使用Java的網格佈局可以實現嗎?
圖10-11 有間隙的網格佈局
我很高興地回答你:“可以!”,我們可以使用GridLayout的另一種構造器方法(簽名不同)來實現: public GridLayout (int rows,int cols,int hgap,int vgap) 在這個方法中,可以帶上四個整型參數,前兩個我們已經很熟悉了,行數與列數。後面則是兩個新的參數。 第一個是hgap,其中gap的意思是間隙、空隙的意思,而h則是horizontal(水平)的第一個字母。也就是說,我們可以通過hgap參數設置橫向的間隙。 第二個是vgap,v則是vertical(垂直)的第一個字母。也就是說,我們可以通過vgap參數設置縱向的間隙。
自測練習
1)_________________是網格佈局管理器。 a.BorderLayout b.GridLayout c.ReseauLayout d.FlowLayout 利用以下代碼回答問題2、3、4、5: 2)這個佈局中有__________行? a.7行 b.5行 c.6行 d.8行 3)這個佈局中有__________列? a.7行 b.5行 c.6行 d.8行 4)這個佈局將容器分爲_________個部分? a.48個 b.35個 c.30個 d.40個 5)第5個部件位於__________位置。 a.左上角 b.左下角 c.右上角 d.右下角 e.中間 6)根據以下界面,編寫一個程序
圖10-12 練習題圖 ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ 7) 如果我們構建一個5*5的網格佈局,但只在該容器中加入17個按鈕,將會出現什麼情況?請編寫一個程序,來試一試效果。 ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________
練習答案
1)b 沒什麼好解釋的,請大家記住! 2)a 第一個參數是行數,因此是7行。 3)b 第二個參數是列數,因此爲5列。 4)b 7行5列,其7*5,35個部分嘛。 5)c 第5個部件是第一行的最後一個,當然在右上角嘛。 6)下面是一個實現的程序實例: 源程序:lianxi10_2.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_2 extends JApplet { String buttonLabels[]={"1","2","3","4","5","6","7", "8","9","*","0","#"};
public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(4,3,10,10)); for (int x=0; x<buttonLabels.length;x++) panel1.add(new JButton(buttonLabels[x])); } }
7)下面是一個實現的程序實例: 源程序:lianxi10_3.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_3 extends JApplet { String buttonLabels[]={"No.1","No.2","No.3","No.4","No.5", "No.6","No.7","No.8","No.9","No.10","No.11","No.12", "No.13","No.14","No.15","No.16","No.17"};
public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(5,5)); for (int x=0; x<buttonLabels.length;x++) panel1.add(new JButton(buttonLabels[x])); } } 這個程序使用javac編譯完後,編寫一個包含這個類的HTML頁面,再用appletviewer來觀察發現運行結果如下圖所示:
圖10-13 練習答案圖
這個輸出是不是令你感到十分意外,整個程序根本不按要求分成5列,所以我們從這裏得到一個使用網格佈局中要十二分注意的一點:“請別忘了將網格填滿”。否則程序的輸出將不可預料。
一些提示: 如果你真的沒有那麼多東西來“佔領”網格的話,我建議你使用一個空標籤來填補這個空白的網格,使得程序的輸出如你所願。使用空標籤的方法很容易: panel1.add(new Label(“”)); 從這裏,我們也看出了,我們學習過的流佈局管理器、邊框佈局管理器,以及我們剛學習過的網格佈局管理器都比較死板,不夠高級。
10.3 組合佈局 傳授新知
正如我們在上一小節結束的時候說的一樣,各種佈局管理器都有自己的缺點,沒有一種能夠真正地完全滿足我們編寫GUI程序時的要求。 而在Java語言中,允許在容器中加入其他容器,這樣每個容器可以根據自己的需要採用不同的佈局管理器,組合成爲一個我們所需要的GUI程序界面。這種方法,我們就稱之爲組合佈局。
注意: 與流佈局、邊框佈局、網格佈局不同,組合佈局並不是一個新的佈局管理器,它是通過結合各種佈局管理器的優點,將它們組合地應用在GUI程序界面的開發中。這是一種佈局管理的方法。也可以說是一種GUI程序界面的開發技巧。 當我們設計GUI程序界面時,最好先在紙上把它畫出來,然後“分塊解決”。也就是將能夠組合在一起的部件找出來,將它們放在一個容器裏,併爲它們選擇合適的佈局管理器。然後把這些容器擺放在一起,就解決了。 設計時還要考慮到窗體大小發生改變的時候,引起的部件形體變化。這方面,請你熟記幾個設計技巧: 1) 對於那些要求扁平狀的部件,我們應該將它放置在邊框佈局中的南面或北面; 2) 對於那些要求細高狀的部件,我們應該將它放置在邊框佈局中的東面或西面; 3) 對於那些可以隨着窗體改變大小部分,我們可以將它放置在邊框佈局的中間; 4) 如果我們要求部件保持大小相同,那麼,我們就應該採用網格佈局。 下面,我們就通過幾個實際的例子,來讓大家領會和掌握這種設計的思路與方法。
實例說明 我們首先創建一個testCombination.java文件,然後輸入以下源程序: 源程序:testCombination.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testCombination1 extends JApplet { public void init() { Frame frame1=new Frame("testCombination1"); frame1.setLayout(new BorderLayout()); TextArea text1=new TextArea(); frame1.add(text1,BorderLayout.CENTER); JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(1,3,10,5)); panel1.add(new JButton("A")); panel1.add(new JButton("B")); panel1.add(new JButton("C")); frame1.add(panel1,BorderLayout.SOUTH); frame1.pack(); frame1.show(); } }
然後,我們使用javac編譯這個程序,然後編輯一個顯示這個Java Applet的HTML頁面。最後調用appletviewer來觀察這個頁面,如下圖所示:
圖10-14 程序testCombination.java的輸出
正如上圖所示,程序的輸出與以前不同,各個部件不是顯示在Appletviewer程序框中,而是顯示在另一個窗口中。 這是怎麼回事呢?下面我們就一起來看一下這個程序!
傳授新知
在以前的程序中,我們一直都是使用容器JPanel,面板。而我們在這個程序中引進了一個新的容器Frame。使用了這個容器後,就會新創建一個窗口。這也就是爲什麼程序的輸出有這麼大的變化的原因。 1) Frame frame1=new Frame("testCombination"); 這條語句,定義了一個Frame容器frame1,然後使用new操作符調用構造器方法,後面帶的參數“testCombination”則是這個Frame的標題。
一些提示: 其實大家能Frame所體現出來的效果是很熟悉的,它等價於Windows中的窗體。而Frame的標題就是窗體的標題。
2) frame1.setLayout(new BorderLayout()); 與JPanel容器一樣,我們可以調用setLayout方法來設置Frame的佈局管理器。在這裏,我們將Frame容器frame1的佈局管理器設置成爲邊框佈局管理器(也就是我們在10.1小節中學習過的佈局管理器)。 3) frame1.add(text1,BorderLayout.CENTER); 緊接着,我們調用frame1的add方法,將文本區部件text1添加到frame1容器中來。注意我們設置了它的位置:BorderLayout.CENTER。 這是因爲,我們希望這個文本區能夠隨着窗體的大小變化而變化。所以適合將其放在在中間位置。 4) panel1.setLayout(new GridLayout(1,3,10,5)); 我們又定義了一個JPanel容器panel1,並將其的佈局管理器設置爲網格佈局管理器。並通過指定參數,使得整個panel1被分成1行3列,水平空隙爲10的網格。 5) frame1.add(panel1,BorderLayout.SOUTH); 這是組合佈局方法最重要的一步,我們將panel1這個容器,加入到了frame1這個容器中去了。並且指定了panel1這個容器在整個frame1中所佔的位置:BorderLayout.SOUTH,也就是下邊。這樣,panel1中包含的三個按鈕就會永遠(不管窗體大小如何改變)呆在文本區的下邊,而且三個按鈕的大小會根據窗體大小的改變而改變。
一些提示: 這是因爲,panel1中的按鈕是用網格佈局的。 6) frame1.pack(); frame1.show(); 與JPanel不一樣,使用Frame容器,不能夠直接顯示了出來。我們必須調用Frame容器的show方法才能使得Frame顯示出來。 而在使用show方法之前,我們還需要使用pack方法將Frame中的內容做一個整合。請記住這裏的使用方法。
自測練習
1)___________不屬於佈局管理器。 a.邊框佈局 b.組合佈局 c.流佈局 d.網格佈局 2)如果要使用組合佈局,需將容器的佈局管理設置爲__________。 a.BorderLayout() b.GridLayout() c.CombinationLayout() d.以上都不對 請說明理由: ____________________________________________________________________ 3)對於同一個容器,可以使用多種佈局管理方式?________ a.對 b.不對 4)對於同一種容器,可以使用多種佈局管理方式?________ a.對 b.不對 5) 將一個容器panel1放到容器frame1中的方法是___________。 a.frame1.insert(panel1) b.frame1.add(panel1) c.frame1.addJPanel(panel1) d.frame1.insertJPanel(panel1) 6) 編寫一個程序,模擬如下圖所示的小鍵盤:
圖10-15 練習題圖 ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________
練習答案
1)b 組合佈局是一種將多種佈局管理器應用在一個程序中的方法,它不屬於佈局管理器。 2)d 組合佈局是一種方法,所以無須指定佈局管理器,想指定也無法指定。 3)b 在一個程序中,一個容器只能有一種佈局管理。 4)a 對於同一種容器在不同的程序中,當然可以採用不同的佈局管理。 5)b 與在Frame上添加一個部件一樣,使用Frame的add方法就可以了。 6) 以下是一個程序實現的實例: 源程序:lianxi10_4.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_4 extends JApplet { public void init() { Frame framePad=new Frame("NumberPad"); framePad.setLayout(new BorderLayout()); JPanel panelTop=new JPanel(); panelTop.setLayout(new GridLayout(1,4,5,10)); panelTop.add(new JButton("Lock")); panelTop.add(new JButton("/")); panelTop.add(new JButton("*")); panelTop.add(new JButton("-")); framePad.add(panelTop,BorderLayout.NORTH);
JPanel panelMid=new JPanel(); panelMid.setLayout(new GridLayout(3,3,10,5)); for(int x=1;x<=9;x++) panelMid.add(new JButton(String.valueOf(x))); JPanel panelBot=new JPanel(); panelBot.setLayout(new BorderLayout()); panelBot.add(new JButton("0"),BorderLayout.CENTER); panelBot.add(new JButton("."),BorderLayout.EAST); JPanel panelNum=new JPanel(); panelNum.setLayout(new BorderLayout()); panelNum.add(panelMid,BorderLayout.CENTER); panelNum.add(panelBot,BorderLayout.SOUTH); framePad.add(panelNum,BorderLayout.CENTER);
JPanel panelRight=new JPanel(); panelRight.setLayout(new GridLayout(2,1,10,5)); panelRight.add(new JButton("+")); panelRight.add(new JButton(" ")); framePad.add(panelRight,BorderLayout.EAST); framePad.pack(); framePad.show(); } }
10.4 GridBag佈局 實例說明 到現在爲止,我們已經學習了邊框佈局、網格佈局以及組合佈局,現在大家試一試編寫一個程序,使其顯示如下圖所示的界面:
圖10-16 挑戰(1)
怎麼樣,挺有難度的吧!完成這個GUI得花很多心思去設計組合,十分討厭,下面我們就使用一個新的佈局管理器GridBagLayout來解決這種難題。 首先,輸入以下源程序: 源程序:testGridBag.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testGridBag extends JApplet { public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridBagLayout()); GridBagConstraints gbdc=new GridBagConstraints(); gbdc.fill=GridBagConstraints.BOTH; gbdc.weightx=1; gbdc.weighty=1; panel1.add(new JButton("No.1"),gbdc); panel1.add(new JButton("No.2"),gbdc); panel1.add(new JButton("No.3"),gbdc); gbdc.gridwidth=2; gbdc.gridx=0; panel1.add(new JButton("No.4"),gbdc); gbdc.gridx=2; gbdc.gridwidth=1; gbdc.gridheight=2; panel1.add(new JButton("No.5"),gbdc); gbdc.gridx=0; gbdc.gridheight=1; panel1.add(new JButton("No.6"),gbdc); gbdc.gridx=1; panel1.add(new JButton("No.7"),gbdc);
gbdc.gridx=0; gbdc.gridwidth=2; panel1.add(new JButton("No.8"),gbdc); gbdc.gridx=2; gbdc.gridwidth=1; panel1.add(new JButton("No.9"),gbdc); } }
傳授新知
在這個程序中,我們使用了GridBagLayout輕鬆地完成了這個界面的設計,允分凸現出它的強大。可以這麼說,GridBagLayout是Java語言中最強大的佈局管理器。 GridBagLayout,從名字上看,就知道它與GridLayout有一定的淵源,是的,GridBagLayout的確與其十分類似,也是使用網格來進行佈局管理的。但與GridLayout(網格佈局)不同的是,GridBagLayout不像網格佈局一相,需要所有的部件的大小、形狀相同。而且還可以將某一個部件放在一個固定的位置上。 下面,我們一起來分析一下testGridBag.java程序。 1) panel1.setLayout(new GridBagLayout()); 在調用setLayout方法時,指定爲GridBagLaoyout,使panel1使用GridBag佈局管理。 2) GridBagConstraints gbdc=new GridBagConstraints(); GridBagLayout佈局管理器是通過一個GridBagConstraints類來實現神奇的效果的。所以,我們要在使用時先定義一個GridBagConstraints類的對象。在這個程序中,我們定義了一個GridBagConstraints類的對象gbdc。 3) gbdc.fill=GridBagConstraints.BOTH; 由於網格單元可能比該單元中的部件大,如果是這樣,部件放置在單元格內會有一些多餘空間。在默認情況下,部件不會擴張,也就是不會填充這個多餘空間。 GridBagConstraints提供了一個fill屬性,我們可以通過設置它的值來起到不同的效果。 ¨ GridBagConstraints.NONE:不擴張,是默認值; ¨ GridBagConstraints.HORIZONTAL:部件水平擴張,將水平方向的多餘空間填滿; ¨ GridBagConstraints.VERTICAL:部件垂直擴張,將垂直方向的多餘空間填滿; ¨ GridBagConstraints.BOTH:部件同時向兩個方向擴張,將單元格填滿。 4) gbdc.weightx=1; gbdc.weighty=1; weightx和weighty是GridBagConstraints提供的另一對屬性。它的取值是整型數,默認值爲0。用來設置行(weightx)、列(weighty)的“重量”,如果值爲0的話,所有的部件都會緊收在一起,聚集在中央,如圖10-17所示。 而如果取值爲其它數字,則會根據值來分配空間。 5) panel1.add(new JButton("No.1"),gbdc); panel1.add(new JButton("No.2"),gbdc); panel1.add(new JButton("No.3"),gbdc); 在沒有任何約束的時候,向gbdc中添加按鈕,這時效果與採用網格佈局的效果完全一樣。一個接着一個地“佔領”單元格。
圖10-17 當weightx與weighty爲0時的效果圖
6) gbdc.gridwidth=2; gbdc.gridx=0; panel1.add(new JButton("No.4"),gbdc); 由於第四個按鈕(No.4)是寬度是2,在GridBagLayout中,是由gridwidth屬性來控制添加進入的部件的寬度的。 我們通過gbdc.gridwidth=2將其設置爲2,這樣,再添加進入的部件就會變成爲2個單元格的寬度。 另外,我們再使用gbdc.gridx=0讓其另起一行,從最左邊的單元格開始填充。 因此,我們發現第四個按鈕被加在了第二行,寬度爲2個單元格。
7) gbdc.gridx=2; gbdc.gridwidth=1; gbdc.gridheight=2; panel1.add(new JButton("No.5"),gbdc); 接下來,我們要擺放第五個按鈕,這個按鈕將從第3個單元開始填充,其寬度爲一個單元格,而高度則爲兩個單元格。 因此,我們首先使用用gbdc.gridx=2,使得下一個添加的部件(第五個按鈕)放入第3個單元格(0代表第1個單元格,因此第3個單元格應該是2)。 由於,前面我們已經將gridwidth設置爲2了,因此,我們需要使用gbdc.gridwidth=1,將其值設置回1。 最後使用gdbc.gridheight=2,使得添入的部件的單元格縱向跨越兩個單元格。
8) gbdc.gridx=0; gbdc.gridheight=1; panel1.add(new JButton("No.6"),gbdc); 我想這一段程序,大家應該都不會再有什麼理解上的問題了吧!主要提醒大家注意的是,我們使用gbdc.gridheight=1將單元格縱向跨度改成了默認值1。這是因爲我們在前面需要時將其改成了2,所以在此需要將其改回來。
實例說明 爲了更好地理解這個強大的GridBagLayout佈局管理器,我們再來做一個有趣的實驗。首先,我們創建一個testGridBag2.java 源程序:testGridBag2.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testGridBag2 extends JApplet { public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridBagLayout()); GridBagConstraints gbdc=new GridBagConstraints(); panel1.add(new JButton("No.1"),gbdc); panel1.add(new JButton("No.2"),gbdc); setSize(300,200); } } 運行這個程序,我們將得到以下結果:
圖10-18 實驗結果(1)
然後我們使用鼠標改變一下窗口的大小,看一下,這兩個按鈕有什麼變化?你會驚奇地發現,窗口改變了大小,兩個按鈕的大小卻沒有變,而且一直呆在正中央的位置。
一些說明: 在這個程序中,我們使用了一個以前沒有用過的語句:setsize(300.200),它的功能是在程序中設置窗口的大小。
現在我們對這個程序做一些修改!將添加兩個按鈕的兩條語句: panel1.add(new JButton("No.1"),gbdc); panel1.add(new JButton("No.2"),gbdc); 將它們擴展爲: gbdc.weightx=1; panel1.add(new JButton("No.1"),gbdc); gbdc.weightx=3; panel1.add(new JButton("No.2"),gbdc); 再重新編譯、運行這個程序,你想會發生什麼變化呢?我們一起來看一下結果:
圖10-19 實驗結果(2) 爲什麼會得到這個效果呢?我們在程序中添加按鈕的程序段前加入一句: gbdc.fill=GridBagConstraints.HORIZONTAL; 再重新編譯一下程序,再看看程序的輸出有什麼變化! 在得到結果之前,自己可以想象一下結果,然後看一下程序的實際輸出與你的想法是否相吻合。 我們驚奇地發現,第二個按鈕,突然變得十分寬起來(如圖10-20所示)。這是因爲放置第二個按鈕的單元格的寬度是3,而第一個按鈕的寬度是1。而且,我們又讓第二個按鈕橫向擴展,因此得到了這樣的輸出結果。
圖10-20 程序實驗結果(3)
相信實驗做到這裏,不須我說,大家也會有一些心得體會了。但是GridBagLayout遠不止這一點,大家應該多做試驗,才能夠在真實的使用環境中有效地掌握GridBagLayout。
自測練習
1) 如果不設置,GridBagConstraints的fill屬性的值是_________。 a.GridBagConstraints.VERTICAL b.GridBagConstraints. HORIZONTAL c.GridBagConstraints.BOTH d.GridBagConstraints.NONE 2) GridBagConstraints的weightx和weighty的值是_______和_______。 a. 1 0 b.0 0 c.0 1 d.1 1 3) 如果在程序中,我們將gridx設置爲0,則______________。 a.新的部件從新的一行開始添加 b.新的部件將覆蓋掉第一個部件 4) 編寫一個程序,使用GridBagLayout佈局管理器實現對小鍵盤的模擬。程序的輸出如下圖所示:
圖10-21 練習題圖 ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________
練習答案
1)d GridBagConstraints屬性fill的默認值是GridBagConstraints.NONE。 2)b 這兩個值的默認值均是0。 3)a 當然不會覆蓋已經存在的部件了。 4)以下是一個程序實例: 源程序:lianxi10_5.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_5 extends JApplet { public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridBagLayout()); GridBagConstraints gbdc=new GridBagConstraints(); gbdc.fill=GridBagConstraints.BOTH; gbdc.weightx=1; gbdc.weighty=1; panel1.add(new JButton(" "),gbdc); panel1.add(new JButton("/"),gbdc); panel1.add(new JButton("*"),gbdc); panel1.add(new JButton("-"),gbdc);
gbdc.gridx=0; panel1.add(new JButton("7"),gbdc); gbdc.gridx=1; panel1.add(new JButton("8"),gbdc); gbdc.gridx=2; panel1.add(new JButton("9"),gbdc); gbdc.gridheight=2; gbdc.gridx=3; panel1.add(ne |