How can I get FlowLayout to align the JPanels below, as with other components?

I have a case where I add JPanels to FlowLayout and they do not align at the bottom of the layout. I use this layout.setAlignOnBaseline(true) and correctly align JLabels to the bottom of the panel. However, once these shortcuts are wrapped by the panels themselves, they no longer work. Here is an example of what I mean, with two panels at the top and bottom.

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

If you run this code, you will notice that the top panel has a smaller "Foo" centered in the panel, and the bottom one with the desired "bottom alignment" I hope for. Any ideas on how to get sub JPanels to behave the same?

+6
source share
3 answers

API for the setAlignOnBaseline(...) method:

Components that do not have a baseline will be centered.

JPanel does not have a reasonable baseline for use, as components may be on multiple lines depending on the layout manager used. Therefore he is focused.

I can’t say for your question if you are actually trying to center all the text on the basis, regardless of the font size, or just trying to make all the components colorize in the panel pane.

If you are trying to center the text on a baseline, perhaps you can redefine the baseline of the panel with the code:

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

Of course, this will only work if all the components on the panel have the same baseline.

Or, if you are just trying to arrange all the components at the bottom of the panel, you need to use a different layout manager.

You can use the Relative layout to align all components at the bottom.

It can be used as a direct replacement for existing code:

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

Or, if you do not want to use a class without JDK, then the BoxLayout or GridBagLayout will be the way to go.

If you use BoxLayout , you will need to play with the setAlignmentY(...) property for each component.

If you use GridBagLayout , you will need to play with restrictions for each component.

+6
source

I myself used a layout with more "oomph" than FlowLayout for this, like GridBagLayout. If you use it, you can set the anchor as SOUTH , and the weighted one is 0.0, which should prevent the component from stretching its height and setting it down. For instance:

  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
source

Thinking how to do this without a GridBagLayout, I came up with this, although this is a bit "hacky":

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

The only reason I did this is because I personally never use GridBagLayout , but it has its advantages (as you can see;)).

Perhaps I just do not have the opportunity to make JPanel upright, and I complicate too much.

+2
source

All Articles