BorderLayout - 替换BorderLayout组件

时间:2013-09-07 12:37:53

标签: java swing jframe layout-manager border-layout

来自BorderLayout javadoc:

  

边框布局布置一个容器,安排并调整其大小   适合五个地区的组成部分:北,南,东,西,和   中央。每个区域可能包含不超过一个组件,并且是   由相应的常数识别:NORTH,SOUTH,EAST,WEST和   中心。

我有一个基于another SO question的程序,它在BorderLayout中心创建一个包含按钮的JFrame UI,等待5秒,然后将不同的按钮放在相同的位置。由于声明(每个区域可能包含不超过一个组件“,我希望第二个按钮替换第一个。但是,原始按钮仍然”悬挂“。这是代码:

import java.awt.BorderLayout;
import java.awt.Component;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class ReplaceBorderLayoutComponent extends JFrame
{
  private static final long serialVersionUID = 1L;

  public static void say(String msg) { System.out.println(msg); }

    public void createUI()
    {
      setDefaultCloseOperation(DISPOSE_ON_CLOSE);
      try
      {
        SwingUtilities.invokeAndWait
        (
            new Runnable()
            {
              public void run()
              {
//                setLayout(new BorderLayout());
                JButton longText = new JButton("Quite a long text");
                /*getContentPane().*/add(longText, BorderLayout.CENTER);
                pack();
                setVisible(true);
                say("longText = " + longText.toString());
              }
            }
        );
      }
      catch (Exception e) {}
    }

    public void replaceComponent()
    {
      try
      {
        SwingUtilities.invokeAndWait
        (
            new Runnable()
            {
              public void run()
              {
                JButton anotherText = new JButton("Another text");
                /*getContentPane().*/add(anotherText, BorderLayout.CENTER);
                pack();
                validate();
                repaint();
                say("anotherText = " + anotherText.toString());
              }
            }
        );
      }
      catch (Exception e)      {      }
      say("replaced");
    }

    public Component getComponent(String constraint)
    {
      BorderLayout bl = (BorderLayout)getContentPane().getLayout();
      return bl.getLayoutComponent(constraint);
    }

    public static void main(String ... args) 
    { 
        ReplaceBorderLayoutComponent st = new ReplaceBorderLayoutComponent();
        st.createUI();
        try { Thread.sleep(5000); } catch (InterruptedException ie) {}
        st.replaceComponent();
        Component c = st.getComponent(BorderLayout.CENTER);
        say("Center component = " + c.toString());

        String otherPlaces[] = { "North", "South", "East", "West", "First", "Last", "Before", "After" };
        for (String s : otherPlaces)
        {
          Component c2 = st.getComponent(s);
          if (c2 != null) { say("found additional component at " + s + ", " + c2.toString()); }
        }
    }
}

当我运行它时,第一个按钮适当占据框架的所有空间。如果我调整它的大小,它会按预期扩展。当延迟代码运行时,它会将第二个按钮放在框架中,但如果我展开框架,我可以看到两个按钮。第二个按钮按中心组件的正常情况展开;第一个按钮保持与添加第二个按钮时的大小相同(例如,如果我在添加之前展开框架,则展开)。

添加后,将鼠标悬停在第二个按钮上会隐藏第一个按钮;调整框架的大小会重新显示第一个框架的第一个。如果第一个按钮不可见,则将鼠标悬停在其位置上,至少有时会显示它。

我必须得出结论,第一个按钮仍然是某个框架布局的一部分(例如,它显示了被点击时的默认动画),但我无法弄清楚在哪里。我有代码确保它不在任何其他BorderLayout组件中,并且中心组件确实是第二个按钮。

我删除了一个和两个对pack()的调用 - 与两个按钮相同的行为。

原始问题的海报通过在添加第二个组件之前移除第一个组件来解决他的问题,但我想了解第一个按钮在此程序中仍被引用的位置。有人可以帮忙吗?

2 个答案:

答案 0 :(得分:1)

我主要根据kleopatra和AndrewThompson的有用评论来回答我自己的问题。

BorderLayout文档说“每个区域可能只包含一个组件”;显然没有代码可以强制执行此操作,用户可以这样做。

我对程序行为的最佳猜测:当第二个组件添加到容器中时,它会适当地放在borderlayout的“center”区域(它有自己对组件的引用)。第一个组件仍然在容器中,但不在布局中,因此它仍然可以呈现并可能出现在其他项目的顶部或下面;行为没有真正定义,因为它不再由布局容器管理。

我认为这很不幸;这是我遇到的第一个案例,一个组件可以在容器中但不在布局管理器中,事实上它是我第一次想到这样的事情。我认为它们是两个密切相互作用的对象,而不是一对我需要帮助管理的协调。

如果我知道应该向谁建议,我建议对BorderLayout javadoc提及用户不要将两个组件放入一个区域的责任。

答案 1 :(得分:0)

我有同样的问题。我放弃了BorderLayout,而是使用了JInternalFrameJInternalFrameJFrame内创建一个JFrame。它可以使用setContentPane()替换其所有组件,然后刷新。

import java.awt.*;
import java.swing.*;

JFrame F = new JFrame();
JInternalFrame f = new JInternalFrame();

//Build outer frame
F.setBounds(100, 100, 500, 500);
F.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
F.getContentPane().setLayout(null);

//Build inner frame
f.setVisible(true);
f.setBounds(120, 120, 120, 120);
F.add(f);

//Replace content of inner frame
f.setContentPane(JComponent);
f.revalidate();
f.repaint();