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 can I modify the FlowLayout to align the top of components as depicted in the following image:
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);
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.