java.awt.Component、setVisible()、LayoutManager 的奇怪行为

Curious behavior of java.awt.Component, setVisible(), LayoutManager

我试图创建一个 GUI,发现 java.awt.Component 有一些奇怪的行为。我想通过外部事件 setVisible(true)/setVisible(false) 一个 java.awt.Component。但这仅在要切换的组件一开始就已经可见时才有效。附件中,我提供了我的问题的最小副本。

package test;

import java.awt.Button;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public final class Test {
    public static void main(String[] args) {
        Button testButton = new Button("Test Button");
        testButton.setVisible(false); /* Removing this line makes the code to work as intended, but why? */
        
        Frame mainFrame = new Frame("Test");
        mainFrame.setMinimumSize(new Dimension(640, 480));
        mainFrame.setVisible(true);
        mainFrame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent event) {
                System.exit(0);
            }
        });
        
        mainFrame.add(testButton);
        
        mainFrame.setMenuBar(new MenuBar());
        mainFrame.getMenuBar().add(new Menu("Test"));
        mainFrame.getMenuBar().getMenu(0).add(new MenuItem("Show/Hide \"Test Button\""));
        mainFrame.getMenuBar().getMenu(0).getItem(0).addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                if(testButton.isVisible()) testButton.setVisible(false);
                else testButton.setVisible(true);
                System.out.println("testButton.getBounds()" + testButton.getBounds()); /* EDIT: Added this line for debugging. */
                System.out.println("testButton.isVisible() " + testButton.isVisible());
            }
        });
    }
}

当您删除行 testButton.setVisible(false); 时,testButton 是可见的,并且在其可见状态下也是可切换的,否则不是。有谁知道为什么?也许布局管理器不适用于不可见的组件?

编辑:布局管理器似乎没有 setBounds(...) 不可见组件,但为什么呢?

Maybe the layout-manager doesn't work with invisible components?

正确,这取决于布局管理器的规则。

例如FlowLayout和BoxLayout,在布局时忽略不可见的组件。但是,GridLayout 将保留 space.

使用 Swing 更改组件的 属性 时,应自动调用布局管理器。因此调用 setVisible() 应该会导致新的布局。

但是,如果布局不是自动完成的,那么您可以使用如下代码:

testButton.getParent().revalidate();

我已经有十多年没有使用 AWT 了,但我记得 AWT 不如 Swing 智能,因此您需要使用:

testButton.getParent().validate();

设置按钮的可见状态后。至少它在您提供的 MRE 中有效。