I'm trying to build a panel with components laid out horizontally, with auto-wrap if not enough place and a vertical scrollbar.
Something like this:
+-----------------+
|[1][2][3][4][5] |
| |
+-----------------+
reducing the width:
+-----------+
|[1][2][3] |
|[4][5] |
+-----------+
reducing the width again, the scrollbar appears:
+---------+
|[1][2] ^|
|[3][4] v|
+---------+
I'm not far from a solution:
public class TestFlow extends JFrame {
public TestFlow() {
getContentPane().setLayout(new BorderLayout());
JPanel panel = new JPanel(new FlowLayout());
JScrollPane scroll = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
getContentPane().add(scroll, BorderLayout.CENTER);
panel.add(new MyComponent("A"));
panel.add(new MyComponent("B"));
panel.add(new MyComponent("C"));
panel.add(new MyComponent("D"));
panel.add(new MyComponent("E"));
panel.add(new MyComponent("F"));
panel.add(new MyComponent("G"));
panel.add(new MyComponent("H"));
panel.add(new MyComponent("I"));
panel.add(new MyComponent("J"));
panel.add(new MyComponent("K"));
panel.add(new MyComponent("L"));
panel.add(new MyComponent("M"));
panel.add(new MyComponent("N"));
panel.add(new MyComponent("O"));
scroll.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
Dimension max=((JScrollPane)e.getComponent()).getViewport().getExtentSize();
// panel.setMaximumSize(new Dimension(max.width,Integer.MAX_VALUE));
panel.setPreferredSize(new Dimension(max.width,Integer.MAX_VALUE));
// panel.setPreferredSize(max);
panel.revalidate();
// panel.repaint();
// System.out.println(panel.getSize().width+"--"+max.width);
}
});
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500, 200);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new TestFlow().setVisible(true));
}
private static class MyComponent extends JLabel {
public MyComponent(String text) {
super(String.join("", Collections.nCopies((int)(Math.round(Math.random()*4)+4), text)));
setOpaque(true);
setBackground(Color.YELLOW);
}
}
}
, but have still strange behaviours:
With the solution panel.setPreferredSize(new Dimension(max.width,Integer.MAX_VALUE));
- after a resize of the window, the panel gets empty. I must manually move the scrollbar to have the content appearing
- the scrollbar is always visible, while it shouldn't
With the solution panel.setPreferredSize(max);
- after a resize of the window, the panel is not re-laid out. I must manually move a second time the window to have the content re-laid out.
- the scrollbar is never visible, while it should.
Any suggestion in that code ?
[EDIT] I've complicated the original code, and applied the suggestions that were provided until now.
For design purpose, I would like to use a MigLayout on top of my Panel. At start, everything is well laid out. When enlarging the window, it works too. But not on reducing the window. The addComponentListener
does not bring any addedvalue.
public class TestMigFlow extends JFrame {
public TestMigFlow() {
getContentPane().setLayout(new BorderLayout());
JPanel panel = new JPanel(new MigLayout("debug, fill, flowy", "[fill]"));
JScrollPane scroll = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
getContentPane().add(scroll, BorderLayout.CENTER);
panel.add(new JLabel("A title as spearator "), "growy 0");
JPanel sub = new JPanel(new WrapLayout());
// panel.add(sub, "growx 0"); // Works well on shrink but not on grow
panel.add(sub); // Works well on grow but not on shrink
sub.add(new MyComponent("A"));
sub.add(new MyComponent("B"));
sub.add(new MyComponent("C"));
sub.add(new MyComponent("D"));
sub.add(new MyComponent("E"));
sub.add(new MyComponent("F"));
sub.add(new MyComponent("G"));
sub.add(new MyComponent("H"));
sub.add(new MyComponent("I"));
sub.add(new MyComponent("J"));
sub.add(new MyComponent("K"));
sub.add(new MyComponent("L"));
sub.add(new MyComponent("M"));
sub.add(new MyComponent("N"));
sub.add(new MyComponent("O"));
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
Dimension max = new Dimension(scroll.getWidth(), Short.MAX_VALUE);
panel.setMaximumSize(max);
panel.repaint();
}
});
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(200, 500);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new TestMigFlow().setVisible(true));
}
private static class MyComponent extends JLabel {
public MyComponent(String text) {
super(String.join("", Collections.nCopies((int) (Math.round(Math.random() * 4) + 4), text)));
setOpaque(true);
setBackground(Color.YELLOW);
}
}