Java - 具有水平滚动的垂直“FlowLayout”

时间:2011-11-19 19:09:40

标签: java swing jframe jpanel layout-manager

如标题中所述,我一直在尝试使用水平滚动设置垂直流布局。布局中的组件将是JLabel。让我画一幅画:

+-------------------------+   <--- window
|Label1   Label4    Label7|
|Label2   Label5    Label8|   <--- labels
|Label3   Label6    Label9|
|<===============>========|   <--- scrollbar
+-------------------------+

同一窗口,垂直扩展

+--------------------------+   <--- window
|Label1   Label5    Label9 |
|Label2   Label6    Label10|   <--- labels
|Label3   Label7    Label11|
|Label4   Label8    Label12|
|<===================>=====|   <--- scrollbar
+--------------------------+

因此,标签将填充可用的垂直空间,然后创建一个新列。一旦可用的水平空间耗尽,就会出现水平滚动条。

通常不应出现垂直滚动条;但是,如果窗口的垂直高度非常小,那么有一个垂直滚动条会很好。

非常感谢任何帮助。我是Java的新手,所以任何额外的解释都会很精彩。谢谢!

编辑:

根据以下回复,我现在正在处理: http://tips4java.wordpress.com/2008/11/06/wrap-layout/http://code.google.com/p/verticalflowlayout/

我让WrapLayout扩展了VerticalFlowLayout:

package LogicSim;

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

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

/**
* Constructs a new <code>WrapLayout</code> with a left
* alignment and a default 5-unit horizontal and vertical gap.
*/
public VerticalWrapLayout()
{
    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 VerticalWrapLayout(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 VerticalWrapLayout(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)
    {
        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;
}
}

这是我的框架设置:

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(300, 300);
    frame.setVisible(true);


    JPanel panel = new JPanel();
    panel.setLayout( new VerticalWrapLayout(0) );

    JScrollPane pane = new JScrollPane(panel);
    frame.add( pane, BorderLayout.CENTER );

    for (int i=0; i < 80; i++ ) {
        panel.add( new JLabel( "Label" + i ) );
    }

现在,这会按照我之后的方式在垂直列中设置标签,但它仍会创建垂直滚动条。在修改VerticalWrapLayout类时,我非常不稳定。另外,我真的不明白JScrollPane如何与这些类进行交互。有关如何进行的任何建议吗?


解决了!请参阅下面的答案以及我的回答。

4 个答案:

答案 0 :(得分:15)

以下是VerticalFlowLayout的示例。它是FlowLayout类的一个副本,其中一些逻辑被改为“垂直”导向而不是“水平”导向:

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

/**
 * A flow layout arranges components in a directional flow, much
 * like lines of text in a paragraph. The flow direction is
 * determined by the container's <code>componentOrientation</code>
 * property and may be one of two values:
 * <ul>
 * <li><code>ComponentOrientation.TOP_TO_BOTTOM</code>
 * <li><code>ComponentOrientation.BOTTOM_TO_TOP</code>
 * </ul>
 * Flow layouts are typically used
 * to arrange buttons in a panel. It arranges buttons
 * horizontally until no more buttons fit on the same line.
 * The line alignment is determined by the <code>align</code>
 * property. The possible values are:
 * <ul>
 * <li>{@link #TOP TOP}
 * <li>{@link #BOTTOM BOTTOM}
 * <li>{@link #CENTER CENTER}
 * <li>{@link #LEADING LEADING}
 * <li>{@link #TRAILING TRAILING}
 * </ul>
 * <p>
 */
public class VerticalFlowLayout implements LayoutManager, java.io.Serializable
{
    /**
     * This value indicates that each row of components
     * should be left-justified.
     */
    public static final int TOP     = 0;

    /**
     * This value indicates that each row of components
     * should be centered.
     */
    public static final int CENTER    = 1;

    /**
     * This value indicates that each row of components
     * should be right-justified.
     */
    public static final int BOTTOM     = 2;

    /**
     * <code>align</code> is the property that determines
     * how each column distributes empty space.
     * It can be one of the following three values:
     * <ul>
     * <code>TOP</code>
     * <code>BOTTOM</code>
     * <code>CENTER</code>
     * </ul>
     *
     * @see #getAlignment
     * @see #setAlignment
     */
    int align;     // This is the one we actually use

    /**
     * The flow layout manager allows a seperation of
     * components with gaps.  The horizontal gap will
     * specify the space between components and between
     * the components and the borders of the
     * <code>Container</code>.
     *
     * @see #getHgap()
     * @see #setHgap(int)
     */
    int hgap;

    /**
     * The flow layout manager allows a seperation of
     * components with gaps.  The vertical gap will
     * specify the space between rows and between the
     * the rows and the borders of the <code>Container</code>.
     *
     * @see #getHgap()
     * @see #setHgap(int)
     */
    int vgap;

    /**
     * Constructs a new <code>VerticalFlowLayout</code> with a centered alignment and a
     * default 5-unit horizontal and vertical gap.
     */
    public VerticalFlowLayout()
    {
        this(CENTER, 5, 5);
    }

    /**
     * Constructs a new <code>VerticalFlowLayout</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>VerticalFlowLayout.TOP</code>, <code>VerticalFlowLayout.BOTTOM</code>,
     * or <code>VerticalFlowLayout.CENTER</code>
     * @param align the alignment value
     */
    public VerticalFlowLayout(int align)
    {
        this(align, 5, 5);
    }

    /**
     * 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>VerticalFlowLayout.TOP</code>, <code>VerticalFlowLayout.BOTTOM</code>,
     * or <code>VerticalFlowLayout.CENTER</code>.
     * @param     align   the alignment value
     * @param     hgap  the horizontal gap between components
     *                   and between the components and the
     *                   borders of the <code>Container</code>
     * @param     vgap  the vertical gap between components
     *                   and between the components and the
     *                   borders of the <code>Container</code>
     */
    public VerticalFlowLayout(int align, int hgap, int vgap)
    {
        this.hgap = hgap;
        this.vgap = vgap;
        setAlignment(align);
    }

    /**
     * Gets the alignment for this layout.
     * Possible values are <code>VerticalFlowLayout.TOP</code>,
     * <code>VerticalFlowLayout.BOTTOM</code> or <code>VerticalFlowLayout.CENTER</code>,
     * @return   the alignment value for this layout
     * @see     java.awt.VerticalFlowLayout#setAlignment
     * @since     JDK1.1
     */
    public int getAlignment()
    {
        return align;
    }

    /**
     * Sets the alignment for this layout. Possible values are
     * <ul>
     * <li><code>VerticalFlowLayout.TOP</code>
     * <li><code>VerticalFlowLayout.BOTTOM</code>
     * <li><code>VerticalFlowLayout.CENTER</code>
     * </ul>
     * @param     align one of the alignment values shown above
     * @see     #getAlignment()
     * @since     JDK1.1
     */
    public void setAlignment(int align)
    {
        this.align = align;
    }

    /**
     * Gets the horizontal gap between components
     * and between the components and the borders
     * of the <code>Container</code>
     *
     * @return   the horizontal gap between components
     *           and between the components and the borders
     *           of the <code>Container</code>
     * @see     java.awt.VerticalFlowLayout#setHgap
     * @since     JDK1.1
     */
    public int getHgap() {
        return hgap;
    }

    /**
     * Sets the horizontal gap between components and
     * between the components and the borders of the
     * <code>Container</code>.
     *
     * @param hgap the horizontal gap between components
     *           and between the components and the borders
     *           of the <code>Container</code>
     * @see     java.awt.VerticalFlowLayout#getHgap
     * @since     JDK1.1
     */
    public void setHgap(int hgap) {
        this.hgap = hgap;
    }

    /**
     * Gets the vertical gap between components and
     * between the components and the borders of the
     * <code>Container</code>.
     *
     * @return   the vertical gap between components
     *           and between the components and the borders
     *           of the <code>Container</code>
     * @see     java.awt.VerticalFlowLayout#setVgap
     * @since     JDK1.1
     */
    public int getVgap() {
        return vgap;
    }

    /**
     * Sets the vertical gap between components and between
     * the components and the borders of the <code>Container</code>.
     *
     * @param vgap the vertical gap between components
     *           and between the components and the borders
     *           of the <code>Container</code>
     * @see     java.awt.VerticalFlowLayout#getVgap
     */
    public void setVgap(int vgap) {
        this.vgap = vgap;
    }

    /**
     * Adds the specified component to the layout.
     * Not used by this class.
     * @param name the name of the component
     * @param comp the component to be added
     */
    public void addLayoutComponent(String name, Component comp) {
    }

    /**
     * Removes the specified component from the layout.
     * Not used by this class.
     * @param comp the component to remove
     * @see    java.awt.Container#removeAll
     */
    public void removeLayoutComponent(Component comp) {
    }

    /**
     * Returns the preferred dimensions for this layout given the
     * <i>visible</i> components in the specified target container.
     *
     * @param target the container that needs to be laid out
     * @return  the preferred dimensions to lay out the
     *          subcomponents of the specified container
     * @see Container
     * @see #minimumLayoutSize
     * @see    java.awt.Container#getPreferredSize
     */
    public Dimension preferredLayoutSize(Container target)
    {
    synchronized (target.getTreeLock())
    {
        Dimension dim = new Dimension(0, 0);
        int nmembers = target.getComponentCount();
        boolean firstVisibleComponent = true;

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

            if (m.isVisible())
            {
                Dimension d = m.getPreferredSize();
                dim.width = Math.max(dim.width, d.width);

                if (firstVisibleComponent)
                {
                    firstVisibleComponent = false;
                }
                else
                {
                    dim.height += vgap;
                }

                dim.height += d.height;
            }
        }

        Insets insets = target.getInsets();
        dim.width += insets.left + insets.right + hgap*2;
        dim.height += insets.top + insets.bottom + vgap*2;
        return dim;
    }
    }

    /**
     * Returns the minimum dimensions needed to layout the <i>visible</i>
     * components contained in the specified target container.
     * @param target the container that needs to be laid out
     * @return  the minimum dimensions to lay out the
     *          subcomponents of the specified container
     * @see #preferredLayoutSize
     * @see    java.awt.Container
     * @see    java.awt.Container#doLayout
     */
    public Dimension minimumLayoutSize(Container target)
    {
    synchronized (target.getTreeLock())
    {
        Dimension dim = new Dimension(0, 0);
        int nmembers = target.getComponentCount();
        boolean firstVisibleComponent = true;

        for (int i = 0 ; i < nmembers ; i++)
        {
            Component m = target.getComponent(i);
            if (m.isVisible())
            {
                Dimension d = m.getMinimumSize();
                dim.width = Math.max(dim.width, d.width);

                if (firstVisibleComponent)
                {
                    firstVisibleComponent = false;
                }
                else
                {
                    dim.height += vgap;
                }

                dim.height += d.height;
            }
        }


        Insets insets = target.getInsets();
        dim.width += insets.left + insets.right + hgap*2;
        dim.height += insets.top + insets.bottom + vgap*2;
        return dim;
    }
    }

    /**
     * Lays out the container. This method lets each
     * <i>visible</i> component take
     * its preferred size by reshaping the components in the
     * target container in order to satisfy the alignment of
     * this <code>VerticalFlowLayout</code> object.
     *
     * @param target the specified component being laid out
     * @see Container
     * @see    java.awt.Container#doLayout
     */
    public void layoutContainer(Container target)
    {
    synchronized (target.getTreeLock())
    {
        Insets insets = target.getInsets();
        int maxHeight = target.getSize().height - (insets.top + insets.bottom + vgap*2);
        int nmembers = target.getComponentCount();
        int x = insets.left + hgap;
        int y = 0;
        int columnWidth = 0;
        int start = 0;

        boolean ttb = target.getComponentOrientation().isLeftToRight();

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

            if (m.isVisible())
            {
                Dimension d = m.getPreferredSize();
                m.setSize(d.width, d.height);

                if ((y == 0) || ((y + d.height) <= maxHeight))
                {
                    if (y > 0)
                    {
                        y += vgap;
                    }

                    y += d.height;
                    columnWidth = Math.max(columnWidth, d.width);
                }
                else
                {
                    moveComponents(target, x, insets.top + vgap, columnWidth, maxHeight - y, start, i, ttb);
                    y = d.height;
                    x += hgap + columnWidth;
                    columnWidth = d.width;
                    start = i;
                }
            }
        }

        moveComponents(target, x, insets.top + vgap, columnWidth, maxHeight - y, start, nmembers, ttb);
    }
    }

    /**
     * Centers the elements in the specified row, if there is any slack.
     * @param target the component which needs to be moved
     * @param x the x coordinate
     * @param y the y coordinate
     * @param width the width dimensions
     * @param height the height dimensions
     * @param columnStart the beginning of the column
     * @param columnEnd the the ending of the column
     */
    private void moveComponents(
        Container target, int x, int y, int width, int height, int columnStart, int columnEnd, boolean ttb)
    {
        switch (align)
        {
            case TOP:
                y += ttb ? 0 : height;
                break;
            case CENTER:
                y += height / 2;
                break;
            case BOTTOM:
                y += ttb ? height : 0;
                break;
        }

        for (int i = columnStart ; i < columnEnd ; i++)
        {
            Component m = target.getComponent(i);

            if (m.isVisible())
            {
                int cx;
                cx = x + (width - m.getSize().width) / 2;

                if (ttb)
                {
                    m.setLocation(cx, y);
                }
                else
                {
                    m.setLocation(cx, target.getSize().height - y - m.getSize().height);
                }

                y += m.getSize().height + vgap;
            }
        }
    }

    /**
     * Returns a string representation of this <code>VerticalFlowLayout</code>
     * object and its values.
     * @return   a string representation of this layout
     */
    public String toString()
    {
        String str = "";

        switch (align)
        {
            case TOP:    str = ",align=top"; break;
            case CENTER: str = ",align=center"; break;
            case BOTTOM: str = ",align=bottom"; break;
        }

        return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + "]";
    }


    public static void main(String[] args)
    {
        JPanel main = new JPanel( new BorderLayout() );

        final JPanel buttons = new JPanel(new VerticalFlowLayout() );
//      buttons.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        main.add(buttons, BorderLayout.CENTER);

        for (int i = 0; i < 7; i++)
        {
            buttons.add( new JRadioButton("button " + i) );
        }

        JButton button = new JButton("Add Radio Button");
        main.add(button, BorderLayout.SOUTH);
        button.addActionListener( new ActionListener()
        {
            private int i = 8;

            public void actionPerformed(ActionEvent e)
            {
                buttons.add( new JRadioButton("button R Us" + i++) );
                buttons.revalidate();
//              pack();
            }
        });

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(main);
        frame.setSize(300, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }


}

理论上你应该能够使用WrapLayout并让它扩展这个类,然后自定义代码也是垂直方向的。

编辑:

  

我让WrapLayout扩展了VerticalFlowLayout:

您不能只扩展VerticalFlowLayout。 WrapLayout代码用于根据父容器的大小计算固定宽度。您需要更改计算固定高度的行为。我没有尝试过,但基本上你需要将“width”相关变量引用更改为“height”和“height”相关变量引用“width”,这样代码就可以在垂直维度而不是水平维度上工作。

答案 1 :(得分:10)

以下是我使用过的修改过的VerticalWrapLayout,以防有人感兴趣!

package LogicSim;

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

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

/**
* Constructs a new <code>WrapLayout</code> with a left
* alignment and a default 5-unit horizontal and vertical gap.
*/
public VerticalWrapLayout()
{
    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 VerticalWrapLayout(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 VerticalWrapLayout(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.height -= (getVgap() + 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 targetHeight = target.getSize().height;

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

    int hgap = getHgap();
    int vgap = getVgap();
    Insets insets = target.getInsets();
    int verticalInsetsAndGap = insets.top + insets.bottom + (vgap * 2);
    int maxHeight = targetHeight - verticalInsetsAndGap;

    //  Fit components into the allowed height

    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 (rowHeight + d.height > maxHeight)
            {
                addColumn(dim, rowWidth, rowHeight);
                rowWidth = 0;
                rowHeight = 0;
            }

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

            if (rowHeight != 0)
            {
                rowHeight += vgap;
            }

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

    addColumn(dim, rowWidth, rowHeight);

    dim.height += verticalInsetsAndGap;
    dim.width += insets.left + insets.right + hgap * 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)
    {
        dim.height -= (vgap + 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 addColumn(Dimension dim, int rowWidth, int rowHeight)
{
    dim.height = Math.max(dim.height, rowHeight);

    if (dim.width > 0)
    {
        dim.width += getHgap();
    }

    dim.width += rowWidth;
}
}

全部谢谢!

答案 2 :(得分:8)

您可以使用BoxLayout

例如:

enter image description here

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class CustomFrame extends JFrame
{

    private int labelCounter = 0;
    private int maxLabels = 3;
    private Box box;
    private JPanel pane;

    public CustomFrame()
    {
        super("Custom JFrame");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pane = new JPanel();
        pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
        JScrollPane scr = new JScrollPane(pane);
        add(scr);

        for(int i = 1; i <= 15; i++) addNewLabel("Label " + i);

        setSize(200,130);
        setVisible(true);
    }

    private void addNewLabel(String s)
    {
        if(labelCounter % maxLabels == 0)
        {
            box = Box.createVerticalBox();
            box.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
        }
        box.add(new JLabel(s));
        pane.add(box);
        labelCounter++;
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new CustomFrame();
            }
        });

    }
}

答案 3 :(得分:7)

我调查了你的问题,就我看到的那样,有多个VerticalFlowLayouts不可以包装,而且还有wrappableFlowLayouts,它们不是垂直的。

我没有将这些放在一起(聪明人会做什么),而是根据你的答案写了一个糟糕的解决方法。它完成了工作,但遗憾的是它并没有像我想要的那样光滑/可靠。但我还以为我发布了它。

public class CustomFrame extends JFrame {

private int borderWidth = 10;
private int labelCounter = 0;
private Box box;
private JPanel pane;
private List<JLabel> registeredLabels = new ArrayList<JLabel>();

public CustomFrame() {
    super("Custom JFrame");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pane = new JPanel();
    pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
    JScrollPane scrollPane = new JScrollPane(pane);
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
    add(scrollPane);
    setSize(200, 130);

    // this just calls the method reAddAllLabels() upon resizing
    this.addComponentListener(new ComponentListener() {

        @Override
        public void componentShown(ComponentEvent e) {
            // ignore
        }

        @Override
        public void componentResized(ComponentEvent e) {
            reAddAllLabels();
            repaint();
        }

        @Override
        public void componentMoved(ComponentEvent e) {
            // ignore
        }

        @Override
        public void componentHidden(ComponentEvent e) {
            // ignore
        }
    });

    setVisible(true);
}

/**
 * Build the Label, register the Label in the Label-List, add the Label through further method
 * 
 * @param text
 *            for the new Label
 */
public void addNewLabel(String text) {
    JLabel myJLabel = new JLabel(text);
    registeredLabels.add(myJLabel);
    addLabel(myJLabel);
}

/**
 * Reset stuff, add all registered Labels
 * 
 */
private void reAddAllLabels() {
    labelCounter = 0;
    pane.removeAll();
    if (registeredLabels.size() > 0) {
        for (JLabel label : registeredLabels) {
            addLabel(label);
        }
    }
}

/**
 * Calculate max-Labels per Column, eventually create new Box, add Label to box
 * 
 * @param label
 */
private void addLabel(JLabel label) {
    int maxLabels = (pane.getHeight() - borderWidth * 2) / label.getPreferredSize().height;
    if (labelCounter % maxLabels == 0) {
        box = Box.createVerticalBox();
        box.setBorder(BorderFactory.createEmptyBorder(borderWidth, borderWidth, borderWidth, borderWidth));
    }
    box.add(label);
    pane.add(box);
    labelCounter++;
}

/**
 * How to use the frame
 * 
 * @param args
 */
public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            CustomFrame customFrame = new CustomFrame();

            for (int i = 1; i <= 20; i++) {
                customFrame.addNewLabel("Label " + i);
            }
        }
    });
}
}