3

I am trying to organise a frame according to the following pattern:

 _______________________
|  ___________________  |
| | +   +   +   +   + | |
| | +   +             | |
| |___________________| |
|  ___________          |
| | +   +   + |         |
| |___________|         |
|_______________________|

Here are my requirements:

  • I do not know at compile time how many components I will have in each nested JPanel
  • The user should be able to resize the window
  • The nested JPanel(s) should extend vertically if there not enough space to display all the components on one line
  • The nested JPanel(s) should not extend vertically if there is available space (i.e. I do not want to have vertical white spaces in the nested JPanel(s), but it's fine if there are some in the main frame)

For the nested JPanel(s), it seems to me that a FlowLayout is the best solution, and I tried to used a BoxLayout and a GridBagLayout for organising my panels, but without success: the internal components never wrap.

Here is my code:

public class Example {

private static final int NB1 = 5;
private static final int NB2 = 13;
private static final int NB3 = 15;

public static void main(String[] args) {

    JFrame f = new JFrame();
    f.setTitle("Example");
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    f.setSize(300,600);

    JPanel p1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
    p1.setBorder(new TitledBorder(new LineBorder(Color.BLACK), "JPanel 1"));
    for(int i=0; i<NB1; i++)
        p1.add(new JButton("Button " + i));

    JPanel p2 = new JPanel(new FlowLayout(FlowLayout.CENTER));
    p2.setBorder(new TitledBorder(new LineBorder(Color.BLACK), "JPanel 2"));
    for(int i=NB1; i<NB2; i++)
        p2.add(new JButton("Button " + i));

    JPanel p3 = new JPanel(new FlowLayout(FlowLayout.CENTER));
    p3.setBorder(new TitledBorder(new LineBorder(Color.BLACK), "JPanel 3"));
    for(int i=NB2; i<NB3; i++)
        p3.add(new JButton("Button " + i));

//  JPanel global = new JPanel(new GridBagLayout());
//  GridBagConstraints gbc = new GridBagConstraints();
//  gbc.gridy = 0;
//  global.add(p1, gbc);
//  gbc.gridy++;
//  global.add(p2, gbc);
//  gbc.gridy++;
//  global.add(p3, gbc);

    JPanel global = new JPanel();
    Box vb = Box.createVerticalBox();
    vb.add(p1);
    vb.add(Box.createVerticalStrut(10));
    vb.add(p2);
    vb.add(Box.createVerticalStrut(10));
    vb.add(p3);
    global.add(vb);

    f.add(global);
    f.setVisible(true);

}

}

If you have any idea how to proceed...

Thank you!

3
  • Why have you commented GridBagLayout? Just use it. Read How to Use GridBagLayout
    – Braj
    Commented Aug 19, 2014 at 20:28
  • I'd go with the JGoodies FormLayout. It can handle this very easily and flexibly. Commented Aug 19, 2014 at 20:33
  • @user3218114 I can't use both BoxLayout and GridBagLayout at the same time. But each of them give the same result: the components are not wrap, and when the window is to narrow, I can't see every button.
    – R2B2
    Commented Aug 19, 2014 at 20:44

1 Answer 1

3

For you layout you need to make sure that the panel will fill the horizontal space when the frame is resized.

However, you still can't use the FlowLayout because FlowLayout does not recalculate the preferred size of the panel as the components wrap. Instead you need to use the Wrap Layout which will recalculate the preferred size.

Here is the updated example with "panel 2" using the WrapLayout and the GridBagLayout changes:

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

public class Example2 {

private static final int NB1 = 5;
private static final int NB2 = 13;
private static final int NB3 = 15;

public static void main(String[] args) {

    JFrame f = new JFrame();
    f.setTitle("Example2");
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

    JPanel p1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
    p1.setBorder(new TitledBorder(new LineBorder(Color.BLACK), "JPanel 1"));
    for(int i=0; i<NB1; i++)
        p1.add(new JButton("Button " + i));

//    JPanel p2 = new JPanel(new FlowLayout(FlowLayout.CENTER));
    JPanel p2 = new JPanel(new WrapLayout(FlowLayout.CENTER));
    p2.setBorder(new TitledBorder(new LineBorder(Color.BLACK), "JPanel 2"));
    for(int i=NB1; i<NB2; i++)
        p2.add(new JButton("Button " + i));

    JPanel p3 = new JPanel(new FlowLayout(FlowLayout.CENTER));
    p3.setBorder(new TitledBorder(new LineBorder(Color.BLACK), "JPanel 3"));
    for(int i=NB2; i<NB3; i++)
        p3.add(new JButton("Button " + i));

    JPanel global = new JPanel(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.fill = GridBagConstraints.HORIZONTAL; // added
    gbc.weightx = 1.0f; // added
    gbc.gridy = 0;
    global.add(p1, gbc);
    gbc.gridy++;
    global.add(p2, gbc);
    gbc.gridy++;
    global.add(p3, gbc);

    f.add(global);
    f.pack();
    f.setVisible(true);

}

}
1
  • It works well indeed. It would be perfect if I can stop the JPanel to grow in width once every component is on the same line. But I am still happy with this solution. Thank you very much.
    – R2B2
    Commented Aug 19, 2014 at 21:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.