1

来自 BorderLayout javadoc:

边界布局布置了一个容器,对其组件进行排列和调整大小以适应五个区域:北、南、东、西和中心。每个区域可能包含不超过一个组件,并由相应的常量标识:NORTH、SOUTH、EAST、WEST 和 CENTER。

我有一个基于另一个 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() 的一个和两个调用——这两个按钮的行为相同。

原始问题的发布者通过在添加第二个组件之前删除第一个组件来解决他的问题,但我想了解该程序中仍然引用第一个按钮的位置。任何人都可以帮忙吗?

4

2 回答 2

1

我将尝试回答我自己的问题,主要基于 kleopatra 和 AndrewThompson 的有用评论。

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

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

我认为这很不幸。这是我第一次遇到组件可以在容器中但不能在布局管理器中的情况,事实上这是我第一次考虑这样的事情。我将它们视为两个密切交互的对象,而不是我需要帮助管理其协调的一对。

如果我知道向谁建议的话,我会建议加强 BorderLayout javadoc 并提及用户有责任不要将两个组件放在一个区域中。

于 2013-09-07T15:27:13.757 回答
0

我有同样的问题。我放弃了BorderLayout,而是使用了JInternalFrame. JInternalFrame创建 a 的JFrame内部JFramesetContentPane()它可以使用然后刷新它来替换它的所有组件。

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();
于 2020-11-09T16:56:39.330 回答