Why does the first panel added to a frame disappear?

自闭症网瘾萝莉.ら 提交于 2019-11-26 02:21:34
  • The default layout of a JFrame (or more specifically in this case, the content pane of the frame) is a BorderLayout.
  • When adding a component to a BordeLayout with no constraint, the Swing API will put the component in the CENTER.
  • A BorderLayout can contain exactly one component in each of the 5 layout constraints.
  • 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.

As to what would be a better approach depends on the specific needs of the user interface.

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.

Not strictly true.

The BorderLayout will only reset the bounds (ie size and location) of the last component added to a specific constraint location. This is different from other layout managers in that they will reset the bounds of all components in the container.

In the example code the red panel was the "active" panel at the time the frame was validated by using the pack() method and therefore only its bound were set and therefore only it was painted.

For a demonstration of this process run the example below using the following steps:

  1. Click on the "Add Panel in Center" button, nothing appears to happen even though the blue panel was added to the center.
  2. Move the mouse over the red panel and the buttons will appear because the mouse rollover logic will cause the buttons to be repainted.
  3. Now increase the frame width and the blue panel will appear under the red panel.

The code:

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

When the blue panel is added to the BorderLayout and when the revalidate() is invoked the bounds of the blue panel are set.

However, because of the way Swing does ZOrder painting the blue panel is painted first and then the red panel is painted on top of the blue panel. The green panel still has a size of (0, 0) since it was never the "active" panel in the BorderLayout.CENTER when the frame was initially validated with the pack() method.

When the frame is resized, the blue panel being the "active" panel in the BorderLayout.CENTER, has its bounds adjusted, so it will now fill the extra space in the frame.

Now for another test:

  1. pack() the frame after adding the green panel to the frame.
  2. run the code and increase the width of the frame and the red and green frame will appear
  3. then click the button and increase the width and now all 3 panels will appear

Bottom line is still the same:

Don't try to add multiple panels to the same constraint of a BorderLayout. If you do, then make sure you remove the previous panel or you have the potential for unexpected results.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!