I have a panel where I place several mini-panels, side-by-side, with different sizes and colors, and they should occupy the entire parent panel (horizontally).
For this I use BorderLayout (for the parent panel), and BoxLayout for a sub-panel where I place all the mini-panels (see code below). It does work and behave correctly uppon resizing and everything. However, as the number of mini-panels becomes larger, a strange behaviour occurs: empty space appears at the end of the parent panel.
I think I found that this is a streching bug in the layout managers, because in order to strech the panels, the layout manager tries to add a single pixel to each mini-panel. However, when the number of mini-panels is large, adding a single pixel to every one will result in adding many pixels and going beyond the size of the parent. Thus, the layout manager ends up not adding any pixels to any mini-panel, resulting in the empty space.
Here is my SSCCE: (try running, and streching the window, to understand the problem)
package com.myPackage;
import java.awt.*;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ColoredPanels extends JPanel
{
/* Content information. */
private Vector<Integer> partitions;
private Vector<Color> colors;
/* Panel where the content panels will go. */
private JPanel contentHolder;
private final int defaultHeight = 20;
public ColoredPanels(Vector<Integer> partitions, Vector<Color> colors)
{
assert partitions != null;
assert !partitions.isEmpty();
assert colors != null;
assert !colors.isEmpty();
assert colors.size() == partitions.size();
this.partitions = partitions;
this.colors = colors;
/* Set layout manager. */
setLayout(new BorderLayout());
/* Create the content holder. */
contentHolder = new JPanel();
contentHolder.setLayout(new BoxLayout(contentHolder, BoxLayout.X_AXIS));
this.add(contentHolder, BorderLayout.NORTH);
/* Fill content holder with colored panels. */
createPanels();
}
private void createPanels()
{
assert partitions != null;
assert !partitions.isEmpty();
assert colors != null;
assert !colors.isEmpty();
assert colors.size() == partitions.size();
for (int i = 0; i < partitions.size(); i++)
{
JPanel newPanel = new JPanel();
newPanel.setBackground(colors.get(i));
newPanel.setPreferredSize(new Dimension(partitions.get(i), defaultHeight));
newPanel.setMinimumSize(new Dimension(1, defaultHeight));
contentHolder.add(newPanel);
}
}
public static void main(String[] in)
{
Vector<Integer> sizes = new Vector<Integer>();
Vector<Color> cols = new Vector<Color>();
/* Make 100 random sizes, and use two colors. */
for (int i = 0; i < 100; i++)
{
int size = (int)Math.round(1 + Math.random() * 10);
sizes.add(size);
cols.add((i%2 == 0)? Color.red : Color.green);
}
ColoredPanels panels = new ColoredPanels(sizes, cols);
panels.setBorder(BorderFactory.createLineBorder(Color.yellow, 1));
JFrame newFrame = new JFrame();
newFrame.getContentPane().add(panels);
newFrame.pack();
newFrame.setVisible(true);
}
}
How do I avoid this behaviour? I want my panels to occupy the whole container.
EDIT: The mini-panels are intended to have (once this is resolved) mouse listeners. Thus, painting solutions are unfortunatelly avoidable.