FlowLayout 的意外行为

Unexpected behavior of FlowLayout

我正在使用 JPanel 和默认的 FlowLayout 布局管理器。我认为万一应用程序 window 被调整大小并且没有足够的宽度在一行中显示 JPanel 中的所有组件,一些组件将被移动到另一行。

此假设基于文档:

If the horizontal space in the container is too small to put all the components in one row, the FlowLayout class uses multiple rows.

https://docs.oracle.com/javase/tutorial/uiswing/layout/flow.html

它在某些情况下有效。例如,在使用此代码并减小 window 宽度时,按钮将位于不同的行:

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

public class FlowLayoutExpected {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();

        JButton button1 = new JButton("Button 1");
        JButton button2 = new JButton("Button 2");
        JButton button3 = new JButton("Button 3");

        panel.add(button1);
        panel.add(button2);
        panel.add(button3);

        frame.getContentPane().add(BorderLayout.CENTER, panel);

        frame.setSize(350, 70);
        frame.setVisible(true);
    }
}

减少宽度之前 -> 减小宽度后

但是将一个 JPanel 放入另一个 JPanel 就足够了,布局管理器将停止按预期运行:

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

public class FlowLayoutReal {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        JPanel outerPanel = new JPanel();
        JPanel innerPanel = new JPanel();

        JButton button1 = new JButton("Button 1");
        JButton button2 = new JButton("Button 2");
        JButton button3 = new JButton("Button 3");

        innerPanel.add(button1);
        innerPanel.add(button2);
        innerPanel.add(button3);

        outerPanel.add(innerPanel);
        frame.getContentPane().add(BorderLayout.CENTER, outerPanel);

        frame.setSize(350, 70);
        frame.setVisible(true);
    }
}

减少宽度之前 -> 减小宽度后

我想澄清我的误解。


我阅读了很多关于使用 WrapLayout 而不是 FlowLayout 的建议。这似乎是合理的,但我仍然不清楚为什么我在上面的示例中出现不一致的行为。

frame.getContentPane().add(BorderLayout.CENTER, panel);

首先,自 JDK1.1 以来,该方法已 "obsolete"。

此后的首选方法是添加 "constraint" 作为第二个参数:

frame.getContentPane().add(panel, BorderLayout.CENTER);

But it is enough to put one JPanel into another JPanel and layout manager stops to behave as expected:

代码按预期工作。问题是你的期望。

更改第一个示例中的代码:

//frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.getContentPane().add(panel, BorderLayout.PAGE_START);

现在,当您减小宽度时,组件就会消失。这是因为 BorderLayout.PAGE_START 将尊重添加的组件的首选高度。首选高度由在一行中显示所有组件决定。

But it is enough to put one JPanel into another JPanel and layout manager stops to behave as expected

开始包装面板时,您需要了解其中的含义。

FlowLayout 尊重添加的所有组件的首选大小。因此,内部面板中的组件都按预期显示在一行中。

当您将外部面板添加到 BorderLayout.CENTER 时,外部面板的大小会调整,但不会影响内部面板,因为 FlowLayout 的规则会显示添加的任何组件在面板的顶部。由于内面板是单个组件,因此没有任何包裹。

这是一个经常被用来确保组件保持其首选大小的优势的技巧。

再举个例子。也许您在要添加到 BorderLayout.PAGE_START.

的面板上有水平 GridLayout 按钮

如果您直接添加面板,那么按钮的大小将随着框架的改变而shrink/grow。

如果您希望按钮大小保持不变,您可以使用 "wrapper" 面板。然后 "wrapper" 面板大小 shrinks/grows,但按钮大小保持不变。

您需要了解布局管理器的规则才能有效地使用它。