Java 如何使包含FlowLayout的JPanel居中?

Java 如何使包含FlowLayout的JPanel居中?,java,swing,jpanel,layout-manager,Java,Swing,Jpanel,Layout Manager,我有一个包含一些组件的JPanel,用FlowLayout将它们布局,以便在必要时进行包装,我想将这个JPanel放在JFrame的中心。 我尝试使用带有垂直胶水的BoxLayout,但它不能完全居中。 下面是一个简单的SSCCE,它演示了我的问题,因为我认为我不能很好地解释它: import javax.swing.*; public class Test extends JFrame { public static void main(String[] args) {

我有一个包含一些组件的JPanel,用FlowLayout将它们布局,以便在必要时进行包装,我想将这个JPanel放在JFrame的中心。 我尝试使用带有垂直胶水的BoxLayout,但它不能完全居中。 下面是一个简单的SSCCE,它演示了我的问题,因为我认为我不能很好地解释它:

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);
    }
}
如果窗口足够宽,可以将两个按钮相邻放置,则窗口看起来几乎居中:

但如果太小,您可以清楚地看到我的问题:

问题在于,JPanel将JFrame的下半部分和上半部分粘合在一起:

我也尝试过其他的裁员经理,但我还不能解决这个问题

编辑:

当BorderLayout和JPanel位于中间时,按钮出现在顶部,因为JPanel扩展到JFrame的ContentPane大小:

GridBagLayout使所有东西彼此相邻,看起来非常完美。但如果组件被包裹,它们就会消失:

使用MigLayout,按钮将不再换行:

编辑:
我使用的解决方案结合了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);
    }
}

您可以使用此代码将包含FlowLayout的JPanel居中

setLayout(new FlowLayout(FlowLayout.CENTER));

您可以使用此代码将包含FlowLayout的JPanel居中

setLayout(new FlowLayout(FlowLayout.CENTER));
问题在于,JPanel将JFrame的下半部分和上半部分粘合在一起:

问题是BoxLayout将允许组件增长到组件的最大尺寸。在面板的情况下,最大大小是最大整数值,因此胶水和面板获得相等的空间量。因此,如果要使用BoxLayout,需要重写
getMaximumSize()
方法以返回面板的首选大小

我尝试使用带有垂直胶水的BoxLayout,但它不能完全居中

进行上述更改后,您需要使用verticalGlue两次:

Box box = new Box.createVerticalBox(); 
box.add( Box.createVerticalGlue() );
box.add( panel );
box.add( Box.createVerticalGlue() );
现在,面板上方和下方的空间相等。但是,当组件换行到下一行时,这仍然不起作用,因为
FlowLayout
不会基于换行的组件重新计算高度。所以在这种情况下,您可以用扩展的
FlowLayout
替换
FlowLayout
,以正确计算包裹高度

或者,您可以使用GridBagLayout,而不是使用BoxLayout。默认情况下,添加到GridBagLayout的组件将水平和垂直居中。您仍然需要带有
WrapLayout

问题在于,JPanel将JFrame的下半部分和上半部分粘合在一起:

问题是BoxLayout将允许组件增长到组件的最大尺寸。在面板的情况下,最大大小是最大整数值,因此胶水和面板获得相等的空间量。因此,如果要使用BoxLayout,需要重写
getMaximumSize()
方法以返回面板的首选大小

我尝试使用带有垂直胶水的BoxLayout,但它不能完全居中

进行上述更改后,您需要使用verticalGlue两次:

Box box = new Box.createVerticalBox(); 
box.add( Box.createVerticalGlue() );
box.add( panel );
box.add( Box.createVerticalGlue() );
现在,面板上方和下方的空间相等。但是,当组件换行到下一行时,这仍然不起作用,因为
FlowLayout
不会基于换行的组件重新计算高度。所以在这种情况下,您可以用扩展的
FlowLayout
替换
FlowLayout
,以正确计算包裹高度


或者,您可以使用GridBagLayout,而不是使用BoxLayout。默认情况下,添加到GridBagLayout的组件将水平和垂直居中。您仍然需要带有
WrapLayout

的面板。下面是一个使用。我不得不搞乱包裹面板的最大尺寸,这有点像黑客,但我认为这足以让你指向正确的方向

public class Test extends JFrame {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new BorderLayout());

        JPanel boxPanel = new JPanel();
        boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
        boxPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN, 1));

        JPanel wrapPanel = new JPanel();

        // hack of panel max size
        wrapPanel.setMaximumSize(new Dimension(99999, 0));
        wrapPanel.setBorder(BorderFactory.createLineBorder(Color.RED, 1));
        wrapPanel.setLayout(new WrapLayout(FlowLayout.CENTER));
        wrapPanel.add(new JButton("New button"));
        wrapPanel.add(new JButton("New button"));

        boxPanel.add(Box.createGlue());     
        boxPanel.add(wrapPanel);
        boxPanel.add(Box.createGlue());     

        add(boxPanel, BorderLayout.CENTER);

        setVisible(true);
    }
}

下面是一个使用的示例。我不得不搞乱包裹面板的最大尺寸,这有点像黑客,但我认为这足以让你指向正确的方向

public class Test extends JFrame {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new BorderLayout());

        JPanel boxPanel = new JPanel();
        boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
        boxPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN, 1));

        JPanel wrapPanel = new JPanel();

        // hack of panel max size
        wrapPanel.setMaximumSize(new Dimension(99999, 0));
        wrapPanel.setBorder(BorderFactory.createLineBorder(Color.RED, 1));
        wrapPanel.setLayout(new WrapLayout(FlowLayout.CENTER));
        wrapPanel.add(new JButton("New button"));
        wrapPanel.add(new JButton("New button"));

        boxPanel.add(Box.createGlue());     
        boxPanel.add(wrapPanel);
        boxPanel.add(Box.createGlue());     

        add(boxPanel, BorderLayout.CENTER);

        setVisible(true);
    }
}

我会尝试将FlowLayout嵌套在BorderLayout的中心…如果这些是面板上唯一的组件,并且您希望精确地确定它们的位置,我建议使用NullLayout(setLayout(null))并使用setBounds()。为了解决调整大小的问题,只需使setBounds()方法的参数与JFrame的大小成比例。@javaislife
我建议使用NullLayout(setLayout(null))并使用setBounds()。
:最糟糕的建议。永远不要使用空布局!简单地用gridbaglayout和默认约束将面板包装到周围的面板中,OP wantsI将使用
MigLayout
来实现这一点,以及其他任何情况。我会尝试将FlowLayout嵌套在BorderLayout的中心…如果这些是面板上唯一的组件,并且您希望它们的位置精确,我建议使用NullLayout(setLayout(null))和setBounds()。为了解决调整大小的问题,只需使setBounds()方法的参数与JFrame的大小成比例。@javaislife
我建议使用NullLayout(setLayout(null))并使用setBounds()。
:最糟糕的建议。永远不要使用空布局!只需使用gridbaglayout和默认约束将面板包装到周围的面板中,OP wantsI将使用
MigLayout
,以及其他任何情况。这将仅使JPanel水平居中,而不是垂直居中。我希望JPanel在两个方向上都居中。这只会使JPa居中