【问题标题】:FlowLayout does not use multiple lines within GridBagLayoutFlowLayout 不在 GridBagLayout 中使用多行
【发布时间】:2011-11-08 11:17:09
【问题描述】:

通常,如果需要,FlowLayout 会使用多行。显然,如果具有 FlowLayout 的组件本身是 GridBagLayout 的一部分,则不会发生这种情况。

考虑这段代码:

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

public class Xyzzy extends JFrame{
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                Xyzzy frame = new Xyzzy();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                frame.setLayout(new GridBagLayout());

                JPanel top = new JPanel();
                top.setLayout(new FlowLayout());
                for (int i=1; i<=30; ++i)
                    top.add(new JLabel(String.format("Label #%d",i)));

                GridBagConstraints c = new GridBagConstraints();
                c.weightx = 1.0;
                c.gridwidth = GridBagConstraints.REMAINDER;
                c.anchor = GridBagConstraints.CENTER;

                frame.add(top,c);
                frame.add(new JLabel("Bottom"),c);

                //top.setPreferredSize(new Dimension(500,300));

                frame.setSize(600, 600);
                frame.setVisible(true);
            }
        });
    }
}

此代码旨在将 JLabels “Label #1”、“Label #2”等显示在多行上,但实际上它只使用了一行。

我可以通过在上述代码中调用 setPreferredSize 之前删除“//”来强制它使用多行,但这需要我同时设置宽度和高度,我不知道要设置什么高度利用。 (我不能使用 FontMetrics 来计算高度,因为在我的实际情况下,JLabels 实际上是不同大小的小型 JPanel。)

那么有没有办法强制 FlowLayout 使用多行呢? (或者,当组件的宽度已知时,有没有办法计算组件所需的高度?)

【问题讨论】:

  • 您考虑过使用其他布局管理器吗?

标签: java swing


【解决方案1】:

尝试添加约束参数:

c.weighty = 1.0;
c.fill = GridBagConstraints.VERTICAL;

它应该允许带有FlowLayout的面板在垂直方向上增长。

【讨论】:

  • 它必须工作,在添加组件之前检查你设置的约束参数。
  • 糟糕,我在将您的代码复制到我的代码时出错了。我诚挚的歉意!是的,您的更正确实有效,谢谢。
【解决方案2】:

据我所知,FlowLayout 确实需要首选尺寸才能实际包裹任何东西。我创建了一个子类,它将首选大小作为父容器的宽度,然后是所需的任何高度:

public class WrappingFlowLayout extends FlowLayout {
@Override
public Dimension preferredLayoutSize(Container target) {
    synchronized (target.getTreeLock()) {
        Dimension result;
        int w = target.getWidth();

        if (w == 0) {
            // The container hasn't been assigned any size yet; just behave like a regular flow layout.
            result = super.preferredLayoutSize(target);
        } else {
            Insets insets = target.getInsets();
            int wrapW = w - insets.left - insets.right;
            int maxW = 0; // Width of the widest row.
            int rowH = 0; // Current row height.
            int x = 0;
            int y = 0;
            boolean firstVisibleComponent = true;

            for (Component c : target.getComponents()) {
                if (c.isVisible()) {
                    Dimension d = c.getPreferredSize();
                    if (firstVisibleComponent) {
                        x = d.width + (getHgap() * 2);
                        y = getVgap();
                        rowH = d.height;
                        firstVisibleComponent = false;
                    } else if (x + d.width + getHgap() <= wrapW) {
                        // Add to current row.
                        x += d.width + getHgap();
                        rowH = Math.max(rowH, d.height);
                    } else {
                        // New row.
                        x = d.width + (getHgap() * 2);
                        y += rowH + getVgap();
                        rowH = d.height;
                    }
                    maxW = Math.max(maxW, x);
                }
            }
            y += rowH + getVgap();

            result = new Dimension(maxW + insets.left + insets.right, y + insets.top + insets.bottom);
        }
        return result;
    }
}
}

请注意,您需要监听父组件(代码中的top)上的调整大小事件并触发首选大小的更新。你最好的选择可能是ComponentListener

【讨论】:

  • 不,这不起作用。如果我在我的程序中使用你的代码有两个问题:首先,当窗口打开时我仍然只看到一行。但是一旦我调整窗口大小,所有的行都会显示出来。其次(更重要的是),在调整窗口大小时,如果我减小窗口大小,线条会很好地环绕,但如果我增加窗口大小,则不会发生任何事情。
  • 编辑了关于监听面板调整大小事件的注释。如果您添加该部分,很确定它应该可以工作。
  • 我不确定如何触发对首选尺寸的更新。我在top 中添加了ComponentListener,并在其componentResized 方法中调用了top.invalidate()。这意味着我现在在程序启动时会看到多行,但它不会在窗口增长时导致重新计算首选大小。
  • 这听起来应该有效,但不知道为什么没有。无论如何,现在你已经接受了尤金的回答,所以现在没有实际意义!
猜你喜欢
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
  • 2012-04-29
  • 1970-01-01
  • 2019-03-17
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
相关资源
最近更新 更多