|
动态绑定事件
Swing的事件模型的优点就在于它的灵活性。你可以调用方法给组件添加或删除事件。 Button 可以连不止一个 listener。通常组件是以多播 (multicast)方式处理事件的,也就是说你可以为一个事件注册多个 listener。但是对于 一些特殊的,以单播 (unicast)方式处理事件的组件,这么做就会引发 TooManyListenersException了。 程序运行的时候能动态地往 Button b2上面添加或删除 listener。你应该已经知道加 listener的方法了,此外每个组件还有一个能用来删 listener的 removeXXXListener( )方法。 这种灵活性为你带来更大的便利。值得注意的是, listener的添加顺序并不一定就是它们的调用顺序 (虽然绝大多数 JVM确实是这么实现的 )。 将业务逻辑 (business logic)与用户界面分离开来 一 般情况下,设计类的时候总是强调一个类 "只作一件事情 "。涉及用户界面的时候更是如此,因为你很可能会把 "要作什么 "同 "要怎样显示 "给混在一起了。这种 耦合严重妨碍了代码的复用。比较好的做法是将 "业务逻辑 (business login)"同 GUI分离开来。这样不仅方便了业务逻辑代码的复用,也简化了 GUI的复用。还有一种情况,就是多层系统 (multitiered systems),也就是说”业务对象 (business object)"完全贮存在另一台机器上。业务规则的集中管理能使规则的更新立即对新交易生效,因此这是这类系统所追求的目标。但是很多应用程序都会用到 这些业务对象,所以它们绝不能同特定的显示模式连在一起。它们应该只做业务处理,别的什么都不管。树立了将 UI同业务逻辑相分离的观点之后,当你再碰到用 Java去维护遗留下来的老代码时,也能稍微轻松一点。 范式,内部类, Swing事件模型,还能继续用下去的 AWT事件模型,以及那些要我们用老办法用的新类库的功能,所有这些都使程序设计变得更混乱了。现在就连大家写乱七八糟的代码的方式也变得五花八门了。这些情况都是事实,但是你应该总是使用最简单也最有条理的解决方案 :用 Listener(通常要写成内部类 )来处理事件。用了这个模型,你可以少写很多 "让我想想这个事件是谁发出的 "这种代码。所有代码都在解决问题,而不是在做类型检查。这是最佳的编程风格,写出来的代码不仅便于总结,可读性和可维护性也高。 并发与Swing 写 Swing 程序的时候,你很可能会忘了它还正用着线程。虽然你并没有明确地创建过 Thread对象,但它所引发的问题却会乘你不备吓你一跳。绝大多数情况下,你写的 Swing或其他带窗口显示的 GUI程序都是事件驱动的,而且除非用户用鼠标或键盘点击 GUI组件,否则什么事都不会发生。 只要记住 Swing有一个事件分派线程就行了,它会一直运行下去,并且按顺序处理 Swing的事件。如果你想确保程序不会发生死锁或者竞争的情形,那么倒是要考虑一下这个问题。 重访Runnable 在第 13章,我曾建议大家在实现 Runnable接口时一定要慎重。 当然如果你设计的类必须继承另一个类而这个类又得有线程的行为,那么选择 Runnable还是对的。 不同的 JVM,在如何实现线程方面,存在着巨大的性能和行为差异。 管理并发 当你用 main方法或另一个线程修改 Swing组件的属性时,一定要记住,有可能事件分派线程正在和你竞争同一个资源。 看来线程遇到 Swing的时候,麻烦也跟着来了。要解决这个问题,你必须确保 Swing组件的属性只能由事件分派线程来修改。 这 要比听上去的容易一些。 Swing提供了两个方法, SwingUtilities.invokeLater( )和 SwingUtilities.invokeandWait( ),你可以从中选一个。它们负责绝大多数的工作,也就是说你不用去操心那些很复杂的线程同步的事了。 这两个方法都需要 runnable对象作参数。当 Swing的事件处理线程处理完队列里的所有待处理事件之后,就会启动它的 run( )方法了。 能用这两个方法来设置 Swing组件的属性。 可视化编程与JavaBeans 看到现在你已经知道 Java在代码复用方面的价值了。复用程度最高的代码是类,因为它是由一组紧密相关的特征 (字段 field)和行为 (方法 )组成的,它既能以合成 (composition),也能以继承的方式被复用。 继承和多态是面向对象编程的基础,但是在构建应用程序的时候,绝大多数情况下,你真正需要的是能帮你完成特定任务的组件。你希望能把这些组件用到设计里面,就像电子工程师把芯片插到电路板上一样。同样,也应该有一些能加速这种 "模块化安装 "的编程方法。 Microsoft 的 Visual Basic为 "可视化编程 (Visual programming)"赢得了初次成功——非常巨大的成功,紧接着是第二代的 Borland Delphi(直接启发了 JavaBean的设计 ) 。有了这些工具,组件就变得看得见摸的着了,而组件通常都表示像按钮,文本框之类的可视组件,因此这样一来组件编程也变得有意义了。实际上组件的外观,通 常是设计时是什么样子运行时也就这样,所以从控件框 (palette)里往表单上拖放组件也就成了可视化编程的步骤了。而当你在这么做的时候,应用程序构 造工具在帮你写代码,所以当程序运行时,它就会创建那些组件了。 通常简单地把组件拖到表单上还不足以创建程序。你还得修改一些特征,比如 它的颜色,上面的文字,所连接的数据库等等。这些在设计时可以修改的特征被称为属性 (properties)。你可以在应用程序的构建工具里控制组件的属 性。当程序创建完毕,这些配置信息也被保存下来,这样程序运行时就能激活这些配置信息了。 看到现在你或许已经习惯这样来理解对象了,也就是对象不仅是一组特征,还是一组行为。设计的时候,可视组件的行为部分的表现为事件,也就是说 "是些能发生在这个组件上的事情 "。一般来说你会用把代码连到事件的方法来决定事件发生时该做些什么。 下 面就是关键部分了 :应用程序的构建工具用 reflection动态地查询组件,找出这个组件支持哪些属性和事件。一旦知道它是谁,构建工具就能把这些属性 显示出来,然后让你作修改了 (创建程序的时候会把这些状态保存下来 ),当然还有事件。总之,只要你在事件上双击鼠标或者其他什么操作,编程工具就会帮你准 备好代码的框架,然后连上事件。现在,你只要编写事件发生时该执行的代码就可以了。 编程工具帮你做了这么多事,这样你就能集中精力去解决程序的外观和功能问题了,至于把各部分衔接起来的细节问题,就交给构建工具吧。可视化编程工具之所以能获得如此巨大的成功,是因为它能极大的提高编程的效率,当然这一点首先体现在用户界面,但是其它方面往往也受益颇丰。 JavaBean是干什么用的? 言 归正传,组件实际上是一段封装成类的代码。关键在于,它能让应用程序的构建工具把自己的属性和事件提取出来。创建 VB组件的时候,程序员必须按照特定的约 定,用相当复杂的代码把属性和事件发掘出来。 Delphi是第二代的可视化编程工具,而且整个语言是围绕着可视化编程设计的,所以用它创建可视化组件要简 单得多。但是 Java凭借其 JavaBean在可视化组件的创建技术领域领先群雄。 Bean只是一个类,所以你不用为创建一个 Bean而去编写任何额外的 代码,也不用去使用特殊的语言扩展。事实上你所要做的只是稍稍改变一下方法命名的习惯。是方法的名字告诉应用程序构建工具,这是一个属性,事件还是一个普 通的方法。 JDK文档把命名规范 (naming convention)错误地表述成 "设计模式 (design pattern)”。这真是不幸,设计模式 (请参阅 www.BruceEckel.com上的 Thinking in Patterns (with Java))本身已经够让人伤脑筋的了,居然还有人来混淆视听。重申一遍,这算不上是什么设计模式,只是命名规范而已,而且还相当简单。 对于名为 xxx的属性,你通常都得创建两个方法:getXxx( )和setXxx( )。注意构建工具会自动地将"get"和"set"后面的第一个字母转换成小写,以获取属性的名字。"get"所返回的类型与”set"所使用的参数的类 型相同。属性的名字同"get"和”set"方法返回的类型无关。 对于boolean型的属性,你既可以使用上述的"get"和"set"方法,也可以用"is"来代替"get"。 Bean的常规方法无需遵循上述命名规范,但它们都必须是public的。 用Swing的listener来处理事件。就是我们讲到现在一直在用的这个方案:用addBounceListener (BounceListener)和removeBounceListener(BounceListener)来处理BounceListener。绝 大多数情况下,内置的事件和监听器已经可以满足你的需要了,但是你也可以创建你自己的事件和监听器接口。 用Introspector提取BeanInfo 你已经知道做一个 Bean有多简单了,但是它的功能并不仅限于此。 JavaBean的架构能让你很快上手,但是经过扩 展,它也可以适应更复杂的情况。这些用途已经超出了本书的范围,但是我会做一个简单的介绍。你可以在 java.sun.com/beans上找到更多的细 节。 属性是一个能加强的地方。在我们举的例子里,属性都是单个的,但是你也可以用一个数组来表示多个属性。这被称为索引化的属性 (indexed property)。你只要给出正确的方法 (还是要遵循方法的命名规范 ), Introspector就能找到索引化的属性,这样应用程序构建工具就能作出 正确的反映了。 属性可以被绑定,也就是说它们能通过 PropertyChangeEvent通知其它对象。而其它对象能根据 Bean的变化,修改自己的状态。 属 性是可以被限制的,也就是说如果其他对象认为属性的这个变化是不可接受的,那么它们可以否决这个变化。 Bean用 PropertyChangeEvent 通知其他对象,而其他对象则用 PropertyVetoException来表示反对,并且命令它将属性的值恢复到原来的状态。 你也可以修改 Bean在设计时的表示方式 : 你 可以为 Bean提供自定义的属性清单。当用户选择其它 Bean的时候,构建工具会提供普通属性清单,但是当他们选用你的 Bean时,它会提供你定义的清 单。 你可以为属性创建一个自定义的编辑器,这样虽然构建工具用的是普通的属性清单,但当用户要编辑这个特殊属性时,编辑器就会自动启动了。 你可以为 Bean提供一个自定义的 BeanInfo类,它返回的信息,可以同 Introspector默认提供的 BeanInfo不同。 还可以把所有 FeatureDescriptor的 "专家 (expert)"模式打开,看看基本功能和高级功能有什么区别。 |
高级 Swing于Java Bean
最新推荐文章于 2025-07-09 16:47:44 发布
本文探讨了JavaBean在Swing GUI编程中的应用,包括事件处理、并发管理及组件封装,强调了将业务逻辑与用户界面分离的重要性,以及如何利用JavaBean特性简化程序设计。

5769

被折叠的 条评论
为什么被折叠?



