Search code examples
javaswingalignmentlayout-managerflowlayout

Prevent Vertical Centering of FlowLayout


I have a JPanel using a FlowLayout layout manager and contains components with different sizes.

EDIT: I want to use the FlowLayout because it allows the components to wrap to a new line when the container is resized and they no longer fit next to each other.

The following image depicts the vertical alignment of the FlowLayout on the different components:

How the FlowLayout is aligning the components

How can I modify the FlowLayout to align the top of components as depicted in the following image:

How I would like the FlowLayout to align the components

Here is a code example of the problem:

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel flowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
frame.getContentPane().add(flowPanel);

JButton firstComp = new JButton("First");
firstComp.setPreferredSize(new Dimension(200, 300));
flowPanel.add(firstComp);

JButton secondComp = new JButton("Second");
secondComp.setPreferredSize(new Dimension(160, 180));
flowPanel.add(secondComp);

frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

Solution

  • The FlowLayout is the only standard JDK layout manager that supports wrapping components to a new line. (There may be third party layout, like MigLayout that support this).

    If you don't like the default functionality then you can customize the layout manager. Here is a simple example that lets the FlowLayout do the default layout and then it resets each component to the top of the line:

    import java.awt.*;
    import java.util.*;
    import javax.swing.*;
    
    public class TopFlowLayout extends FlowLayout
    {
        @Override
        public void layoutContainer(Container container)
        {
            super.layoutContainer(container);
    
            Component c = container.getComponent(0);
    
            int lineStart = getVgap();
            int lineHeight = lineStart + c.getSize().height;
    
            for (int i = 0; i < container.getComponentCount(); i++)
            {
                c = container.getComponent(i);
    
                Point p = c.getLocation();
                Dimension d = c.getSize();
    
                if (p.y < lineHeight) // still on current line
                {
                    p.y = lineStart;
                    lineHeight = Math.max(lineHeight, lineStart + d.height);
                }
                else  // start a new line
                {
                    lineStart = lineHeight + getVgap();
                    p.y = lineStart;
                    lineHeight = lineStart + d.height;
                }
    
                p.y = lineStart;
                c.setLocation(p);
            }
        }
    
        private static void createAndShowGUI()
        {
            TopFlowLayout layout = new TopFlowLayout();
            layout.setAlignment(FlowLayout.LEFT);
            JPanel flowPanel = new JPanel( layout );
    
            Random random = new Random();
    
            for (int i = 0; i < 10; i++)
            {
                flowPanel.add( createButton(i + "", random.nextInt(100), random.nextInt(100)) );
            }
    
            JFrame frame = new JFrame("SSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add( flowPanel );
            frame.setLocationByPlatform( true );
            frame.setSize(400, 400);
            frame.setVisible( true );
        }
    
        private static JButton createButton(String text, int width, int height)
        {
            JButton button = new JButton(text);
            Dimension size = new Dimension(width + 50, height + 50);
            button.setPreferredSize(size);
    
            return button;
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowGUI();
                }
            });
        }
    }
    

    You may also want to consider extending the Wrap Layout which is also based on the FlowLayout but adds additional functionality.