swing flowlayout PreferredSize 不会自动更改

Dar*_*ari 5 java swing layout-manager flowlayout border-layout

我想要一个FlowLayoutforMyPanel来添加一些任意按钮。我添加MyPanelJFramenorth(JFrame有一个BorderLayout)。我的问题是:
当里面的按钮MyPanel占据超过一行时,它们不会显示。
换句话说,preferredSizeofMyPanel不会自动改变以显示其全部内容。它只显示一排按钮。

 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{

  }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

当我进行更改MyPanel以覆盖getPreferredSize并设置恒定大小时,它可以正常工作。

public static class MyPanel extends JPanel{

    @Override
    public Dimension getPreferredSize(){
        return new Dimension(-1,100);
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但我希望它自动工作。
任何帮助将不胜感激。

Dar*_*ari 2

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

\n\n
    \n
  • 确定容器的首选尺寸
  • \n
  • 根据布局规则对容器中的组件进行布局
  • \n
\n\n

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

\n\n

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

\n\n

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

\n\n
 buttons.setLayout(new WrapLayout());\n
Run Code Online (Sandbox Code Playgroud)\n\n

在此输入图像描述
\n随着框架尺寸变小,按钮面板的高度将增加,蓝色面板的高度将减小:

\n\n

在此输入图像描述

\n\n

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

\n\n

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

\n\n
buttons.setSize(new Dimension(300, 1));\n
Run Code Online (Sandbox Code Playgroud)\n\n

整个代码WrapLayout

\n\n
import java.awt.*;\nimport javax.swing.JScrollPane;\nimport javax.swing.SwingUtilities;\n\n/**\n*  FlowLayout subclass that fully supports wrapping of components.\n*/\npublic class WrapLayout extends FlowLayout\n{\nprivate Dimension preferredLayoutSize;\n\n/**\n* Constructs a new <code>WrapLayout</code> with a left\n* alignment and a default 5-unit horizontal and vertical gap.\n*/\npublic WrapLayout()\n{\n    super();\n}\n\n/**\n* Constructs a new <code>FlowLayout</code> with the specified\n* alignment and a default 5-unit horizontal and vertical gap.\n* The value of the alignment argument must be one of\n* <code>WrapLayout</code>, <code>WrapLayout</code>,\n* or <code>WrapLayout</code>.\n* @param align the alignment value\n*/\npublic WrapLayout(int align)\n{\n    super(align);\n}\n\n/**\n* Creates a new flow layout manager with the indicated alignment\n* and the indicated horizontal and vertical gaps.\n* <p>\n* The value of the alignment argument must be one of\n* <code>WrapLayout</code>, <code>WrapLayout</code>,\n* or <code>WrapLayout</code>.\n* @param align the alignment value\n* @param hgap the horizontal gap between components\n* @param vgap the vertical gap between components\n*/\npublic WrapLayout(int align, int hgap, int vgap)\n{\n    super(align, hgap, vgap);\n}\n\n/**\n* Returns the preferred dimensions for this layout given the\n* <i>visible</i> components in the specified target container.\n* @param target the component which needs to be laid out\n* @return the preferred dimensions to lay out the\n* subcomponents of the specified container\n*/\n@Override\npublic Dimension preferredLayoutSize(Container target)\n{\n    return layoutSize(target, true);\n}\n\n/**\n* Returns the minimum dimensions needed to layout the <i>visible</i>\n* components contained in the specified target container.\n* @param target the component which needs to be laid out\n* @return the minimum dimensions to lay out the\n* subcomponents of the specified container\n*/\n@Override\npublic Dimension minimumLayoutSize(Container target)\n{\n    Dimension minimum = layoutSize(target, false);\n    minimum.width -= (getHgap() + 1);\n    return minimum;\n}\n\n/**\n* Returns the minimum or preferred dimension needed to layout the target\n* container.\n*\n* @param target target to get layout size for\n* @param preferred should preferred size be calculated\n* @return the dimension to layout the target container\n*/\nprivate Dimension layoutSize(Container target, boolean preferred)\n{\nsynchronized (target.getTreeLock())\n{\n    //  Each row must fit with the width allocated to the containter.\n    //  When the container width = 0, the preferred width of the container\n    //  has not yet been calculated so lets ask for the maximum.\n\n    int targetWidth = target.getSize().width;\n\n    if (targetWidth == 0)\n        targetWidth = Integer.MAX_VALUE;\n\n    int hgap = getHgap();\n    int vgap = getVgap();\n    Insets insets = target.getInsets();\n    int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);\n    int maxWidth = targetWidth - horizontalInsetsAndGap;\n\n    //  Fit components into the allowed width\n\n    Dimension dim = new Dimension(0, 0);\n    int rowWidth = 0;\n    int rowHeight = 0;\n\n    int nmembers = target.getComponentCount();\n\n    for (int i = 0; i < nmembers; i++)\n    {\n        Component m = target.getComponent(i);\n\n        if (m.isVisible())\n        {\n            Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();\n\n            //  Can\'t add the component to current row. Start a new row.\n\n            if (rowWidth + d.width > maxWidth)\n            {\n                addRow(dim, rowWidth, rowHeight);\n                rowWidth = 0;\n                rowHeight = 0;\n            }\n\n            //  Add a horizontal gap for all components after the first\n\n            if (rowWidth != 0)\n            {\n                rowWidth += hgap;\n            }\n\n            rowWidth += d.width;\n            rowHeight = Math.max(rowHeight, d.height);\n        }\n    }\n\n    addRow(dim, rowWidth, rowHeight);\n\n    dim.width += horizontalInsetsAndGap;\n    dim.height += insets.top + insets.bottom + vgap * 2;\n\n    //  When using a scroll pane or the DecoratedLookAndFeel we need to\n    //  make sure the preferred size is less than the size of the\n    //  target containter so shrinking the container size works\n    //  correctly. Removing the horizontal gap is an easy way to do this.\n\n    Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);\n\n    if (scrollPane != null && target.isValid())\n    {\n        dim.width -= (hgap + 1);\n    }\n\n    return dim;\n}\n}\n\n/*\n *  A new row has been completed. Use the dimensions of this row\n *  to update the preferred size for the container.\n *\n *  @param dim update the width and height when appropriate\n *  @param rowWidth the width of the row to add\n *  @param rowHeight the height of the row to add\n */\nprivate void addRow(Dimension dim, int rowWidth, int rowHeight)\n{\n    dim.width = Math.max(dim.width, rowWidth);\n\n    if (dim.height > 0)\n    {\n        dim.height += getVgap();\n    }\n\n    dim.height += rowHeight;\n}\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n

  • 请考虑将此代码的原始作者归功于此,并提供一个指向您复制/粘贴此信息的位置的链接。 (6认同)