为什么添加到框架中的第一个面板会消失?

Why does the first panel added to a frame disappear?

下面是将两个面板添加到框架的示例。只出现一个面板(第二个,红色面板)。

为什么第一个面板消失了?

import java.awt.Color;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class DisappearingPanelInFrame {

    DisappearingPanelInFrame() {
        JFrame f = new JFrame(this.getClass().getSimpleName());
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        f.add(getColoredPanel(Color.GREEN));
        f.add(getColoredPanel(Color.RED));

        f.pack();
        f.setVisible(true);
    }

    private JPanel getColoredPanel(Color color) {
        JPanel p = new JPanel();
        p.setBackground(color);
        p.setBorder(new EmptyBorder(20, 150, 20, 150));
        return p;
    }

    public static void main(String[] args) {
        Runnable r = DisappearingPanelInFrame::new;
        SwingUtilities.invokeLater(r);
    }
}
  • JFrame(或更具体地说,在本例中,框架的 内容窗格)的默认布局是 BorderLayout
  • 在没有约束的情况下向 BordeLayout 添加组件时,Swing API 会将组件放入 CENTER.
  • 一个 BorderLayout 可以在 5 个布局约束中的每一个中恰好包含 一个 组件。
  • 当将第二个组件添加到 BorderLayout 的相同(在本例中为 CENTER)约束时,Java 的此实现将显示 last添加组件。

至于什么是更好的方法取决于用户界面的具体需求。

When a second component is added to the same (in this case CENTER) constraint of a BorderLayout, this implementation of Java will display the last component added.

不完全正确。

BorderLayout只会将reset the bounds(即大小和位置)的最后一个组件添加到特定的约束位置。这与其他布局管理器的不同之处在于它们会重置容器中所有组件的边界。

在示例代码中,在使用 pack() 方法验证框架时,红色面板是 "active" 面板,因此只设置了它的边界,因此只绘制了它。

为了演示此过程 运行 下面的示例使用以下步骤:

  1. 单击 "Add Panel in Center" 按钮,即使蓝色面板已添加到中心,但似乎没有任何反应。
  2. 将鼠标移到红色面板上,按钮就会出现,因为鼠标悬停逻辑会导致按钮重新绘制。
  3. 现在增加框架宽度,蓝色面板将出现在红色面板下方。

代码:

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

public class DisappearingPanelInFrame {

    DisappearingPanelInFrame()
    {

        JButton button = new JButton ("Add Panel In Center");
        button.addActionListener( new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                JPanel blue = new JPanel();
                blue.setBackground( Color.BLUE );
                blue.add( new JButton("Button 1") );
                blue.add( new JButton("Button 2") );

                Component c = (Component)e.getSource();
                Window window = SwingUtilities.windowForComponent(c);
                window.add(blue );
                window.revalidate();
                window.repaint();
            }
        });

        JFrame f = new JFrame(this.getClass().getSimpleName());
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        f.add(new ColoredPanel(Color.GREEN));
        //f.pack();
        f.add(new ColoredPanel(Color.RED));
        f.add(button, BorderLayout.SOUTH);

        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                new DisappearingPanelInFrame();
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

class ColoredPanel extends JPanel {

    ColoredPanel(Color color) {
        setBackground(color);
        setBorder(new EmptyBorder(20, 150, 20, 150));
    }
}

将蓝色面板添加到 BorderLayout 并调用 revalidate() 时,将设置蓝色面板的边界。

但是,由于 Swing 执行 ZOrder 绘制的方式,首先绘制蓝色面板,然后在蓝色面板之上绘制红色面板。绿色面板的大小仍然为 (0, 0),因为当最初使用 pack() 方法验证框架时,它从来不是 BorderLayout.CENTER 中的 "active" 面板。

调整框架大小时,蓝色面板是 BorderLayout.CENTER 中的 "active" 面板,其边界已调整,因此现在它将填充框架中额外的 space .

现在进行另一个测试:

  1. pack() 将绿色面板添加到框架后的框架。
  2. 运行代码,增加边框的宽度,就会出现红绿边框
  3. 然后单击按钮并增加宽度,现在将显示所有 3 个面板

Bottom line is still the same:

不要尝试将多个面板添加到 BorderLayout 的同一约束。如果这样做,请确保移除之前的面板,否则可能会出现意外结果。