2016-08-23 89 views
6

我有一個情況,我將JPanels添加到FlowLayout,並且他們沒有將自己對齊到佈局的底部。我正在使用這個layout.setAlignOnBaseline(true),它將JLabel正確對齊面板的底部。但是,一旦這些標籤本身包裹在面板中,它就不再起作用。這裏是我的意思的例子,有兩個面板頂部和底部。如何讓FlowLayout將JPanels底部對齊,就像它對其他組件一樣?

import javax.swing.*; 
import java.awt.*; 

public class BadLayout { 

    private static final Font font1 = new Font("Arial", Font.BOLD, 14); 
    private static final Font font2 = new Font("Arial", Font.BOLD, 30); 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> { 
      JFrame frame = new JFrame("Bad layout"); 
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

      FlowLayout layout = new FlowLayout(FlowLayout.LEADING, 0, 0); 
      layout.setAlignOnBaseline(true); 

      JPanel topPanel = new JPanel(); 
      topPanel.setLayout(layout); 
      topPanel.setBackground(Color.BLACK); 
      for (int i = 0; i < 10; i++) { 
       JLabel label = new JLabel("Foo"); 
       label.setForeground(Color.WHITE); 
       label.setBackground(Color.RED); 
       label.setOpaque(true); 
       label.setFont(i % 2 == 0 ? font1 : font2); 

       JPanel subPanel = new JPanel(); 
       subPanel.setLayout(layout); 
       subPanel.setBackground(Color.RED); 
       subPanel.add(label); 
       subPanel.setAlignmentY(Component.BOTTOM_ALIGNMENT); 

       topPanel.add(subPanel); 
      } 

      JPanel bottomPanel = new JPanel(); 
      bottomPanel.setLayout(layout); 
      bottomPanel.setBackground(Color.DARK_GRAY); 
      for (int i = 0; i < 10; i++) { 
       JLabel label = new JLabel("Foo"); 
       label.setForeground(Color.WHITE); 
       label.setBackground(Color.RED); 
       label.setOpaque(true); 
       label.setFont(i % 2 == 0 ? font1 : font2); 
       bottomPanel.add(label); 
      } 

      JPanel parentPanel = new JPanel(); 
      parentPanel.setLayout(new BorderLayout()); 
      parentPanel.add(topPanel, BorderLayout.NORTH); 
      parentPanel.add(bottomPanel, BorderLayout.SOUTH); 

      frame.getContentPane().add(parentPanel); 
      frame.pack(); 
      frame.setVisible(true); 
     }); 
    } 
} 

如果你運行這段代碼,你會發現在頂部面板具有更小的「富」 S在面板中心,而在底部的一個人所期望的「底部對齊」行爲我希望對於。任何想法如何讓子JPanel行爲相同?

回答

6

setAlignOnBaseline(...)方法狀態的API:不具有基線將居中

一個JPanel不具有合理的基線使用,因爲組件可以在根據多行

組件正在使用的佈局管理器上。所以它是中心。

我不能告訴你的問題,如果你是實際上試圖將所有的文本都放在基線上,而不管字體的大小如何,還是隻是試圖讓所有的組件都被繪製在面板的底部。

如果你正在嘗試集中在基線文本,那麼也許你可以重寫面板的基線的代碼是這樣的:

JPanel subPanel = new JPanel() 
{ 
    @Override 
    public int getBaseline(int width, int height) 
    { 
     Component c = getComponent(0); 
     return c.getBaseline(width, height); 
    } 
}; 

當然,這隻會工作,如果面板上所有的部件都相同的基線。

或者,如果您只是想將所有組件放在面板的底部,那麼您需要使用不同的佈局管理器。

您可以使用Relative Layout將所有組件對齊到底部。

它可以被用來作爲直接替換你現有代碼:

RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS, 0); 
rl.setAlignment(RelativeLayout.TRAILING); 
JPanel topPanel = new JPanel(rl); 

或者,如果你不想使用非JDK類則BoxLayoutGridBagLayout將要走的路。

如果您使用BoxLayout那麼您將需要玩每個組件的setAlignmentY(...)屬性。

如果您使用GridBagLayout,那麼您將需要使用每個組件的約束。

+0

謝謝。我意識到我的意圖是集中於基線(而不是整個組件),因此覆蓋面板返回其組件的基線可能是我想要的。最終,我的應用程序只是將一堆標籤分組在一起,因此覆蓋應該不會太差。謝謝。 – Glucose

2

我自己,我會使用一個佈局比這個更流行,比如GridBagLayout。如果你使用它,你可以設置錨點爲SOUTH,重量爲0.0,這將防止組件伸展高度,並將其放置在底部。例如:

JPanel topPanel = new JPanel(); 
    // topPanel.setLayout(layout); 
    topPanel.setLayout(new GridBagLayout()); 
    topPanel.setBackground(Color.BLACK); 
    for (int i = 0; i < 10; i++) { 
     JLabel label = new JLabel("Foo"); 
     label.setForeground(Color.WHITE); 
     label.setBackground(Color.RED); 
     label.setOpaque(true); 
     label.setFont(i % 2 == 0 ? font1 : font2); 

     GridBagConstraints gbc = new GridBagConstraints(); 
     gbc.gridx = i; 
     gbc.gridy = 0; 
     gbc.weightx = 1.0; 
     gbc.weighty = 0.0; 
     gbc.fill = GridBagConstraints.HORIZONTAL; 
     gbc.anchor = GridBagConstraints.SOUTH; 

     JPanel subPanel = new JPanel(); 
     subPanel.setLayout(new BorderLayout()); 
     subPanel.setBackground(Color.RED); 
     subPanel.add(label); 
     subPanel.setPreferredSize(subPanel.getMinimumSize()); 
     // subPanel.setAlignmentY(Component.BOTTOM_ALIGNMENT); 
     topPanel.add(subPanel, gbc); 
    } 
2

思考如何可以不GridBagLayout的完成後,我想出了這個,即使它是一個有點「hackish的」:

 JPanel topPanel = new JPanel(); 
     ((FlowLayout) topPanel.getLayout()).setAlignOnBaseline(true); 
     topPanel.setBackground(Color.BLACK); 

     int h = 0; 
     for (int i = 0; i < 10; i++) { 
      JLabel label = new JLabel("Foo"); 
      label.setForeground(Color.WHITE); 
      label.setBackground(Color.GREEN); 
      label.setOpaque(true); 
      label.setFont(i % 2 == 0 ? font1 : font2); 
      JPanel wrapBorder = new JPanel(new BorderLayout()); 
      JPanel subPanel = new JPanel(); 
      subPanel.setBackground(Color.RED); 
      subPanel.add(label); 
      subPanel.setBackground(Color.GREEN); 
      wrapBorder.setOpaque(false); 
      wrapBorder.add(BorderLayout.SOUTH, subPanel); 
      if(wrapBorder.getPreferredSize().height > h) { 
       h = wrapBorder.getPreferredSize().height; 
      } 
      topPanel.add(wrapBorder); 
     } 

     for(Component component : topPanel.getComponents()) { 
      component.setPreferredSize(new Dimension(component.getPreferredSize().width, h)); 
     } 

我這樣做的唯一原因是因爲我個人從未使用GridBagLayout,但它有其優點(可以看出;))。

我可能只是缺少一種方法,使JPanel的垂直擴展和我過分複雜的事情很多。