一、 引言
模态一直是我最喜欢的话题之一,至少因为一直存在大量的感兴趣的客户的有关于这方面内容的回馈信息。作为一个Java SE测试工程师,这正是驱动我工作的动力-它使我一直处于忙碌之中,而且还为我的工作带来快乐。另一方面,这也说明了模态是客户端最广为使用的特征之一,不管是使用Swing还是使用AWT进行开发。
在Java SE 6(代码名为Mustang)中,我的工作变得更有意思——在模态方面进行大量的改进。这些改进将为应用程序开发者提供更大的灵活性——在设计可能用到模态对话框行为的程序的过程中。在深入讨论这些改进之前,让我们首先看一下在Mustang之前的AWT所提供的功能。
从其有关介绍来看,AWT仅提供了两种类型的模态:模态和非模态的。
·模态-显示任何一个模态窗口时,应用程序中的所有窗口都将被阻断。
·非模态的-这是一种不能阻断任何窗口的对话框。
我们可能会提出下列一些有趣的问题:
·为什么一个模态对话框应该阻断当前应用程序中的所有的窗口?
·如果模态对话框仅阻断父窗口而不是其它窗口,不好吗?
·由应用程序开发者来决定(代替AWT)在他的应用程序的对话框应该阻断什么窗口,不好吗?比方说,当一个模态对话框处于活动状态时,如果一个应用程序用户想要滚动帮助窗口来看一下他/她在对话框中作了怎样的选择,他/她该如何实现这一点呢?
AWT在新的Java SE 6中加强了这一方面的功能。现在,它提供了四种类型的模态(应用范围由宽到窄):工具箱,应用程序,文档和非模态的。开发者可以视具体需要为他的对话框选择适当的模态类型。
二、 工具箱模态
选择这种类型,如果:
·你的对话框必须阻断你的应用程序中的所有窗口(除了该对话框的子层次窗口之外)
·你的对话框应该阻断你的applet及同一个工具箱中所有其它applet
·你的对话框应该阻断浏览器本身
·你想使用一个具有最大阻断范围的对话框
三、 应用程序模态
就通常应用程序来说,在应用程序和工具箱模态之间并不存在很多区别。但是,如果你正在开发一个applet,那么搞清其区别是十分重要的。
·如果在浏览器中启动若干applet,那么,根据你使用的是什么浏览器(检查你的浏览器文档),它们可以被当作单独的应用程序或单个的应用程序。应用程序模态对话框将阻断同一个"应用程序"中的所有的窗口
·默认的模态类型,未给模态对话框指定任何内容时使用。
四、 文档模态
选择这种类型,如果:
·对话框只阻断同一个文档中的窗口("文档"由最接近顶部的没有所有者的窗口决定)
·对话框应该具有邻近非模态的窗口的最小范围的阻断。
五、 非模态型
如果你不想要你的对话框阻断任何窗口,那么你可以使用这种模态。
注意 既然工具箱模态对话框能够阻断浏览器/Java WebStart,那么你需要一个AWTPermission "toolkitModality"以便从一个applet中使用这种类型的模态。
总的而言,在选择每一个对话框的适当模态类型(根据它应该阻断应用程序中的其它顶级窗口的指定范围)时,这为应用程序开发者提供大量的灵活性。
六、 模态排除
还有另外一种场所-在你的应用程序中存在许多窗口,并且你想要你的模态对话框阻断除了一个窗口之外的所有其它窗口。在这样情况下,你将必须选择模态类型-它具有最大范围的阻断能力。但是,从被对话框阻断的窗口中排除这些不应该被阻断的窗口,有可能吗?是的,完全可以!
下面,让我们看一下AWT在这一方面所提供的功能:
在Java SE 6中,AWT又引入了两种模态排除类型(参考图1)。
(一) 阻断工具箱模态对话框排除型
如果一个窗口是工具箱模态排除的,那么它就不会被任何应用程序或工具箱模态对话框所阻断。另外,它也不会被文档模态对话框从其它的子层次窗口(注意:如果你使用的是一种applet环境,那么你会要求AWTPermission-"toolkitModality"使用这种排除类型)外所阻断。
(二) 阻断应用程序模态对话框排除型
如果一个窗口是一个应用程序模态排除的,那么它就不会被任何应用程序模态对话框所阻断。另外,它也不会被文档模态对话框从其子层次窗口外面所阻断。
图1.排除于应用程序模态之外的窗口 |
默认情况下,一个窗口的模态排除属性是被关闭的。也就是说,默认情况下,它被阻断-如果它在可见的任何模态对话框的阻断范围之内。
在使用任何模态或排除类型之前,请检查一下是否你的平台支持这种类型-通过调用由java.awt.Toolkit类所提供方法isModalitySupported()和isModalExclusionTypeSupported()来实现。
七、 无父对话框
一直以来,对话框总是有一个父窗口与之相关联。但是,一个对话框总是有一个父窗口真正非常有必要吗?答案不再是这样了!
现在,在Java SE 6中,我们有可能创建一个父窗口为"null"的AWT对话框(在对话框构造器中的"parent"参数值为null)。在以前的发行版本中,这一直会引发一个异常。
因此,如果你不想让你的对话框有一个父窗口的话,那么你就不再需要创建一个"哑元"父窗口了!
除此之外,还有一些有趣的值得探讨的内容:
(一) 如果无父对话框是文档模态的
一个没有所有者的文档模态对话框会自动地成为该文档的一个根,因此它的阻断范围为空。因此,它的行为就象一个非模态的对话框一样。
(二) 如果无父对话框是应用程序或工具箱模态
一个应用程序或工具箱模态对话框(相对于一个文档模态对话框)的阻断范围并不依赖于它的所有者,因此对阻断范围不会产生任何影响。
在任何情况下,一个模态对话框应该总是位于它阻断的其它顶级窗口的顶部。你不能改变一个已经可见的对话框的模态类型。如果你想这样做,那么你需要隐藏它并且再次显示之,以便该新指定的模态类型起作用。