I have a JPanel containing a few components, laying them out with a FlowLayout, so that they will wrap if necessary and i want to center this JPanel in a JFrame. I tried to use a BoxLayout with a VerticalGlue, but it doesn't center it completely. Here is a simple SSCCE, which demonstrates my problem, because i dont think i can explain it well:
import javax.swing.*;
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
public Test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
getContentPane().add(Box.createVerticalGlue());
JPanel panel = new JPanel();
panel.add(new JButton("New button"));
panel.add(new JButton("New button"));
getContentPane().add(panel);
setVisible(true);
}
}
If the window is wide enough to fit both buttons next to each other, it almost seems centered:
But if its too small you can clearly see my problem:
The problem is that the JPanel takes the lower half of the JFrame and the Glue the upper half:
I have tried other LayoutManagers aswell, but I couldn't fix this problem yet.
EDIT:
With a BorderLayout and the JPanel placed in the center the buttons appear at the top because the JPanel expands to the size of the ContentPane of the JFrame:
With a GridBagLayout it looks perfect with everything next to each other. But if the components are wrapped they disappear:
Using a MigLayout, the buttons wont wrap anymore:
EDIT: The solution i used is a combination of the Wrap Layout with the GridBagLayout:
import java.awt.*;
import javax.swing.*;
class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
Test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWeights = new double[]{1.0};
getContentPane().setLayout(gridBagLayout);
JPanel panel = new JPanel(new WrapLayout());
GridBagConstraints gbc_panel = new GridBagConstraints();
gbc_panel.fill = GridBagConstraints.HORIZONTAL;
getContentPane().add(panel, gbc_panel);
panel.add(new JButton("New button"));
panel.add(new JButton("New button"));
setVisible(true);
}
}
The problem is that the BoxLayout will allow components to grow up to the maximum size of the component. In the case of a panel, the maximum size is the maximum Integer value so both the glue and the panel get equal amounts of space. So if you want to use a BoxLayout, you need to override the
getMaximumSize()
method to return the preferred size of the panel.After the above change you then need to use verticalGlue twice:
Now you will have equal amounts of space above and below the panel. However, this still won't work when components wrap to the next line because the
FlowLayout
does not recalculate the height based on the wrapped components. So in this case you can replace theFlowLayout
with the Wrap Layout which simply extendsFlowLayout
to calculate the wrapped height correctly.Or instead of using a BoxLayout, you can use a GridBagLayout. By default components added to the GridBagLayout will be centered horizontally and vertically. You would still need the panel with the
WrapLayout