在 Java 布局管理器方面,最新增加了 SpringLayout 管理器,它是與 Java 1.4 一起發布的。這種布局管理器允許您將“spring”附加到組件上,這樣組件就可以相對於其他組件進行布局。例如,利用 SpringLayout 您可以讓一個按鈕依附於右邊框來進行顯示,而不管用戶將屏幕寬度設為多大。
開始使用 SpringLayout
與所有布局管理器一樣, SpringLayout 管理器負責安排組件的位置。組件的位置是通過為之提供相關聯的約束來進行控制的。對於 SpringLayout 控制的組件,有一個帶有 4 個設置值的約束 -- 每個設置值對應於組件的每條邊。 SpringLayout 管理器依賴一個 SpringLayout.Constraints 對象來提供這些組件約束。這與 GridBagConstraints 類的工作原理有點類似, GridBagConstraints 類補充了 GridBagLayout 管理器:每個添加到容器中的組件都可以有一個依附在其上的 SpringLayout.Constraints 對象。不過,兩者的相似之處僅此而已。
在使用 GridBagLayout的時候 ,您通常的做法是使用約束將組件添加到容器中。在使用 SpringLayout 管理器的情況下,您通常不必使用約束來添加組件。相反,您可以直接添加組件,然後再分別地為之附加約束。除了 SpringLayout 外,沒有什麼可以阻止您為組件添加約束 。Constraints 不是一個簡單的類。它是 Spring 對象(用於每條邊)的一個集合。當您使用 SpringLayout.Constraints 類時,您需要分別地將每個 Spring 約束添加到 SpringLayout.Constraints 。您是通過對組件的某一條邊設置特定的約束來向 SpringLayout.Constraints “添加”約束的。通過使用 EAST 、 WEST 、 NORTH 和 SOUTH 這 4 個 SpringLayout 常量,您可以調用 SpringLayout.Constraints 的 setContraints(String edge, Spring spring) 方法,其中 String 類型的參數是 4 個常量中的一個。例如,如果您想將一個組件添加到一個容器的頂部偏左的位置,那麼可以建立兩個大小固定的 spring,將它們組合起來,然後將組件添加到帶有這樣組合而成的 spring 集的容器中,如清單 1 所示:
清單 1. 使用 SpringLayout
Component left = ...;
SpringLayout layout = new SpringLayout();
JPanel panel = new JPanel(layout);
Spring xPad = Spring.constant(5);
Spring yPad = Spring.constant(25);
SpringLayout.Constraints constraint = new SpringLayout.Constraints();
constraint.setConstraint(SpringLayout.WEST, xPad);
constraint.setConstraint(SpringLayout.NORTH, yPad);
contentPane.add(left, constraint);
這看上去不是特別難,但是當您需要添加下一個組件時,不管是添加到第一個組件的右邊還是下面,事情都要更難辦一些。您不能簡單地在 n 像素外添加組件;實際上,您必需為早先的組件添加 padding(補白)。為了找出前一個組件的邊,您可以使用 getConstraint() 方法請求布局管理器,為該方法傳遞您所針對的邊和組件,例如 layout.getConstraint(SpringLayout.EAST, left) ,以此來獲得第一個組件的正確的邊的位置。從這個位置,您可以加進必需的 padding,並將其附加到其他組件的邊上,如清單 2 所示:
清單 2. 使用 SpringLayout 添加第二個組件
Component right = ...;
Spring rightSideOfLeft = layout.getConstraint(SpringLayout.EAST, left);
Spring pad = Spring.constant(20);
Spring leftEdgeOfRight = Spring.sum(rightSideOfLeft, pad);
constraint = new SpringLayout.Constraints();
constraint.setConstraint(SpringLayout.WEST, leftEdgeOfRight);
constraint.setConstraint(SpringLayout.NORTH, yPad);
contentPane.add(right, constraint);
通過 SpringLayout 使用 putConstraint()
這種方法非常有效,但是如果組件的數量多起來的話,這種方法就顯得單調乏味了。相反,另一種回避中間步驟的方法是先不帶約束地直接添加組件,然後再分別地添加約束,使用 SpringLayout 的 putConstraint() 方法將約束連接到組件,如清單 3 所示:
清單 3. 用 SpringLayout 添加第二個組件
public void putConstraint(String e1, Component c1, int pad,
String e2, Component c2)
public void putConstraint(String e1, Component c1, Spring s,
String e2, Component c2)
這裡,您無需請求組件的邊並自己加進 padding, putConstraint() 方法調用為您同時處理了這兩個任務。為了演示這一點,清單 4 像清單 3 那樣向正確的組件添加了同樣的約束,不過這裡使用的是 putConstraint(), 而不是直接使用 SpringLayout.Constraints :
清單 4. 使用 putConstraint() 添加第二個組件
Component left = ...;
Component right = ...;
SpringLayout layout = new SpringLayout();
JPanel panel = new JPanel(layout);
panel.add(left);
panel.add(right);
layout.putConstraint(SpringLayout.WEST, left, 5,
SpringLayout.WEST, panel);
layout.putConstraint(SpringLayout.NORTH, left, 25,
SpringLayout.NORTH, panel);
layout.putConstraint(SpringLayout.NORTH, right, 25,
SpringLayout.NORTH, panel);
layout.putConstraint(SpringLayout.WEST, right, 20,
SpringLayout.EAST, left);
putConstraint() 方法中的 String 類型參數是 4 個 SpringLayout 常量 EAST、WEST、NORTH 和 SOUTH。當使用 putConstraint() 時,應首先確信指定了未知組件的位置,並將其連接到某樣可以計算的或者固定的東西上,比如屏幕的邊界。
用 BeanBuilder 試驗 SpringLayout
為了幫助您親歷 SpringLayout 的用法,Sun 提供了一個名為 BeanBuilder 的工具(參閱 參考資料)。當使用 JavaBeans 組件時,該工具還有更多的用處,不過它也為研究 SpringLayout 提供了一種簡單的方式。圖 1 展示了該工具啟動時的樣子:
圖 1. BeanBuilder 啟動屏幕
雖然我們不打算討論 BeanBuilder 工具的細節,但是關於這個工具有一個地方是要談到的,那就是使用 SpringLayout 連接組件。在每個組件的各條邊上共有 4 個小方框,分別對應 north(北)、south(南)、east(東) 和 west(西)。您可以從一個小方框中拖出一個箭頭,將其連接到任何其他的小方框。如果該工具再高級一點,它將允許您指定間隙寬度,但是圖 2 顯示的是在開發階段的一個屏幕:
圖 2. BeanBuilder 使用屏幕
由圖 2 可以說明,您可以可視化地將箭頭連接到一個指定的 putConstraint() 調用。
完整的 SpringLayout 實例
為了演示 SpringLayout 的用法,清單 4 給出了 SpringFormTest 程序,該程序將前面解釋過的使用 putConstraint() 的代碼片斷拼接起來。(您也可以下載該代碼;參閱 參考資料。)
清單 4. 完整的 SpringLayout 實例
import java.awt.*;
import javax.swing.*;
public class SpringFormTest {
public static void main(String args[]) {
JFrame frame = new JFrame("Spring Form");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
SpringLayout layout = new SpringLayout();
contentPane.setLayout(layout);
Component left = new JLabel("Left");
Component right = new JTextField(15);
contentPane.add(left);
contentPane.add(right);
layout.putConstraint(SpringLayout.WEST, left, 10,
SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, left, 25,
SpringLayout.NORTH, contentPane);
layout.putConstraint(SpringLayout.NORTH, right, 25,
SpringLayout.NORTH, contentPane);
layout.putConstraint(SpringLayout.WEST, right, 20,
SpringLayout.EAST, left);
frame.setSize(300, 100);
frame.show();
}
}
圖 3 顯示了結果:
圖 3. SpringFormTest 實例屏幕