Kelvin的胡言乱语

==============> 重剑无锋,大巧不工。

剖析GroupLayout can only be used with one Container at a time异常的出现原因及解决方法

这是我第二个博客其中的一篇文章。

下面是原文(未大改,稍作了一些格式上的调整):


今天写一个小的Swing程序,使用 GroupLayout 布局时,出现了上述问题,出问题的代码大致如下:

...
GroupLayout mainLayout = new GroupLayout(this);
setLayout(mainLayout);
pack();
setSize(500, 400);
...

由于我的类继承了JFrame,所以上面的this指针是Container类型的,没有问题。

代码看来没有问题,但在运行时却报了标题中所写的异常,像往常一样去Google了一下,居然没找到合适的解决方法!我汗啊,看来大家平时都不怎么用Swing做东西的,这只有我自己解决了。

我尝试着修改了一下,将:

GroupLayout mainLayout = new GroupLayout(this);setLayout(mainLayout);

改为:

GroupLayout mainLayout = new GroupLayout(getContentPane());
getContentPane().setLayout(mainLayout);

结果成功运行了,没报错,好了,基本可以知道该怎么下手了。

getContentPane() 方法:

return getRootPane().getContentPane();

getRootPane() 方法:

return rootPane;

再查看 rootPaneJRootPane 类型,其 getContentPane() 方法 return contentPane; 是一个 Container ,好了,这算第一步。

下面查看 JFrame 的构造方法,调用 frameInit() ,而 frameInit() 调用了 setRootPane(createRootPane())setRootPane() 不用说,看 createRootPane()

JRootPane rp = new JRootPane();

果然是新new了一个rootPane!那么其中的Container肯定是新new的了,那就自然不是我自己的类,所以抛出标题中的异常现在可以理解一点了。

接着来,单步调试,发现在pack()处抛出异常,步入后继续,得到其抛出异常的相关调用如下:

Window.pack()
  -> Frame.addNotify()
  -> Window.addNotify()
  -> Window.super.addNotify()
  -> Container.super.addNotify()
  -> Component.invalidate()
  -> Container.invalidate()
  -> LayoutManager2.invalidateLayout(this) (注:此处this指向JRootPane中新new的Container)
  -> GroupLayout.checkParent(Container)
  -> if (parent != host) {
         throw new IllegalArgumentException("GroupLayout can only be used with one Container at a time");
     }

看见问题了,上面的host是new GroupLayout时传进去的,就是我自己写的类,而传给 checkParent() 的Container则是在JFrame中新new出来的JRootPane带的Container,二者根本不是一个类,自然会抛出异常了,不过从这个问题也说明了一点,一个GroupLayout是不能让两个Container共用的。

异常出现原因找到了,问题也就容易解决了,保证:

GroupLayout layout = new GroupLayout(xxx1);
xxx2.setLayout(mainLayout);

这两句中的xxx1和xxx2为同一个Container即可。


附:文中相关类的继承关系

我自己的类 -> JFrame -> Frame -> Window -> Container -> Component

Comments

comments powered by Disqus