我希望FlowLayout
MyPanel
添加一些任意按钮。我将MyPanel
添加到JFrame
北方(JFrame有BorderLayout
)。我的问题是:
当MyPanel
内的按钮占据多行时,不会显示它们
换句话说,preferredSize
的{{1}}不会自动更改以显示其全部内容。它只显示一行按钮。
MyPanel
当我更改 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
但我想让它自动运作 任何帮助将不胜感激。
答案 0 :(得分:2)
发生这种情况的原因在于你正在筑巢
两位布局经理。不同的是,遇到了
行为是FlowLayout
和BorderLayout
的结果
经理们一起工作。
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());
随着框架尺寸变小,按钮面板的高度将增加,蓝色面板将减小:
当面板添加到滚动窗格时,滚动窗格的大小不会更改,但水平和垂直滚动条将根据需要显示。
布局管理器的初始首选大小计算仍假设所有组件都将显示在一行中。因此,如果你打包()框架,首选宽度可能过多。您可以使用以下方法限制容器的宽度:
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;
}
}