選擇 JPanel 或頂層容器的 content pane 時,必須考慮布局管理。JPanel 預設 FlowLayout,content pane 預設 BorderLayout。本文詳細介紹六大常用布局管理器並附完整代碼範例。
每個演示類包含三個核心方法:
addComponentsToPane(Container):佈局邏輯實現。createAndShowGUI():建立 JFrame、載入內容面板、顯示視窗。main():透過 SwingUtilities.invokeLater 在事件調度執行緒啟動 UI。組件從左至右排列,空間不足自動換行。
public static void addComponentsToPane(Container pane) {
pane.setLayout(new FlowLayout());
pane.add(new JButton("Button 1"));
pane.add(new JButton("Button 2"));
pane.add(new JButton("Button 3"));
pane.add(new JButton("Long-Named Button 4"));
pane.add(new JButton("5"));
}
將容器劃分為 PAGE_START、PAGE_END、LINE_START、LINE_END、CENTER 五區域。
public static void addComponentsToPane(Container pane) {
JButton button = new JButton("Button 1 (PAGE_START)");
pane.add(button, BorderLayout.PAGE_START);
button = new JButton("Button 2 (CENTER)");
button.setPreferredSize(new Dimension(200, 100));
pane.add(button, BorderLayout.CENTER);
button = new JButton("Button 3 (LINE_START)");
pane.add(button, BorderLayout.LINE_START);
button = new JButton("Long-Named Button 4 (PAGE_END)");
pane.add(button, BorderLayout.PAGE_END);
button = new JButton("5 (LINE_END)");
pane.add(button, BorderLayout.LINE_END);
}
支援 X_AXIS(水平)與 Y_AXIS(垂直)兩種方向,常搭配 BorderLayout 使用。
public static void addComponentsToPane(Container pane) {
JPanel xPanel = new JPanel();
xPanel.setLayout(new BoxLayout(xPanel, BoxLayout.X_AXIS));
addButtons(xPanel);
JPanel yPanel = new JPanel();
yPanel.setLayout(new BoxLayout(yPanel, BoxLayout.Y_AXIS));
addButtons(yPanel);
pane.add(yPanel, BorderLayout.PAGE_START);
pane.add(xPanel, BorderLayout.PAGE_END);
}
private static void addAButton(String text, Container container) {
JButton button = new JButton(text);
button.setAlignmentX(Component.CENTER_ALIGNMENT);
container.add(button);
}
private static void addButtons(Container container) {
addAButton("Button 1", container);
addAButton("Button 2", container);
addAButton("Button 3", container);
addAButton("Long-Named Button 4", container);
addAButton("5", container);
}
同一時間僅顯示一張「卡片」,適合嚮導、分頁切換場景。
public void addComponentToPane(Container pane) {
final JPanel contentPanel = new JPanel();
JPanel controlPanel = new JPanel();
final CardLayout cardLayout = new CardLayout();
pane.setLayout(new BorderLayout());
pane.add(contentPanel, BorderLayout.CENTER);
pane.add(controlPanel, BorderLayout.PAGE_END);
controlPanel.setLayout(new FlowLayout());
JButton[] b = new JButton[10];
for (int i = 0; i < 10; i++) {
b[i] = new JButton("No." + i);
contentPanel.add(b[i]);
}
contentPanel.setLayout(cardLayout);
JButton nextButton = new JButton("next");
nextButton.addActionListener(e -> cardLayout.next(contentPanel));
controlPanel.add(nextButton);
}
組件按順序從左至右、上至下填充,無法指定具體格子。
public static void addComponentsToPane(Container pane) {
JButton[] buttons = new JButton[9];
pane.setLayout(new GridLayout(3, 3));
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton(i + "");
pane.add(buttons[i]);
}
}
透過 GridBagConstraints 的 11 個屬性精準控制組件位置、大小、對齊、填充、間距等。
| 屬性 | 說明 |
|---|---|
| gridx / gridy | 組件網格坐標(從 0 開始) |
| gridwidth / gridheight | 跨越列數/行數,REMAINDER 表示佔滿剩餘空間 |
| weightx / weighty | 額外空間分配權重,決定縮放比例 |
| anchor | 組件小於顯示區時的停靠位置(CENTER、NORTH、EAST 等) |
| fill | 區域大於組件時的填充方式(HORIZONTAL、VERTICAL、BOTH、NONE) |
| insets | 組件四周外邊距(上、左、下、右) |
| ipadx / ipady | 組件內部水平/垂直間距,增加最小寬高 |
public static void addComponentsToPane(Container pane) {
GridBagConstraints c = new GridBagConstraints();
pane.setLayout(new GridBagLayout());
JButton button = new JButton("Button 1");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0; c.gridy = 0;
pane.add(button, c);
button = new JButton("Button 2");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5; c.gridx = 1; c.gridy = 0;
pane.add(button, c);
button = new JButton("Button 3");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5; c.gridx = 2; c.gridy = 0;
pane.add(button, c);
button = new JButton("Long-Named Button 4");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 40; c.weightx = 0.0; c.gridwidth = 3;
c.gridx = 0; c.gridy = 1;
pane.add(button, c);
button = new JButton("5");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 0; c.weighty = 1.0;
c.anchor = GridBagConstraints.PAGE_END;
c.insets = new Insets(10, 0, 0, 0);
c.gridx = 1; c.gridwidth = 2; c.gridy = 2;
pane.add(button, c);
}