理解SWT佈局[1]


相關鏈接:
http://www.csdn.net/develop/article/28/28479.shtm
http://www.chinaitpower.com/A200507/2005-07-24/165936.html

摘要 
     當你用SWT編寫應用程序的時候,你可能需要用佈局(layout)來給你的窗口 設置特特定的外觀。佈局控制組合窗口組件(composite)中的子組件的位置和大小。佈局類都是抽象類Layout的子類。這篇文章爲你展示瞭如何使 用標準佈局,以及如何編寫定製你自己的佈局。
 
作者:Carolyn MacLeod, OTI
    2001年3月22日
 
修訂:Shantha Ramachandran, OTI
    2002年5月2日 
 
翻譯:Link
    2006年5月
 
--------------------------------------------------------------------------------
佈局 
概述
    當你用標準小窗口工具箱(SWT)編寫應用程序的時候,你可能需要用佈局來爲你的窗口定製特定的外觀。佈局控制組合窗口組件(composite)中的子 組件的位置和大小。 佈局類都是抽象類Layout的子類。SWT提供了很多標準的佈局類,你可以編寫定製的佈局類。
 
    在SWT中,定位和尺寸縮放不能自動地發生。應用程序可以初始化地確定一個Composite的子組件的大小和位置,或者可以通過一個調整大小的監聽器來 實現。另一個選擇是指定一個佈局類來定位和縮放這些子組件。如果子組件沒有給定的尺寸大小,它們將會具有零尺寸(zero size)並且是不可見的。
 
   下面的圖中顯示了一些討論佈局時通常使用的術語。Composite(在這個例子中,是一個TabFolder)有一個location,一個clientArea和一個trim。Composite的大小是clientArea的大小加上trim的大小。這個Composite有兩個並排佈置的子組件。佈局(Layout)管理子組件的大小和位置。這個佈局允許子組件之間的spacing,以及子組件和佈局邊緣之間的margin。佈局的大小和Composite的clientArea的大小一樣。 
        
    小窗口部件(widget)的首選大小是顯示它的內容所需要的最小的大小。在這個composite的例子中,首選大小是包含所有它的子組件的最小的矩 形。如果子組件已經被應用程序定位,composite會基於這些子組件的大小和位置計算它自己的首選大小。如果composite用佈局類來定位它的子 組件,它要求佈局來計算clientArea的大小,然後加上trim來決定它的首選大小。
 
標準佈局 
   在SWT庫中的標準佈局類是:
 
  · FillLayout – 在單行或者單列中放置相同大小的小窗口部件。
  · RowLayout – 在一行或者多行中放置小窗口部件,應用了fill,wrap和spacing等選項。
  · GridLayout – 在網格中放置小窗口部件。
  · FormLayout  * 2.0新特性*通過定義四邊的“粘貼”位置來放置小窗口部件。
 
  爲了使用這些標準佈局,你必須導入SWT的佈局包:
 
   import org.eclipse.swt.layout.*;
 
  佈局是可插件化的。爲了設置composite小窗口部件的佈局,你可以使用composite小窗口部件的setLayout(Layout)方法。在接下來的代碼中,一個Shell(Composite的子類)用RowLayout來定位它的子組件:
  
   Shell shell = new Shell(); 
   shell.setLayout(new RowLayout());
 
   一個佈局類可能有一個對應的佈局數據(layout data)類 – 包括了定製子組件的佈局數據的Object的子類。習慣上,佈局數據類通過取代佈局類類名中的Layout爲Data爲標識。例如:標準佈局類 RowLayout具有佈局數據類RowData。佈局類GridLayout使用佈局數據類GridData,而佈局類FormLayout具有名稱爲 FormData的佈局數據類。一個窗口小部件的佈局數據類的設置如下: 
 
   Button button = new Button(shell, SWT.PUSH);
   button.setLayoutData(new RowData(50, 40));
 
這個文檔中的例子
  這個文檔中絕大多數的快照是通過運行下面的示例代碼的變更版本來得到的。我們將會改變佈局的種類,使用的選項,或者是子組件的數目。
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
 
public class LayoutExample {
 
      public static void main(String[] args) {
            Display display = new Display();
            Shell shell = new Shell(display);
            // Create the layout.
            RowLayout layout = new RowLayout();
            // Optionally set layout fields.
            layout.wrap = true;
            // Set the layout into the composite.
            shell.setLayout(layout);
            // Create the children of the composite.
            new Button(shell, SWT.PUSH).setText("B1");
            new Button(shell, SWT.PUSH).setText("Wide Button 2");
            new Button(shell, SWT.PUSH).setText("Button 3");
            shell.pack();
            shell.open();
            while (!shell.isDisposed()) {
                  if (!display.readAndDispatch()) display.sleep();
            }
      }
}
    運行以上代碼得到如下的結果:
 
      
 
    如果用戶調整了shell的大小使得右邊的Button 3沒有足夠的空間,RowLayout將Button 3換行放置到下一行,如下所示:
 
    
 
    我們將會看到,使用佈局和調整大小有緊密的關係。因此,這個文檔中大多數的例子展示了當Composite變大或者變小時將會發生什麼,以舉例說明佈局是如何工作的。
 
FillLayout 
 
    FillLayout是最簡單的佈局類。它在單行或者單列中放置小窗口部件,強制它們爲同一大小。 開始,窗口小部件都和最高的容器小部件一樣高,和最寬的窗口小部件一樣寬。FillLayout不會換行,而且你不能定製空白(margin)和間隔 (spacing)。當Composite只有一個子組件時FillLayout也能被使用。例如,如果一個Shell有一個Group子組件, FillLayout會使Group完全填充這個Shell。
 
   這裏是示例代碼相關的一部分。首先我們創建了一個FillLayout,然後(如果我們需要垂直的樣式)我們設定它的type域爲SWT.VERTICAL,並且把它設定到Composite(一個Shell)中。這個Shell有三個按扭子組件,B1,B2和B3。注意在FillLayout中,子組件總是有相同的大小,而且充滿可用空間。
 
    FillLayout fillLayout = new FillLayout();
    llLayout.type = SWT.VERTICAL;
    shell.setLayout(fillLayout);
    new Button(shell, SWT.PUSH).setText("B1");
    new Button(shell, SWT.PUSH).setText("B2");
    new Button(shell, SWT.PUSH).setText("Button 3");
 
  下面的表格顯示了水平和垂直樣式的FillLayout,初始狀態以及當父組件增大時的不同點

 
初始狀態
縮放後
fillLayout.type = SWT.HORIZONTAL
(默認)
 
fillLayout.type = SWT.VERTICAL
 
RowLayout
    RowLayout比FillLayout的使用更爲普遍,因爲它能夠換行(warp)和提供了可配置的空白(margin)和間隔(spacing)。RowLayout有很多可配置的域。而且,RowLayout中的每個小窗口部件的高度和寬度都可以通過使用setLayoutData設置小窗口部件的RowData對象來指定。
 
RowLayout的可配置域

Type
* 2.0新特性*  
    type域控制RowLayout在水平行中還是在垂直列中放置小窗口部件。默認情況下RowLayout是水平方式的。
 
Wrap
    warp域控制RowLayout當前行中沒有足夠的空間時是否把小窗口部件換行放放置到下一行。默認情況下RowLayout是換行的方式.
 
pack
      如果pack爲true,RowLayout中的小窗口部件會採用它們正常的大小,而且它們會儘可能的左對齊。如果pack爲false,小窗口部件會填充可用的空間,就象FillLayout中的小窗口部件一樣。默認情況下RowLayout的pack爲false。
 
justify
     如果justify域爲true,RowLayout中的小窗口部件從左到右在可用的空間中伸展開。如果父Composite變大,額外的空間均勻的分佈在小窗口部件之中。如果packjustify都爲true,窗口小部件採用它們正常的大小,而且額外的空間被放置在這些小窗口部件之間以保持它們完全的散開(justify)。默認情況下RowLayout不進行散開。
 
MarginLeft, MarginTop, MarginRight, MarginBottom和Spacing
    這些域控制小窗口部件之間的象素數(spacing)以及小窗口部件和父Composite的邊界之間的象素數(margin)。默認情況下RowLayout爲空白(margin)和間隔(spacing)保留3個象素。空白和間隔在下面的圖中展示: 
   
     
   RowLayout的例子
  下面的示例代碼中創建了一個RowLayout,設置它的所有域爲非默認的值,然後把它設定到一個Shell中。
     RowLayout rowLayout = new RowLayout();
      rowLayout.wrap = false;
      rowLayout.pack = false;
      rowLayout.justify = true;
      rowLayout.type = SWT.VERTICAL;
      rowLayout.marginLeft = 5;
      rowLayout.marginTop = 5;
      rowLayout.marginRight = 5;
      rowLayout.marginBottom = 5;
      rowLayout.spacing = 0;
      shell.setLayout(rowLayout);
 
   如果你僅使用默認的域值,你只需要一行代碼:
 
     shell.setLayout(new RowLayout());  
 
  在下面的表格中,展示了設置指定的域的結果:
 

 
初始狀態
縮放後
wrap = true
pack = true
justify = false
type = SWT.HORIZONTAL 
(默認)
 
 
  wrap = false
(沒有足夠的空間則進行修剪)
 
  
 pack = false
(所有的小窗口部件都有相同的大小)
 
 
justify = true
(小窗口部件在可用空間中伸展開來)
 
 
  
 
 type = SWT.VERTICAL
(窗口小部件被垂直地安排在一列中)
 
  
 

RowLayout一起使用RowData對象

      每由RowLaout控制的一個小窗口部件都能通過設置它的RowData對象指定它初始的寬度和高度。以下代碼用RowData對象來改變一個Shell中按鈕(Button)的初始大小。
   
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class RowDataExample  
   public static void main(String[] args) {
       Display display = new Display();
       Shell shell = new Shell(display);
       shell.setLayout(new RowLayout());
       Button button1 = new Button(shell, SWT.PUSH);
       button1.setText("Button 1");
       button1.setLayoutData(new RowData(50, 40));
       Button button2 = new Button(shell, SWT.PUSH);
       button2.setText("Button 2");
       button2.setLayoutData(new RowData(50, 30));
       Button button3 = new Button(shell, SWT.PUSH);
       button3.setText("Button 3");
       button3.setLayoutData(new RowData(50, 20));
       shell.pack();
       shell.open();
       while (!shell.isDisposed()) {
           if (!display.readAndDispatch()) display.sleep();
       }
   }
}
 
  這是你運行這些代碼後看到的結果。 
       
 
GridLayout
    
     GridLayout可能是最有用最強大的標準佈局,但它也是最爲複雜的。在一個GridLayout中,一個Composite的小窗口部件子組件被 放置在網格中。GridLayout有很多可配置的域,而且,和RowLayout一樣,它所放置的小窗口部件可以有一個關聯的佈局數據對象,叫做 GridData。GridLayout的強大在於它具有爲GridLayout所控制的每一個小窗口部件配置GirdData的能力。

 
GridLayout的可配置域
 
NumColumns
  numColumns域是GridLayout中最重要的域,而且它通常也是應用程序會設定的第一個域。小窗口部件被從左到右放置在不同的列中,當有numColumns + 1個小窗口部件被加到Composite中時,一個新的行就會被創建。默認情況下只有1列。接下來的代碼創建了一個有着五個不同寬度的按鈕(Button)的Shell,並用GridLayout來管理。以下的表格顯示了當numColumns被設爲1,2或者3時網格的情況。
 
 Display display = new Display();
 Shell shell = new Shell(display);
 GridLayout gridLayout = new GridLayout();
 gridLayout.numColumns = 3;
 shell.setLayout(gridLayout);
 new Button(shell, SWT.PUSH).setText("B1");
 new Button(shell, SWT.PUSH).setText("Wide Button 2");
 new Button(shell, SWT.PUSH).setText("Button 3");
 new Button(shell, SWT.PUSH).setText("B4");
 new Button(shell, SWT.PUSH).setText("Button 5");
 shell.pack();
 shell.open();
 while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) display.sleep();
 } 
 
numColumns = 1
numColumns = 2
numColumns = 3
 
 
 

MakeColumnsEqualWidth
    makeColumnsEqualWidth域強制讓列都具有相同的寬度。默認值爲false。如果我們改變上面的代碼讓它具有相同寬度的3列,這就是我們將得到的(注意:在沒有進一步說明的情況下,小窗口部件在列中都是左對齊的)。

     

MarginWidth, MarginHeight, HorizontalSpacing, 和VerticalSpacing
     GridLayout中的marginspacing域和RowLayout中的這些域是相同的。不同的地方在於左邊和右邊的空白(margin)被組合成marginWidth,而項部和底部的空白被組合成marginHeight。而且,在GridLayout中,你可以獨立地指定horizontalSpacingverticalSpacing,然而在RowLayout中,spacing應用於水平或者垂直樣式是取決於RowLayout的類型的。
 
GridData 對象域
   GridData是關聯於GridLayout的佈局數據對象。爲了設置一個小窗口部件的GridData對象,你可以使用setLayoutData方法。例如:爲了給一個按鈕(Button)設定GridData,我們可以象下面這樣做:
 
 Button button1 = new Button(shell, SWT.PUSH);
 button1.setText("B1");
 button1.setLayoutData(new GridData());
 
    當然,這段代碼只是用所有它的域的默認值創建了一個GridData對象,這各沒有完全設置佈局數據是一樣的。有兩種創建帶有某些已設置域的GridData對象的方法。第一種方法是直接對域進行賦值,象這樣:
 
 GridData gridData = new GridData();
 gridData.horizontalAlignment = GridData.FILL;
 gridData.grabExcessHorizontalSpace = true;
 button1.setLayoutData(gridData);
 
 第二種方法是是利用一些有用的API - GridData定義的“類型位”(style bits)。
 
 button1.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL |    GridData.GRAB_HORIZONTAL));
 
   事實上,爲了進一步的方便,還提供了一些常用的“類型位”的聯合。
   button1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 
   注意到FILL_這些方便的類型設置了填充式排列(fill alignment)和掄佔式(grab)填充。GridData的“類型位”只能被布爾型或者枚舉型域使用。數據域必須直接進行設置。
 
  (Swing程序員注意)在我們講述它們的域之前關於GridData最後要注意的是:不要重用GridData對象。每一個Composite中被 GridLayout管理的小窗口部件必須有一個唯一的GridData對象。如果在佈局的時候一個GridLayout中的小窗口部件的佈局數據爲 null,就會爲它創建一個唯一的GridData對象。

HorizontalAlignment和VerticalAlignment
    Alignment域用於指定在一個網格單元中的哪個位置水平的和/或者垂直的放置一個小窗口部件。每一個alignment域可以有下列的其中的一個值:
  •     BEGINNING
  •     CENTER
  •     END
  •     FILL
  默認的horizontalAlignment值是BEGINNING(或者左對齊)。默認的verticalAlignment值是CENTER。
  讓我們回到我們那個在三個列中有五個按鈕的例子,我們會改變Button 5的horizontalAlignment值。
 
horizontalAlignment = GridData.BEGINNING
 
(默認)
 
 
 horizontalAlignment = GridData.CENTER
 
 
 
 
 
 
 horizontalAlignment = GridData.END
 
 
 
 
 
 
 horizontalAlignment = GridData.FILL
 
 
 
 
 

 
 
HorizontalIndent
  horizontalIndent域允許你通過指定一個特定數目的象素數來把一個小窗口部件右移。這個域典型的只在horizontalAlignment值爲BEGINNING時有用。我們不能用一個“類型位”來設置縮進,所以我們象下面這樣把我們的例子中的Button 5縮進4個象素:

 

GridData gridData = new GridData();
gridData.horizontalIndent = 4;
button5.setLayoutData(gridData);
 
HorizontalSpan and VerticalSpan
    Span域讓小窗口部件佔有多於一個網格單元的空間。它們通常和FILL排列(aligment)一起使用。我們象下面這樣讓我們例子中的的Button 5跨越最後兩個網格單元:

   

GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.horizontalSpan = 2;
button5.setLayoutData(gridData);
 
  如果我們決定讓我們的Wide Button 2跨越兩個網格單元,我們可以以這樣的方式結束:

 
 
GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.horizontalSpan = 2;
button2.setLayoutData(gridData);
 
  或者我們可以讓Button 3垂直地跨越兩個網格單元:

 
 
GridData gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
gridData.verticalSpan = 2;
button3.setLayoutData(gridData);
 
GrabExcessHorizontalSpace和GrabExcessVerticalSpace
    grabExcessHorizontalSpacegrabExcessVerticalSpace域 典型的被較大的小窗口部件如Text,List或者Canvas使用,以允許當它們包含的Composite變大時它們也相應的增大。如果一個Text搶 佔(grab)了額外的水平空間並用用戶縮放了Shell的寬度,那麼這個Text會佔有所有這些新的水平空間而同一行中的其他的小窗口部件會維持原來的 寬度。當然,當Shell縮小時搶佔了額外空間的小窗口部件也是最先收縮的。在縮放的上下文中總是考慮grabExcessSpace域是最容易的。作爲一個簡單的例子,我們重新使用前面Button 3垂直地跨越兩個網格單元的例子。這是這個例子的又一次展現:

  
 
  如果我們縮放這個窗口,唯一發生的事情只是窗口變大了。

 
 
   現在,我們讓Button 3搶佔額外的水平和垂直的空間,並且讓B1和B4垂直地填充(不使用搶佔),然後我們再一次對窗口進行縮放:

  
  
 
    這一次,Button 3再兩個方向上都增大了,而B4垂直的增大。其他的按鈕維持原來的大小。因爲Button 3是垂直地搶佔的並且它跨越了兩行,它所跨越的最後一行變高了。注意到B1並沒有增大-雖然它是垂直填充的-因爲它的行並沒有增大。因爲Button 3是水平地搶佔的,它的列變寬了,並且因爲它是水平的填充的,它的寬度變大了以填充這一列。這裏是所有五個按鈕的代碼:
 
 Button button1 = new Button(shell, SWT.PUSH);
 button1.setText("B1");
 GridData gridData = new GridData();
 gridData.verticalAlignment = GridData.FILL;
 button1.setLayoutData(gridData);
 
 new Button(shell, SWT.PUSH).setText("Wide Button 2");
 
 Button button3 = new Button(shell, SWT.PUSH);
 button3.setText("Button 3");
 gridData = new GridData();
 gridData.verticalAlignment = GridData.FILL;
 gridData.verticalSpan = 2;
 gridData.grabExcessVerticalSpace = true;
 gridData.horizontalAlignment = GridData.FILL;
 gridData.grabExcessHorizontalSpace = true;
 button3.setLayoutData(gridData);
 
 Button button4 = new Button(shell, SWT.PUSH);
 button4.setText("B4");
 gridData = new GridData();
 gridData.verticalAlignment = GridData.FILL;
 button4.setLayoutData(gridData);
 
 new Button(shell, SWT.PUSH).setText("Button 5");
 
   在一個典型的應用程序窗口中,你通常需要有至少一個搶佔的小窗口部件。如果多於一個窗口試圖搶佔同樣的空間,那麼這些額外的空間會被均勻的分配到這些搶佔式的小窗口部件中:
   
      
 
    最後一個關於搶佔需要注意的地方。如果一個小窗口部件搶佔了額外的水平空間並且它的父Composite變寬了,那麼包含這個小窗口部件的整個列都變寬 了。如果一個小窗口部件搶佔了額外的垂直空間並且它的父Composite變高了,那麼包含這個小窗口的整個行都變高了。這其中的含義是說如果任何在同一 受影響的列或者行中的小窗口部件有具有填充排列(fill alignment)的屬性,那麼它也會伸展。具有開始(beginning),居中(center) 或結束(end)的排列屬性不會伸展-他們會維持在變寬的這一列或者變寬的這一行的開始,中間或者結束處。

WidthHint和HeightHint
 如果不和GridLayout的約束系統中的其他需求發生衝突,widthHintheightHint域指出了你要讓一個小窗口部件具有的寬或者高的象素數。回到五個按鈕,三列的例子,假如我們要Button 5有70個象素寬40個象素高。我們象下面這樣編碼:
 
  GridData gridData = new GridData();
  gridData.widthHint = 70;
  gridData.heightHint = 40;
  button5.setLayoutData(gridData);
 
    Button 5在窗口中正常的大小如下左圖所示,而70個象素寬40個象素高的Button 5如下右圖所示:
    
       
  
    注意到,雖然如此,如果Button 5的horizontalAlignment是FILL,那麼GridLayout就不能滿足70個象素寬的需求。
 
    使用寬度和高度hint的最後一個意見。在一個平臺上看起來很好的事情不一定在另一個平臺也看起來很好。跨平臺的字體大小和正常小窗口部件大小間的變化意味着硬編碼的象素值通常不是佈局窗口的最好辦法。因此,如果你要使用大小hint,也讓它儘可能少地被使用。
 
 一個複雜的GridLayout的例子
    至到目前爲止,爲了展示各個域是如何工作的,GridLayout的例子都相當的簡單。現在,我們把它們放在一起創建一個比較複雜的例子。我們由手畫一個粗糙的我們將要創建的窗口的草圖開始,用以決定例如網格將含有多少個列,一些小窗口部件是否需要被伸展等問題。
 
     
 
     然後,我們開始從圖中編寫這個例子。代碼如下。注意到我們增加了一些邏輯使得這段代碼更有趣,例如,Browse…打開一個文件對話框 (FileDialog)來讀入一張圖片,Canvas在一個重繪監聽器中顯示這張圖片,Delete刪除這張圖片,Enter打印當前的狗以及它的主人 的信息。這個例子在一個單獨的main函數中編碼,這讓我們集中於佈局的代碼編寫而不用爲編程風格而感到煩亂。
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
 
public class ComplexGridLayoutExample {
     static Display display;
     static Shell shell;
     static Text dogName;
     static Combo dogBreed;
     static Canvas dogPhoto;
     static Image dogImage;
     static List categories;
     static Text ownerName;
     static Text ownerPhone;
 
     public static void main(String[] args) {
         display = new Display();
         shell = new Shell(display);
         shell.setText("Dog Show Entry");
         GridLayout gridLayout = new GridLayout();
         gridLayout.numColumns = 3;
         shell.setLayout(gridLayout);
  
         new Label(shell, SWT.NONE).setText("Dog's Name:");
         dogName = new Text(shell, SWT.SINGLE | SWT.BORDER);
         GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
         gridData.horizontalSpan = 2;
         dogName.setLayoutData(gridData);
 
         new Label(shell, SWT.NONE).setText("Breed:");
         dogBreed = new Combo(shell, SWT.NONE);
         dogBreed.setItems(new String [] {"Collie", "Pitbull", "Poodle", "Scottie"});
         dogBreed.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
 
         Label label = new Label(shell, SWT.NONE);
         label.setText("Categories");
         label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
  
         new Label(shell, SWT.NONE).setText("Photo:");
         dogPhoto = new Canvas(shell, SWT.BORDER);
         gridData = new GridData(GridData.FILL_BOTH);
         gridData.widthHint = 80;
         gridData.heightHint = 80;
         gridData.verticalSpan = 3;
         dogPhoto.setLayoutData(gridData);
         dogPhoto.addPaintListener(new PaintListener() {
             public void paintControl(final PaintEvent event) {
                  if (dogImage != null) {
                       event.gc.drawImage(dogImage, 0, 0);
                  }
             }
        });
 
        categories = new List(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
        categories.setItems(new String [] {
             "Best of Breed", "Prettiest Female", "Handsomest Male",
             "Best Dressed", "Fluffiest Ears", "Most Colors",
             "Best Performer", "Loudest Bark", "Best Behaved",
             "Prettiest Eyes", "Most Hair", "Longest Tail",
             "Cutest Trick"});
        gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
        gridData.verticalSpan = 4;
        int listHeight = categories.getItemHeight() * 12;
        Rectangle trim = categories.computeTrim(0, 0, 0, listHeight);
        gridData.heightHint = trim.height;
        categories.setLayoutData(gridData);
  
        Button browse = new Button(shell, SWT.PUSH);
        browse.setText("Browse...");
        gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
        gridData.horizontalIndent = 5;
        browse.setLayoutData(gridData);
        browse.addSelectionListener(new SelectionAdapter() {
             public void widgetSelected(SelectionEvent event) {
                 String fileName = new FileDialog(shell).open();
                  if (fileName != null) {
                     dogImage = new Image(display, fileName);
                 }
            }
       });
  
      Button delete = new Button(shell, SWT.PUSH);
      delete.setText("Delete");
      gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL |                GridData.VERTICAL_ALIGN_BEGINNING);
     gridData.horizontalIndent = 5;
     delete.setLayoutData(gridData);
     delete.addSelectionListener(new SelectionAdapter() {
         public void widgetSelected(SelectionEvent event) {
              if (dogImage != null) {
                   dogImage.dispose();
                   dogImage = null;
                   dogPhoto.redraw();
              }
         }
     });
  
     Group ownerInfo = new Group(shell, SWT.NONE);
     ownerInfo.setText("Owner Info");
     gridLayout = new GridLayout();
     gridLayout.numColumns = 2;
     ownerInfo.setLayout(gridLayout);
     gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
     gridData.horizontalSpan = 2;
     ownerInfo.setLayoutData(gridData);
  
     new Label(ownerInfo, SWT.NONE).setText("Name:");
     ownerName = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);
     ownerName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
  
     new Label(ownerInfo, SWT.NONE).setText("Phone:");
     ownerPhone = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);
     ownerPhone.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
  
     Button enter = new Button(shell, SWT.PUSH);
     enter.setText("Enter");
     gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
     gridData.horizontalSpan = 3;
     enter.setLayoutData(gridData);
     enter.addSelectionListener(new SelectionAdapter() {
         public void widgetSelected(SelectionEvent event) {
              System.out.println("/nDog Name: " + dogName.getText());
              System.out.println("Dog Breed: " + dogBreed.getText());
              System.out.println("Owner Name: " + ownerName.getText());
              System.out.println("Owner Phone: " + ownerPhone.getText());
              System.out.println("Categories:");
              String cats[] = categories.getSelection();
              for (int i = 0; i < cats.length; i++) {
                   System.out.println("/t" + cats[i]);
              }
         }
     });
  
     shell.pack();
     shell.open();
     while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) display.sleep();
     }
     if (dogImage != null) {
         dogImage.dispose();
     }
   }
}
 
    這是當Mary Smith輸入Fifi後窗口看起來的樣子:
 
  
 
   如果窗口被放大,佈局調整如下所示:
 
 
 
  注意下面這些問題:
  • 這裏有3列7行。
  • dogPhoto這個Canvas會變寬和變高同,這是因爲它是填充的並且水平地和垂直的搶佔的(雖然我們本應該縮放圖片,但我們沒有對圖片進行縮放)。
  •  dogBreed這個Combo會變寬,因爲它是水平的填充的,並且它和Canvans在同一列。
  •  dogName這個Text會變寬,那是因爲它是水平填充的,並且它所跨越的其中一列包含有Canvas。
  • Categories這個List會變高,這是因爲它是垂直填充的,並且它和Canvas跨越了相同的行。
  • 因爲categories這個List變高了,它的垂直滾動條消失了(它並沒有變寬)。
  • ownerInfo這個Group會變寬,這是因爲它是水平的填充的,並且它所跨越的其中一列包含有Canvas。
  • 作爲Composite的子類,ownerInfo這個Group有它自己的2列2行的GridLayout。
  • ownerNameownerPhone這兩個Text會變寬,這是因爲Group會變寬,並且它們在Group的GridLayout中是填充的和水平搶佔的。
  • browsedelete這兩個Button會稍微的縮進,而且因爲它們都是水平填充的,它們有相同的寬度。
  • delete這個Button在它的行的頂部垂直的對齊。
  • “Categories”這個Label在categories這個List的頂端居中。
  • enter這個Button是水平地對齊到它所跨越的3列的最右邊。
  • dogPhoto這個Canvas用寬度和高度hint來創建,這是因爲如果可能的話,我們要讓Image有80象素×80象素的大小。
  • categories這個List用List的字體的12倍的高度hint值來創建,這是因爲我們要讓List在初始狀態下顯示十二個項。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章