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

Tags: ,



I was trying to create a GUI and found some curious behavior of java.awt.Component. I wanted to setVisible(true)/setVisible(false) an java.awt.Component by an external Event. But this only works when the to be switched Component was already visible in the first place. Attached, I provided a minimal replica of my problem.

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());
            }
        });
    }
}

When you remove line testButton.setVisible(false);, testButton is viewable and also switchable in its state of visibility, otherwise not. Does anyone know why? Maybe the layout-manager doesn’t work with invisible components?

EDIT: It seems the layout-manager doesn’t setBounds(...) for invisible components, but why?

Answer

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

Correct, it depends on the rules of the layout manager.

For example the FlowLayout and BoxLayout, ignore invisible components when doing the layout. However, a GridLayout will reserve space.

When using Swing changing a property of a component should automatically invoke the layout manager. So invoking setVisible() should cause a new layout.

However, if layout is not done automatically then you would use code like:

testButton.getParent().revalidate();

I haven’t used AWT for over a decade now but as I recall AWT is not as smart as Swing so you need to use:

testButton.getParent().validate();

after setting the visible state of the button. At least it works in the MRE you provided.



Source: stackoverflow