2016-08-23 57 views
6

Mam przypadek, w którym dodaje JPanels do FlowLayout, i nie są one wyrównanie się do dolnej części układu. Używam tego layout.setAlignOnBaseline(true) i poprawnie wyrównuje JLabels do dolnej części panelu. Jednakże, gdy etykiety te są już zapakowane w panele, nie działają one już. Oto przykład tego, co mam na myśli, z dwoma panelami u góry iu dołu.Jak mogę uzyskać FlowLayout, aby dopasować JPanels na dole, tak jak robi to dla innych składników?

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); 
     }); 
    } 
} 

Po uruchomieniu tego kodu zauważysz górny panel ma mniejsze „foo” S w środku panelu, natomiast jeden na dole jest pożądany „bottom-wyrównane” zachowanie mam nadzieję dla. Jakieś pomysły, jak sprawić, aby sub-JPanele zachowywały się tak samo?

Odpowiedz

6

API dla państw setAlignOnBaseline(...) metoda:

Elementy, które nie mają bazowa zostanie wyśrodkowany

JPanel nie ma rozsądnego odniesienia do wykorzystania, ponieważ komponenty mogą być na wielu liniach w zależności na używanym menedżerze układu. Więc jest wyśrodkowany.

Nie mogę stwierdzić na podstawie twojego pytania, czy faktycznie próbujesz wyśrodkować cały tekst na linii bazowej, niezależnie od rozmiaru czcionki, czy próbujesz po prostu, aby wszystkie komponenty były pomalowane na dole panelu.

Jeśli chcesz, aby wyśrodkować tekst na początku badania, a następnie być może można zastąpić odniesienia panelu z kodem coś takiego:

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

Oczywiście to będzie działać tylko wtedy, gdy wszystkie elementy na panelu mają ta sama linia podstawowa.

Jeśli próbujesz ustawić wszystkie elementy na dole panelu, musisz użyć innego menedżera układu.

Możesz użyć Relative Layout, aby wyrównać wszystkie komponenty na dole.

Może być stosowany jako bezpośredni zamiennik do istniejącego kodu:

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

Albo jeśli nie chcesz używać non klasę JDK wtedy BoxLayout lub GridBagLayout będzie droga.

Jeśli używasz BoxLayout, musisz grać z właściwością setAlignmentY(...) każdego komponentu.

Jeśli używasz GridBagLayout, musisz grać z ograniczeniami każdego komponentu.

+0

Dzięki. Zdałem sobie sprawę, że moim zamiarem było skupienie się na linii bazowej (a nie na całym komponencie), więc nadrzędność tego panelu, aby przywrócić linię bazową jego komponentów, jest prawdopodobnie tym, czego chcę. Ostatecznie moja aplikacja to po prostu grupowanie grup etykiet, więc nie powinno być źle. Dziękuję Ci. – Glucose

2

Ja sam użyłbym układu z większą ilością "oomph" niż FlowLayout do tego, na przykład GridBagLayout. Jeśli go używasz, możesz ustawić kotwicę na SOUTH, a ważącą na 0.0, która powinna uniemożliwić elementowi rozciągnięcie jego wysokości i umieścić go na dole. Na przykład:

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

Po myśląc, jak to można zrobić bez GridBagLayout, wpadłem na to, mimo że jest nieco „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)); 
     } 

Jedynym powodem, zrobiłem to ponieważ osobiście nigdy nie używam GridBagLayout, ale ma swoje zalety (jak widać;)).

Po prostu może brakować sposobu, aby powiększyć o JPanel i nadmiernie skomplikować rzeczy.