swing flowlayout preferredSize不会自动更改

时间:2014-08-16 05:31:04

标签: java swing layout-manager border-layout flowlayout

我希望FlowLayout MyPanel添加一些任意按钮。我将MyPanel添加到JFrame北方(JFrame有BorderLayout)。我的问题是:
  当MyPanel内的按钮占据多行时,不会显示它们 换句话说,preferredSize的{​​{1}}不会自动更改以显示其全部内容。它只显示一行按钮。

MyPanel

enter image description here

当我更改 public class NewMain { public static void main(String[] args) { JFrame mainFrame = new JFrame(); mainFrame.getContentPane().setLayout(new BorderLayout()); mainFrame.setSize(new Dimension(500,500)); JPanel p1 = new MyPanel(); p1.setLayout(new FlowLayout()); mainFrame.add(p1,BorderLayout.NORTH); mainFrame.add(new JButton("center"),BorderLayout.CENTER); p1.add(new JButton("helllloo1")); p1.add(new JButton("helllloo2")); p1.add(new JButton("helllloo3")); p1.add(new JButton("helllloo4")); p1.add(new JButton("helllloo5")); p1.add(new JButton("helllloo6")); p1.add(new JButton("helllloo7")); mainFrame.setVisible(true); } public static class MyPanel extends JPanel{ } } 使其覆盖MyPanel并设置常量大小时,它可以正常工作。

getPreferredSize

enter image description here

但我想让它自动运作 任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

发生这种情况的原因在于你正在筑巢 两位布局经理。不同的是,遇到了 行为是FlowLayoutBorderLayout的结果 经理们一起工作。

FlowLayout让孩子保持他们喜欢的大小。首选 面板本身的大小取决于最高的高度 组件(首选高度)和子宽度的总和 (首选宽度)。

BorderLayout通过以下方式计算北区:它伸展 它的孩子从左到右(不尊重其首选宽度)和 将其高度设置为其子项的首选高度 (尊重其首选高度)。

因此BorderLayout会影响具有按钮的面板的行为方式。 它不允许为按钮创建第二行。 选择不同的布局管理器,如BoxLayout,按钮 不合适的行显示在另一行中。

补充意见:

mainFrame.getContentPane().setLayout(new BorderLayout());

JFrame's内容窗格的默认布局管理器是 BorderLayout,无需明确设置。

    JPanel p1 = new MyPanel();
    p1.setLayout(new FlowLayout());

实例化面板的默认管理器是FlowLayout。 因此,再次没有必要明确地设置它。

答案 1 :(得分:0)

布局管理器有两个主要功能:

  • 确定容器的首选大小
  • 根据布局规则布置容器中的组件

FlowLayout 是一种奇怪的动物。它完成了这两个功能。容器的首选大小假定所有组件将布置在一行中。当遇到容器的最大宽度时,布局代码会将组件包装到下一行。然而,问题在于功能不相互通信。将组件包装到新行时,首选大小不会更改,因此您永远不会在额外行上看到组件。

我们想要的是随着容器大小的改变而动态计算的首选大小。换句话说,随着容器宽度的变化,高度也需要重新计算。 WrapLayout扩展了FlowLayout以实现此功能。这将导致容器的首选大小与容器的布局同步。

在以下示例中,按钮面板添加到BorderLayout的北部,蓝色面板添加到中心。您使用WrapLayout与使用FlowLayout相同:

 buttons.setLayout(new WrapLayout());

enter image description here
随着框架尺寸变小,按钮面板的高度将增加,蓝色面板将减小:

enter image description here

当面板添加到滚动窗格时,滚动窗格的大小不会更改,但水平和垂直滚动条将根据需要显示。

布局管理器的初始首选大小计算仍假设所有组件都将显示在一行中。因此,如果你打包()框架,首选宽度可能过多。您可以使用以下方法限制容器的宽度:

buttons.setSize(new Dimension(300, 1));

WrapLayout的整个代码:

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

/**
*  FlowLayout subclass that fully supports wrapping of components.
*/
public class WrapLayout extends FlowLayout
{
private Dimension preferredLayoutSize;

/**
* Constructs a new <code>WrapLayout</code> with a left
* alignment and a default 5-unit horizontal and vertical gap.
*/
public WrapLayout()
{
    super();
}

/**
* Constructs a new <code>FlowLayout</code> with the specified
* alignment and a default 5-unit horizontal and vertical gap.
* The value of the alignment argument must be one of
* <code>WrapLayout</code>, <code>WrapLayout</code>,
* or <code>WrapLayout</code>.
* @param align the alignment value
*/
public WrapLayout(int align)
{
    super(align);
}

/**
* Creates a new flow layout manager with the indicated alignment
* and the indicated horizontal and vertical gaps.
* <p>
* The value of the alignment argument must be one of
* <code>WrapLayout</code>, <code>WrapLayout</code>,
* or <code>WrapLayout</code>.
* @param align the alignment value
* @param hgap the horizontal gap between components
* @param vgap the vertical gap between components
*/
public WrapLayout(int align, int hgap, int vgap)
{
    super(align, hgap, vgap);
}

/**
* Returns the preferred dimensions for this layout given the
* <i>visible</i> components in the specified target container.
* @param target the component which needs to be laid out
* @return the preferred dimensions to lay out the
* subcomponents of the specified container
*/
@Override
public Dimension preferredLayoutSize(Container target)
{
    return layoutSize(target, true);
}

/**
* Returns the minimum dimensions needed to layout the <i>visible</i>
* components contained in the specified target container.
* @param target the component which needs to be laid out
* @return the minimum dimensions to lay out the
* subcomponents of the specified container
*/
@Override
public Dimension minimumLayoutSize(Container target)
{
    Dimension minimum = layoutSize(target, false);
    minimum.width -= (getHgap() + 1);
    return minimum;
}

/**
* Returns the minimum or preferred dimension needed to layout the target
* container.
*
* @param target target to get layout size for
* @param preferred should preferred size be calculated
* @return the dimension to layout the target container
*/
private Dimension layoutSize(Container target, boolean preferred)
{
synchronized (target.getTreeLock())
{
    //  Each row must fit with the width allocated to the containter.
    //  When the container width = 0, the preferred width of the container
    //  has not yet been calculated so lets ask for the maximum.

    int targetWidth = target.getSize().width;

    if (targetWidth == 0)
        targetWidth = Integer.MAX_VALUE;

    int hgap = getHgap();
    int vgap = getVgap();
    Insets insets = target.getInsets();
    int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
    int maxWidth = targetWidth - horizontalInsetsAndGap;

    //  Fit components into the allowed width

    Dimension dim = new Dimension(0, 0);
    int rowWidth = 0;
    int rowHeight = 0;

    int nmembers = target.getComponentCount();

    for (int i = 0; i < nmembers; i++)
    {
        Component m = target.getComponent(i);

        if (m.isVisible())
        {
            Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();

            //  Can't add the component to current row. Start a new row.

            if (rowWidth + d.width > maxWidth)
            {
                addRow(dim, rowWidth, rowHeight);
                rowWidth = 0;
                rowHeight = 0;
            }

            //  Add a horizontal gap for all components after the first

            if (rowWidth != 0)
            {
                rowWidth += hgap;
            }

            rowWidth += d.width;
            rowHeight = Math.max(rowHeight, d.height);
        }
    }

    addRow(dim, rowWidth, rowHeight);

    dim.width += horizontalInsetsAndGap;
    dim.height += insets.top + insets.bottom + vgap * 2;

    //  When using a scroll pane or the DecoratedLookAndFeel we need to
    //  make sure the preferred size is less than the size of the
    //  target containter so shrinking the container size works
    //  correctly. Removing the horizontal gap is an easy way to do this.

    Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);

    if (scrollPane != null && target.isValid())
    {
        dim.width -= (hgap + 1);
    }

    return dim;
}
}

/*
 *  A new row has been completed. Use the dimensions of this row
 *  to update the preferred size for the container.
 *
 *  @param dim update the width and height when appropriate
 *  @param rowWidth the width of the row to add
 *  @param rowHeight the height of the row to add
 */
private void addRow(Dimension dim, int rowWidth, int rowHeight)
{
    dim.width = Math.max(dim.width, rowWidth);

    if (dim.height > 0)
    {
        dim.height += getVgap();
    }

    dim.height += rowHeight;
}
}

参考:http://tips4java.wordpress.com/2008/11/06/wrap-layout/