Java - вертикальный «FlowLayout» с горизонтальной прокруткой

Как описано в заголовке, я пытался создать своего рода макет вертикального потока с горизонтальной прокруткой. Компоненты в макете будут JLabels. Позвольте мне нарисовать картинку:

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

/**
* Constructs a new FlowLayout with the specified
* alignment and a default 5-unit horizontal and vertical gap.
* The value of the alignment argument must be one of
* WrapLayout, WrapLayout,
* or WrapLayout.
* @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.
* 

* The value of the alignment argument must be one of * WrapLayout, WrapLayout, * or WrapLayout. * @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 * visible 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 visible * 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 взаимодействует с этими классами. Есть предложения, как действовать?


Решено! Пожалуйста, посмотрите ответы ниже, а также мой ответ.

17
задан Eng.Fouad 24 February 2013 в 15:18
поделиться