今天记录两个内容:
1. JFrame在不同版本下面的add方法区别
2. JFrame的层次问题(如何在监听器中获取JFrame)
----------------------------------------------------------------------------------------------------------------
在做毕业设计的时候,经常要用到JFrame,这是一个可以在桌面上显示的组件,在网上查看使用方法和技巧的时候,一般对于Swing组件的使用是这样的描述:
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
与AWT组件不同,Swing组件不能直接添加到顶层容器中,它必须添加到一个与Swing顶层容器相
关联的内容面板(content pane)上。内容面板是顶层容器包含的一个普通容器,它是一个轻量
级组件。
即,把Swing组件放入一个顶层Swing容器的内容面板上。
---------------------------------------------------------------------------------------------
对JFrame添加组件有两种方式:
1、用getContentPane( )方法获得JFrame的内容面板,再对其加入组件:即,
frame.getContentPane().add(childComponent)
2、建立一个Jpanel或 JDesktopPane之类的中间容器,把组件添加到容器中,用
setContentPane()方法把该容器置为JFrame的内容面板,再向上面添加组件
---------------------------------------------------------------------------------------------
在翻我们原来学的教材时候(java程序设计教程
后来一次设计一个小窗口的时,我直接在JFrame上使用add(Component)来添加组件(我以为自己写的是一个JPanel),之后检查时发现这个问题,但我也很惊讶这样直接就把组件添加上去了。
查了API文档,发现原来JDK1.5以后的版本,JFrame中已经可以直接使用add方法添加组件,下面摘录不同版本API文档的描述:
JDK1.4:
For example, to add a child to an AWT frame you'd write:
frame.add(child);
However using JFrame you need to add the child to the JFrame's content pane instead:
frame.getContentPane().add(child);
The same is true for setting layout managers, removing components, listing children, and so on.
-----------------------------------
JDK1.5:
作为 add的便捷方法及其变体,已经重写了 remove和 setLayout,以在必要时将其转发到
contentPane。这意味着可以编写:
frame.add(child);
子级将被添加到 contentPane。
-----------------------------------
JDK1.6:
为了方便地使用 add及其变体,已经重写了 remove和 setLayout,以在必要时将其转发到
contentPane。这意味着可以编写:
frame.add(child);
子级将被添加到 contentPane。
这就一目了然了,从1.5开始,在JFrame使用add方法就可以直接将组件添加到默认ContentPane上,而不用在采用前文所说的第二种方法.
关于这个机制改变,是在接口 RootPaneContaine做的。可以看到,在JDK1.5中,这个接口的描述:
-----------------------------------------------------------
-----------------------------------------------------------
为了便于使用 JFrame、JDialog、JWindow、JApplet和 JInternalFrame,默认情况下,将 add、remove和 setLayout方法的所有调用转发到 contentPane。这意味着您可以调用:
rootPaneContainer.add(component);
而不是:
rootPaneContainer.getContentPane().add(component);
-------------------------------------------------
于是这个问题就很清晰了,我也得出一个经验,那就是一定要关注新版本的JDK,研究其与老版本之前的差别,这样才能更好的做开发。
·············································
(下面这个问题使用jdk1.5版本以上)
下面是我遇到的另一个问题,比如如下代码:(假设我已经有一个监听器handler)
JFrame frame = new JFrame();
button = new JButton("Test");
button.addActionListener(handler);
frame.add(button);
那么,当点击这个button时,在监听器的ActionPerformed(ActionEvent e)中要如何获取button所在的JFrame??(假设监听器是一个独立的实现ActionListener接口的类)
请看下图
这个图是我自己根据理解画的,展示了JFrame的层次。这也就是说,当点击button时,点击事件发生在上图JButton所在的层次上,如果想要根据这个button点击事件获取JFrame,自然就需要getParent() 4次
下面代码展示了这个过程:
public void actionPerformed(ActionEvent e) { JButton button = (JButton) e.getSource(); JPanel panel = (JPanel)button.getParent(); JLayeredPane layeredPane = (JLayeredPane)panel.getParent(); JRootPane rootPane = (JRootPane) layeredPane.getParent(); JFrame frame = (JFrame) rootPane.getParent(); }
这样最终才获取了JFrame。
关于上图中的JPanel的解释:如果直接用frame.add()方法添加button,那么该组件会添加到一个默认的ContentPane上面,也就是一个JPanel。
-------------------------------------------------------
-------------------------------------------------------
我使用frame的一些经验:
经验1--
在毕业设计后面的开发中,我改掉了直接用frame.add()方法添加组件的代码,因为我构思了一个功能:
(虽然后来没用)点击button改变ContentPane”
如果我使用默认面板,由于这个面板并没有名字,所以在我更换了contentPane后再想要改回原先的默认面板时,就无从下手了。(注:当然也可以在事先获取默认面板并保存)
所以说,建立一个Jpanel或 JDesktopPane之类的中间容器,把组件添加到容器中,用setContentPane()方法把该容器置为JFrame的内容面板是比较好的方式。我觉得这样更容易表达设计的思路。
----------------
经验2--
另外,我在设计的时候,要经常在监听器的事件处理方法中改变各种面板的内容,比如我想要操作一个JFrame,那么,如果使用上面给出的代码来获取,是比较麻烦的方式。
后来我想了个办法,我编写了一个类似于注册部门的类,起名叫注册类,在编写好一个JFrame后,就把这个frame注册到这个类中。如果在哪里需要使用这个frane,就通过这个注册类的静态方法进行获取。(注:翻看设计模式的时候,发现这有点类似中介者模式,我还需要研究)
-------------------------------------------------------------------------------------------------------------- ------------------------------------
我是一个菜鸟,我热烈欢迎任何人指出我的错误和缺点!