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