上一章
下面,首先概述一下Swing的基本架构。为了理解如何高效地使用一些高级组件,我们必须理解& quot底部& quot事情。然后,我们将讨论Swing中用户界面模块的使用,如文本字段、单选按钮和菜单。接下来,介绍如何在不考虑特定用户界面lookandfeel的情况下,使用Java中的布局管理器功能在窗口中排列这些组件。最后,介绍了如何在Swing中实现对话框。
本章涵盖了基本的Swing组件,如文本组件、按钮和滑块,它们是非常常用的重要用户界面模块。Swing中的高级组件将在第二卷中讨论。如果想详细了解Swing框架,可以参考KimTopley的《CoreJFC》和《CoreSwing:AdvancedTopics》(Prentice Hallptr出版社出版)。
内容,例如按钮的状态(是否按下)或文本字段的文本。
外观(颜色、大小等。)
行为(对事件的反应)。
这三个元素之间的关系相当复杂,即使是最简单的组件(比如按钮)。显然,按钮的外观取决于外观和感觉。金属按钮的外观不同于Windows按钮或图案按钮。此外,外观显示取决于按钮的状态:当按钮被按下时,按钮需要用不同的外观重新绘制。状态取决于按钮接收到的事件。当用户用鼠标点击按钮时,按钮被按下。
当然,在程序中使用按钮的时候,你只需要把它当成一个按钮,不需要考虑它的内部操作和特性。毕竟这些都是实现按钮的程序员的工作。但是,实现按钮的程序员应该更仔细地考虑这些按钮。毕竟,无论外观如何,他们必须实现这些按钮和其他用户界面模块,以便这些组件正常工作。
为了满足这种需求,Swing设计者采用了一种著名的设计模式:模型-视图-控制器。像许多其他设计模式一样,这种设计模式遵循第5章中介绍的面向对象设计的基本原则:限制一个对象拥有的功能数量。不要用一个按钮类来做所有的事情,而是让一个对象负责组件的外观,另一个对象负责存储内容。模型-视图-控制器(MVC)设计模式将告诉我们如何实现这种设计,并实现三个独立的类:
模式:存储内容。
查看:显示内容。
控制器:处理用户输入。
这个模式清楚地定义了三个对象是如何交互的。该模型存储内容,并且没有用户界面。按钮的内容很简单,只用几个图标来表示当前按钮是否被按下,是否处于活动状态等等。文本字段的内容稍微复杂一些。它是一个保存当前文本的string对象,与视图中显示的内容不一致——如果内容的长度大于文本字段的显示长度,用户只能看到显示的部分,如图9-1所示。
该模型必须实现更改内容和查找内容的方法。例如,文本模型中的方法包括在当前文本中添加或删除字符,并将当前文本作为字符串返回。记住:模型是完全看不见的。视图的工作是显示存储在模型中的数据。
注意:这个术语& quot模型& quot可能不太合适,因为人们通常把模型看成是一个抽象概念的具体表现。汽车和飞机的设计者建造模型来模拟真实的汽车和飞机。但是这个类比可能会让你误解模型-视图-控制器模型。在设计模式中,模型存储完整的内容,视图给出内容的可视化显示(完整或不完整)。一个更恰当的比喻是模特为画家摆姿势。在这一点上,就看画师如何看待模型,并据此作画了。那幅画是正式的肖像画、印象派作品还是立体派作品(用奇怪的曲线描绘四肢),完全取决于画家。
模型-视图-控制器模式的一个优点是一个模型可以有多个视图,其中每个视图可以显示整个内容的不同部分或方面。例如,HTML编辑器通常会同时提供同一内容的两个视图:
WYSIWYG(所见即所得)视图和& quot原始标签& quot视图(见图9-2)。
当模型被一个视图的控制器更新时,模型将通知两个视图这一变化。收到通知后,视图将自动刷新。当然,对于一个简单的用户界面模块,比如一个按钮,没有必要为同一个模型提供多个视图。
控制器负责处理用户输入事件,如点击鼠标和敲击键盘。然后决定是否将这些事件转化为对模型或视图的更改。例如,如果用户在文本框中按下字符键,控制器调用& quot插入字符& quot命令,然后模型告诉视图进行更新。视图永远也不会知道为什么文本发生了变化。
但是如果用户按下光标键,控制器将通知视图滚动屏幕。滚动视图对实际的文本没有影响,所以模型永远不会知道事件发生了。
>设计模式在解决一个问题时,不需要从头做起,而是参考过去的经验,或者向做过相关工作的专家请教。设计模式是一种方法,该方法以一种结构化的形式展示了专家们的心血。
近几年来,软件工程师们开始对这些模式进行汇总分类。这个领域的先行者的灵感来源于建筑师ChristopherAlexander的设计模式。他在《TheTimelessWayofBuilding》(OxfordUniversityPress,1979)一书中,为公共和私人生活空间的建筑设计模式进行了分类。下面是一个典型的例子:
窗户位置
人人都喜欢靠窗户的座位,可以画上凸窗、低窗台的大窗户以及放在这里的舒适的椅子。如果一个房间没有这样的地方,那么很少有人会感到舒服和安逸。
如果这个房间没有一个像这样“位置”的窗户,那么房间里的人就可能会面对下面的选择左右为难:
1)舒服地坐下。
2)要充足的光线。
很明显,如果舒适的位置—该房间内最想坐的位置—远离窗户的话,那么冲突就不可避免。
因此,对于白天长时间呆的房间,至少要把一个窗户设计成“窗户位置”。
在Alexander的模式分类以及软件模式的分类中,每个模式都遵循一种特定的格式。模式首先说明使用环境,即产生设计问题的背景。接着解释问题,通常这里会有几个冲突的因素。最终,权衡这些冲突,给出问题的解决方案。
在“窗户位置”模式中,其使用环境就是白天大部分时间呆着的房间。冲突因素就是想舒服地坐下和充足的光线。而解决方案就是找到一个“窗户位置”。
在模型-视图-控制器模式中,使用环境就是表示信息和接收用户输入的用户界面系统。
这里有若干冲突因素:对于同一数据来说,可能同时需要更新多个可视化表示,而可视化表示方式可能会改变,例如,适应不同的观感标准。交互机制也可能改变,例如,支持语音命令等。解决方案是把这些功能分布到三个独立的交互组件:模型、视图和控制器。
当然,模型-视图-控制器模式要比“窗户位置”模式复杂得多,它需要详细地说明如何分布这些功能。
可以在由ErichGamma等编写的《DesignPatterns—ElementsofReusableObjectOrientedSoftware》(Addisom-Wesley出版社,1995年出版)一书中找到模型-视图-控制器模式和其他大量实用的软件模式的规范描述。这是一本研究模式运动的书籍。
另外,我们强烈推荐另一本由FrankBuschmann等编写的《ASystemofPatterns》,JohnWiley&Sons出版社于1996年出版。这是一本不错的书,相对上一本来说,这本书更容易读懂。
模型-视图-控制器模式并不是Java设计中所使用的唯一模式。例如,AWT事件处理机制采用了“观察者”(observer)模式。
设计模式的另一个重要特点就是它们已经成为文化的一部分。当你谈论模型-视图-控制器模式或者“观察者”模式时,全世界的程序员都能明白你的意思。因而,模式已经成为探讨设计问题的有效方法。
图9-4给出了模型、视图、控制器对象之间的交互。
程序员使用Swing组件,通常不需要考虑它们的模型-视图-控制器体系结构。每个用户界面元素都有一个包装器类(如JButton或JTextField)来保存模型和视图。
当需要查询内容(如文本域中的文本)时,包装器类会向模型询问并且返回所要的结果。当想改变视图时(例如,在一个文本域中移动光标位置),包装器类会把此请求转发给视图。然而,有时候包装器转发命令并不卖力。在这种情况下,就不得不直接同模型打交道。(不必直接操作视图—这是观感代码的工作。)
模型-视图-控制器模式吸引Swing设计者的一个重要原因是该模式允许他们实现可插观感。每个按钮或者文本域的模型是独立于观感的。当然可视化表示是完全依赖于特殊观感的用户界面设计的,且控制器也能改变它。例如,在一个语音控制设备中,控制器需要处理的各种事件与使用键盘和鼠标的标准计算机完全不同。通过把底层模型与用户界面分离开,Swing设计者就能够重用模型的代码,甚至在程序运行时对观感进行切换。
当然,模式只能作为一种指导性的建议而并没有严格的戒律。没有一种模式能够适用于所有情况。例如,使用“窗户位置”模式(设计模式中并非主要成分)来安排小卧室就不太合适。同样地,Swing设计者发现对于可插观感实现来说,使用模型-视图-控制器模式并非都是完美的。
模型容易分离开,每个用户界面组件都有一个模型类。但是,视图和控制器的职责分工有时并不很明显,这样将会导致产生很多不同的类。当然,作为这些类的使用者来说,不必为这些细节问题费心。前面已经说过,这些类的使用者根本无需为模型操心—只是使用组件包装器类。
Swing按钮的模型-视图-控制器分析
前一章已经介绍了如何使用按钮,当时没有考虑模型、视图和控制器。按钮是最简单的用户界面元素,所以我们从按钮开始学习模型-视图-控制器模式。对于更加复杂的Swing组件来说,所遇到的类和接口都是类似的。
对于大多数组件来说,模型类实现了名字结尾为Model的接口,例如,按钮就实现了ButtonModel接口。实现了此接口的类可以定义按钮的多种状态。实际上,按钮并不复杂,Swing库包含了一个名为DefaultButtonModel的类,该类实现了这个接口。
我们可以通过查看ButtonModel接口中的方法来获知按钮模型维护的是哪种类型的数据。表9-1列举了访问性方法。
每个JButton对象存储一个按钮模型对象,可以用下列形式得到它的引用。
JButtonbutton=newJButton("Blue");
ButtonModelmodel=button.getModel();
实际上,我们不必关心按钮状态的琐碎信息,只有绘制它的视图才对此感兴趣。而像按钮是否可用这样的重要信息可以从JButton类中得到。(当然,JButton类也通过向它的模型询问来获得这些信息。)
重新查看ButtonModel接口中不包含的信息。模型不存储按钮标签或者图标。对于一个按钮来说,由模型无法知道它的外观。(在关于单选按钮组的一节中会看到,这种纯粹的设计会为程序员带来一些麻烦。)
值得注意的是,同样的模型(即DefaultButtonModel)可用于下压按钮、单选按钮、复选框,甚至是菜单项。当然,这些按钮都有各自不同的视图和控制器。当使用Metal观感时,JButton类用BasicButtonUI类作为其视图;用ButtonUIListener类作为控制器。一般来说,每个Swing组件都有一个相关的后缀为UI的视图对象,但并不是所有的Swing组件都有专门的控制器对象。
所以,在给出JButton底层工作的简短介绍之后,你可能会想:JButton究竟是什么?事实上,它仅仅是一个继承了JComponent的包装器类,JComponent包含了一个DefaultButtonModel对象,一些视图数据(例如按钮标签和图标)以及一个负责按钮视图的BasicButtonUI对象。
下篇文章介绍布局管理器概述的内容,不容错过!!!!
上一篇:义务小商品博览会