如何让FlowLayout将JPanels与其他组件对齐?

时间:2016-08-23 21:33:16

标签: java swing layout layout-manager flowlayout

我有一个案例,我将JPanels添加到FlowLayout,他们没有将自己与布局的底部对齐。我正在使用这个layout.setAlignOnBaseline(true)并且它正确地将JLabel对齐到面板的底部。然而,一旦这些标签被包裹在面板中,它就不再起作用了。这是我的意思的一个例子,顶部和底部有两个面板。

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

public class BadLayout {

    private static final Font font1 = new Font("Arial", Font.BOLD, 14);
    private static final Font font2 = new Font("Arial", Font.BOLD, 30);

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Bad layout");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            FlowLayout layout = new FlowLayout(FlowLayout.LEADING, 0, 0);
            layout.setAlignOnBaseline(true);

            JPanel topPanel = new JPanel();
            topPanel.setLayout(layout);
            topPanel.setBackground(Color.BLACK);
            for (int i = 0; i < 10; i++) {
                JLabel label = new JLabel("Foo");
                label.setForeground(Color.WHITE);
                label.setBackground(Color.RED);
                label.setOpaque(true);
                label.setFont(i % 2 == 0 ? font1 : font2);

                JPanel subPanel = new JPanel();
                subPanel.setLayout(layout);
                subPanel.setBackground(Color.RED);
                subPanel.add(label);
                subPanel.setAlignmentY(Component.BOTTOM_ALIGNMENT);

                topPanel.add(subPanel);
            }

            JPanel bottomPanel = new JPanel();
            bottomPanel.setLayout(layout);
            bottomPanel.setBackground(Color.DARK_GRAY);
            for (int i = 0; i < 10; i++) {
                JLabel label = new JLabel("Foo");
                label.setForeground(Color.WHITE);
                label.setBackground(Color.RED);
                label.setOpaque(true);
                label.setFont(i % 2 == 0 ? font1 : font2);
                bottomPanel.add(label);
            }

            JPanel parentPanel = new JPanel();
            parentPanel.setLayout(new BorderLayout());
            parentPanel.add(topPanel, BorderLayout.NORTH);
            parentPanel.add(bottomPanel, BorderLayout.SOUTH);

            frame.getContentPane().add(parentPanel);
            frame.pack();
            frame.setVisible(true);
        });
    }
}

如果运行此代码,您会注意到顶部面板的面板中心有较小的“Foo”,而底部的那个具有我希望的“底部对齐”行为。任何想法如何让子JPanel表现相同?

3 个答案:

答案 0 :(得分:7)

setAlignOnBaseline(...)方法的API声明:

没有基线的组件将居中

JPanel没有合理的基线可供使用,因为组件可以在多行上,具体取决于所使用的布局管理器。所以它是中心的。

我无法从您的问题中判断出您是否实际上试图将所有文本居中在基线上而与字体大小无关,或者您是否只是想在面板的底部绘制所有组件。< / p>

如果您尝试在基线上居中文本,那么您可以使用以下代码覆盖面板的基线:

JPanel subPanel = new JPanel()
{
    @Override
    public int getBaseline(int width, int height)
    {
        Component c = getComponent(0);
        return c.getBaseline(width, height);
    }
};

当然,只有当面板上的所有组件具有相同的基线时,这才有效。

或者,如果您只是尝试将所有组件放置在面板底部,那么您需要使用不同的布局管理器。

您可以使用Relative Layout将所有组件对齐到底部。

它可以直接替代现有代码:

RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS, 0);
rl.setAlignment( RelativeLayout.TRAILING );
JPanel topPanel = new JPanel(rl);

或者,如果您不想使用非JDK类,那么BoxLayoutGridBagLayout将成为可能。

如果您使用BoxLayout,则需要使用每个组件的setAlignmentY(...)属性。

如果您使用GridBagLayout,则需要使用每个组件的约束。

答案 1 :(得分:2)

我自己,我会使用比FlowLayout更多“oomph”的布局,例如GridBagLayout。如果您使用它,您可以将锚设置为SOUTH,并将weighty设置为0.0,这样可以防止组件拉伸其高度并将其固定在底部。例如:

   JPanel topPanel = new JPanel();
    // topPanel.setLayout(layout);
    topPanel.setLayout(new GridBagLayout());
    topPanel.setBackground(Color.BLACK);
    for (int i = 0; i < 10; i++) {
        JLabel label = new JLabel("Foo");
        label.setForeground(Color.WHITE);
        label.setBackground(Color.RED);
        label.setOpaque(true);
        label.setFont(i % 2 == 0 ? font1 : font2);

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = i;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.weighty = 0.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.anchor = GridBagConstraints.SOUTH;

        JPanel subPanel = new JPanel();
        subPanel.setLayout(new BorderLayout());
        subPanel.setBackground(Color.RED);
        subPanel.add(label);
        subPanel.setPreferredSize(subPanel.getMinimumSize());
        // subPanel.setAlignmentY(Component.BOTTOM_ALIGNMENT);   
        topPanel.add(subPanel, gbc);
    }

答案 2 :(得分:2)

在考虑如何在没有GridBagLayout的情况下完成这项工作后,我想出了这一点,即使它有点&#39; hackish&#39;:

        JPanel topPanel = new JPanel();
        ((FlowLayout) topPanel.getLayout()).setAlignOnBaseline(true);
        topPanel.setBackground(Color.BLACK);

        int h = 0;
        for (int i = 0; i < 10; i++) {
            JLabel label = new JLabel("Foo");
            label.setForeground(Color.WHITE);
            label.setBackground(Color.GREEN);
            label.setOpaque(true);
            label.setFont(i % 2 == 0 ? font1 : font2);
            JPanel wrapBorder = new JPanel(new BorderLayout());
            JPanel subPanel = new JPanel();
            subPanel.setBackground(Color.RED);
            subPanel.add(label);
            subPanel.setBackground(Color.GREEN);
            wrapBorder.setOpaque(false);
            wrapBorder.add(BorderLayout.SOUTH, subPanel);
            if(wrapBorder.getPreferredSize().height > h) {
                h = wrapBorder.getPreferredSize().height;
            }
            topPanel.add(wrapBorder);
        }

        for(Component component : topPanel.getComponents()) {
            component.setPreferredSize(new Dimension(component.getPreferredSize().width, h));
        }

我这样做的唯一原因是因为我个人不能使用GridBagLayout,但它有其优点(可以看出;))。

我可能只是错过了让JPanel垂直展开的方法,而且我的内容很复杂。