【问题标题】:How can I get FlowLayout to align JPanels at the bottom like it does for other components?如何让 FlowLayout 像其他组件一样在底部对齐 JPanel?
【发布时间】:2016-08-23 21:33:15
【问题描述】:

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

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 表现相同?

【问题讨论】:

    标签: java swing layout layout-manager flowlayout


    【解决方案1】:

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

    没有基线的组件会居中

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

    我无法从您的问题中判断您是否真的试图将所有文本置于基线上,而与字体大小无关,或者您是否只是试图将所有组件绘制在面板底部。

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

    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,那么您将需要使用每个组件的约束。

    【讨论】:

    • 谢谢。我意识到我的意图是以基线(而不是整个组件)为中心,因此覆盖面板以返回其组件的基线可能是我想要的。最终,我的应用程序只是将一堆标签组合在一起,因此覆盖应该不错。谢谢。
    【解决方案2】:

    我自己,我会为此使用比 FlowLayout 更“魅力”的布局,例如 GridBagLayout。如果你使用它,你可以将anchor设置为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);
        }
    

    【讨论】:

      【解决方案3】:

      在考虑了如何在没有 GridBagLayout 的情况下完成之后,我想出了这个,尽管它有点“hackish”:

              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 垂直扩展的方法,而且我把事情弄得太复杂了。

      【讨论】:

        猜你喜欢
        • 2012-03-14
        • 2021-04-11
        • 2015-07-06
        • 2012-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多