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 中有效。
我试图创建一个 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 中有效。