绍
以下记录描述了有关此版本的重要更改和信息。在某些情况下,该说明提供了有关问题或更改的其他详细信息的链接。
从JDK 11开始,JavaFX模块与JDK分开提供。这些发行说明涵盖了独立的JavaFX 11发行版。JavaFX 11需要JDK 10(必须是OpenJDK版本)或JDK 11.建议使用JDK 11。
重要变化
运行JavaFX应用程序
既然JDK不再包含JavaFX,则必须明确包含应用程序使用的JavaFX模块。有关说明,请参阅JavaFX 11入门页面。
添加API以自定义Spinner控件的步骤重复计时
在JavaFX 11中修改值步骤之前,必须在Spinner控件箭头按钮上按下鼠标的默认持续时间。已添加两个新属性“initialDelay”和“repeatDelay”来配置此行为。
initialDelay:在下一个值步骤之前必须在箭头按钮上按下鼠标的持续时间。默认值现在为300毫秒。
repeatDelay:在第一个值步骤之后,每个连续步骤必须按下鼠标的持续时间。默认值现在为60毫秒。
有关更多信息,请参阅JDK-8167096。
默认情况下,独立的javafx模块不再具有权限
javafx.* 模块现在由应用程序类加载器加载,默认情况下不再具有权限。想要在启用安全管理器的情况下运行的应用程序需要使用“-Djava.security.policy”指定自定义策略文件,并为每个 javafx.* 模块授予所有权限。有关更多信息,请参阅JDK-8210617。
将默认GTK版本切换为3
现在,JavaFX将在存在gtk3库的Linux平台上使用GTK 3。在JavaFX 11之前,GTK 2库是默认的。这与JDK 11中AWT的默认值相匹配。有关更多信息,请参阅JDK-8198654。
新功能
以下注释描述了JavaFX 11中的一些增强功能。有关完整列表,请参阅发行说明末尾的表格。
FX Robot API
添加了公共FX Robot API以支持模拟用户交互,例如在键盘上键入键并使用鼠标以及捕获图形信息。有关更多信息,请参阅JDK-8090763。
删除了功能和选项
删除对libavcodec 53和55的支持
FX Media对libavcodec 53和55的支持已被删除。默认情况下,这些库不在受支持的Linux平台上,并且不再需要。有关更多信息,请参阅JDK-8194062。
已知的问题
JavaFX在Ubuntu 18.04上使用Wayland与OpenJDK 11崩溃
启用XWayland窗口服务器时,JavaFX在Ubuntu 18.04 Linux机器上崩溃。只要FX窗口工具包代码在Linux上使用GTK 3,就会发生这种情况,这是JavaFX 11的默认设置。
建议的解决方法是在运行JavaFX应用程序时使用Xorg服务器而不是Wayland服务器。请注意,JDK 10或JDK 11不支持Wayland。
另一种解决方法是通过在命令行上传递以下系统属性来显式强制GTK 2:
java -Djdk.gtk.version=2 ...
有关更多信息,请参阅JDK-8210411。
使用JDK 10运行时,Swing interop需要合格的导出
要使用带有OpenJDK 10版本的JavaFX 11运行FX / Swing互操作应用程序,必须在java命令行中添加以下四个限定导出。
--add-exports=java.desktop/java.awt.dnd.peer=javafx.swing --add-exports=java.desktop/sun.awt=javafx.swing --add-exports=java.desktop/sun.awt.dnd=javafx.swing --add-exports=java.desktop/sun.swing=javafx.swing
有关更多信息,请参阅JDK-8210615。
使用具有独立SDK的安全管理器运行时,Swing interop失败
在启用安全管理器的情况下运行时,FX / Swing互操作应用程序将失败。使用JFXPanel或SwingNode的应用程序必须在未启用安全管理器的情况下运行。有关更多信息,请参阅JDK-8202451。
使用jlink创建的最小jdk映像时,Swing interop失败
使用包含JavaFX 11 jmods包中的javafx.swing模块的jlink创建的最小Java映像将无法运行FX / Swing互操作应用程序。例如,如下创建的图像将不起作用:
jlink --output myjdk --module-path javafx-jmods-11 \ --add-modules java.desktop,javafx.swing,javafx.controls
javafx.swing模块依赖于JDK 11中新的jdk.unsupported.desktop模块,必须通过该--bind-services选项显式添加或包含该模块。
解决方法:使用以下两种方法之一创建映像:
jlink --output myjdk --module-path javafx-jmods-11 \ --add-modules java.desktop,javafx.swing,javafx.controls,jdk.unsupported.desktop jlink --output myjdk --bind-services --module-path javafx-jmods-11 \ --add-modules java.desktop,javafx.swing,javafx.controls
有关更多信息,请参阅JDK-8210759。
固定错误列表
发行密钥概要子组件JDK-8203345启用屏幕阅读器时VirtualFlow中的内存泄漏无障碍JDK-8204336当嵌套事件循环处于活动状态时,Platform.exit()会抛出ISE应用程序生命周期JDK-8089454[HTMLEditor]选择删除CENTER对齐控制JDK-8154039选择TabPane :: getTabs()中未包含的选项卡时内存泄漏控制JDK-8157690[TabPane]排序选项卡使选项卡选择菜单为空控制JDK-8165459HTMLEditor:意外禁用剪贴板工具栏按钮控制JDK-8185854具有自定义外观的TabPane中不可编辑的ComboBox上的NPE控制JDK-8187432ListView:启动时EditEvent的索引不正确控制JDK-8192800表自动调整大小会忽略列调整大小策略控制JDK-8193311[Spinner]在ENTER上未激活默认按钮控制JDK-8193495快速删除和添加操作后,TabPane不会正确更新标题区域中的选项卡位置控制JDK-8194913如果将窗格添加到工具栏,则会破坏焦点遍历控制JDK-8196827test.javafx.scene.control.ComboBoxTest - 生成NullPointerException控制JDK-8197846ComboBox:删除并重新添加后变为无法点击控制JDK-8197985在ListView中按Shift + DOWN会导致抛出异常控制JDK-8200285TabDragPolicy.REORDER阻止显示ContextMenu控制JDK-8201285重复使用具有disable = true的DateCell时,DateCell文本颜色未正确更新控制JDK-8208610在FXMLLoader :: getDefaultClassLoader中调用类的错误检查FXMLJDK-8129582在Linux上显示RTL语言文本时,控件显着减慢图像JDK-8195801用MarlinFX中的sun.misc.Unsafe替换jdk.internal.misc.Unsafe图像JDK-8195802消除在javafx.graphics中使用jdk.internal.misc安全实用程序图像JDK-8195806消除javafx.graphics中对sun.font.lookup的依赖图像JDK-8195808消除javafx.graphics中对sun.print的依赖图像JDK-8196617在某些环境中,FX打印测试因NPE而失败图像JDK-8198354[macOS]单词包装标签中显示的损坏的泰语字符图像JDK-8201231WindowStage.setPlatformEnabled中的java.lang.NullPointerException图像JDK-8202396ios native imageloader中的内存泄漏图像JDK-8202743虚线描边随机涂错,可冻结应用图像JDK-8203378如果FX是使用OpenJDK构建的,则JDK构建无法编译javafx.graphics module-info.java图像JDK-8203801PrismLoaderGlue.stg文件中缺少Classpath异常图像JDK-8207328javafx.css.Stylesheet的API文档不准确/错误图像JDK-8209191[macOS]扭曲的复杂文本渲染图像JDK-8088722GSTPlatform无法播放具有多个音轨的MP4文件媒体JDK-8191446[Linux]为openjfx构建构建并提供libav媒体存根媒体JDK-8193313MediaPlayer泄漏本机内存媒体JDK-8195803消除在javafx.media中使用sun.nio.ch.DirectBuffer媒体JDK-8198316在macOS High Sierra 10.13.2上播放m3u8文件时,MediaPlayer崩溃媒体JDK-8199008[macOS,Linux]实例化MediaPlayer导致CPU使用率超过100%媒体JDK-8199527将GStreamer升级到1.14媒体JDK-8202393App Transport Security使用新的编译器使用JDK构建阻止macOS上的http媒体媒体JDK-8191661Win32 HiDPI上的FXCanvas产生错误的结果其他JDK-8193910cssref.html和introduction_to_fxml.html中的版本号是错误的其他JDK-8195799在javafx模块中使用系统记录器而不是平台记录器其他JDK-8195800消除对javafx模块中sun.reflect.misc的依赖其他JDK-8195974将javafx中的java.util.logging替换为System logger其他JDK-8196297删除过时的JFR记录器代码其他JDK-8199357从FX删除对applet和Java Web Start的引用其他JDK-8200587修复FX API文档中的错误其他JDK-8202036更新OpenJFX许可证文件以匹配OpenJDK其他JDK-8202357ModuleHelper.java中版权标头中的额外字符其他JDK-8204653修复FX API文档中的错误其他JDK-8204956修复JDK-8200285后清理空白其他JDK-8207794FXCanvas被重新定义时,FXCanvas不会更新EmbeddedStageInterface的x / y其他JDK-8208294使用jrt协议时,安装本机库失败其他JDK-8180151JavaFX错误地使用具有特定尺寸的两个3D框渲染场景图场景图JDK-8192056从组或容器中删除javafx.scene.shape.Sphere-objects时发生内存泄漏场景图JDK-8205008GeneralTransform3D转换函数与单个Vec3d参数错误结果场景图JDK-8207377使用HiDPI记录Robot :: getPixelColor的行为场景图JDK-8201291单击具有setFocusable(false)的JFXPanel会导致其processMouseEvent方法永远循环swingJDK-8088769HtmlEditor中未显示透明色的AlphachannelwebJDK-8088925非透明背景导致NumberFormatExceptionwebJDK-8089375当WebWorker文件无法访问时,脚本应该以静默方式失败或发布有意义的异常webJDK-8147476使用MathML标记元素渲染问题webJDK-8193368[OS X]删除冗余文件webJDK-8193590将WebView与Tooltip一起使用时内存泄漏webJDK-8194265使用FileReader读取文件时,Webengine(webkit)崩溃webJDK-8194935Cherry挑选GTK WebKit 2.18.5的变化webJDK-8195804从java.base删除未使用的合格sun.net.www导出到javafx.webwebJDK-8196011从JFXPanel应用程序使用WebView时发生间歇性崩溃webJDK-8196374windows x86 webview-icu isAlphaNumericString崩溃webJDK-8196677Cherry挑选GTK WebKit 2.18.6的变化webJDK-8196968在JNIEnv _ :: CallObjectMethod退出时出现一次崩溃webJDK-8197987将libxslt更新为1.1.32版webJDK-8199474更新到WebKit的606.1版本webJDK-8200418“webPage.executeCommand(”“removeFormat”“,null)删除了body元素的样式”webJDK-8200629将SQLite更新到版本3.23.0webJDK-8202277由于依赖于javafx.swing,WebView图像捕获因独立FX而失败webJDK-8203698访问某些网站时,JavaFX WebView崩溃webJDK-8204856在PAGE_REPLACED事件之后,WebEngine文档变为空webJDK-8206899运行'dom / html / level2 / html / AppletsCollection.html'时,DRT会随机崩溃webJDK-8206995删除未使用的WebKit文件webJDK-8208114在Webview中打破了文本内容和URL链接功能的拖放webJDK-8208622使用html表单控件调用print API时出现[WebView] IllegalStateExceptionwebJDK-8209049Cherry挑选GTK WebKit 2.20.4更改webJDK-8163795[Windows]在本机GetScreenCapture方法中删除对StretchBlt的调用窗口的工具包JDK-8191885[MacOS] JavaFX主窗口无法在MacOS中从全屏模式返回窗口的工具包JDK-8196031FX Robot mouseMove在Windows 10 1709上使用HiDPI失败窗口的工具包JDK-8199614[macos] ImageCursor.getBestSize()抛出NullPointerException窗口的工具包JDK-8204635[Linux] getMouseX,gtk中的getMouseY GlassRobot.cpp忽略了HiDPI规模窗口的工具包JDK-8207372Robot.mouseWheel在Linux,Mac上没有正确实现窗口的工具包增强列表
发行密钥概要子组件JDK-8205919创建工件和功能以将其上载到Maven Central构建JDK-8167096添加API以自定义Spinner控件的步骤重复计时控制JDK-8177380在ColorPicker调色板中添加标准颜色控制JDK-8186187修改公共API的返回类型StyleConverter.getEnumConverter()控制JDK-8204621将MarlinFX升级到0.9.2图像JDK-8090763FX Robot API场景图JDK-8130379使用getCenter方法增强Bounds类场景图JDK-8195811使用公共API支持FX Swing互操作swingJDK-8198654将FX的默认GTK版本切换为3窗口的工具包
记得智趣狗上周为大家带来的Parrot Mambo吗?这款能开炮,还能帮你送情书的微型无人机乐趣多多。今天,智趣狗将为大家带来Mambo的“同宗兄弟”,同样是Parrot旗下的Swing,业界首款固定X翼的微型无人机。
小编第一眼看到Parrot Swing时的第一感觉就是:这货好大!没错,在Parrot旗下的微型无人机家族中,Swing的体型绝对算得上是巨无霸级别。但是,相对庞大的机身并没有影响Swing鹰击长空的本领,反而带来了有别于传统微型无人机的玩法和更强大的性能。
相信你已经迫不及待了吧?那就一起看看怎么和Parrot Swing一起玩耍吧。
Flypad手柄让操作更带感
Parrot Swing在国内又称速影无人机,而且是以“套餐”的形式发售,948元的价格可以得到Parrot Swing主机和Parrot Flypad手柄。
关于Parrot Flypad手柄我们在Parrot Mambo体验报告中就已经有所介绍,它最大的意义就是将通过手机APP点触屏幕的操作改为了物理摇杆和按钮,“驾驶”起来更带感。
同时,通过Parrot Flypad控制Swing飞行,有效控制距离可以从手机操作的20米提升到60米,这意味着你可以让Swing飞得更远更高,而不必担心超出遥控距离。
Parrot Flypad和时下智能手机的游戏手柄类似,它内置的锂电池可提供6小时的持续使用时间,通过常见的MicroUSB接口5V充电器就能为其充电,2小时左右即可充满。
手柄自带固定手机的支架,将支架固定在手柄的中凹部分,再利用可伸缩的支架固定好手机即可。打开手机蓝牙和FreeFlight Mini APP,然后按照界面提示就能轻松配对使用。
借助APP,可以让Swing直接在空中进行各种高速特技飞行。比如右转、左转、U形转、侧翻、回旋。咱们无需懂得原理,反正只要你下达了指令,Swing就能完美贯彻执行,这就足够了。
Parrot Swing为何这么大
为了实现固定翼垂直起降的能力,Parrot Swing一改传统微型无人机的设计风格,在无人机装上了四片由聚丙烯泡沫塑料打造的“翅膀”,并以“X”型固定。
这四片X翼,就是让Parrot Swing看起来超大的“罪魁祸首”。不过,别看Parrot Swing看着体型唬人,其实它的重量依旧十分轻盈,73g(没错,算上无人机和X翼的总重量)并没有和传统微型无人机拉开太大差距。和智趣狗上周体验的Parrot Mambo相比仅重了10g。
Parrot Swing将四个螺旋桨固定在了X翼的顶端,同时还带有一定向内的倾角,更符合空气动力学原理。
Swing无人机主体正面依旧有着两颗“大眼睛”,内藏LED灯,可以通过不同颜色反映各种使用状态。
Swing无人机顶部只有固定螺丝,和黑白相间的配色设计,看起来很醒目。
无人机底部配有独立的电源开关。
Swing的“屁股”上则配备了1颗30万像素的摄像头、超声波传感器以及Micro USB充电接口,电池仓也设计在了这里。
熟悉的550mAh电池,和Parrot旗下的其他微型无人机通用,建议大家可以多配几块换着使用。
不要小看Swing迷你的机身(主机部分)哦,它里面集成着一个三轴加速计和一个三轴陀螺仪用以测定Swing的每一个飞行动作或倾斜角度,而独立的压力传感器则用于控制无人机的飞行高度。在四旋翼模式下,Swing的摄像头每16毫秒将地面图像与之前图像进行对比以确定Swing的飞行速度,而超声波传感器还能为Swing分析高达4米的飞行高度哦。
独特的飞行乐趣
Parrot Swing的起飞过程和传统无人机类似,都是借助四个螺旋桨旋转使其垂直升空。但是,在悬浮半空之后,这款无人机则带来了更多的玩法。
比如,你可以让Swing依旧保持垂直状态飞行,这个模式没啥可说的。
独特的X翼设计可以让Swing轻松从垂直进入水平飞行状态,这才是这款无人机的杀手级功能。在水平飞行模式下可将螺旋桨提供的动力发挥到极致,X翼本身也能产生一定的滑行力,对Swing飞行的总动力有所增益(蚊子再小也是肉)。
根据资料,Swing在水平飞行模式下要比垂直模式能多出1分钟的续航时间,从7分钟延长到了8分钟,由此不难体现无人机从多轴向水平飞行转换的潜力所在。
如果你想看Swing的实际飞行视频,可以看看下面三段哦
小编实际飞行拍摄:https://v.qq.com/x/page/e0353bu98ue.html
官方宣传视频:https://v.qq.com/x/page/r0325y4g31h.html
Swing操作教程:https://v.qq.com/x/page/m033641qt1l.html
需要注意的是,Swing在水平飞行模式的速度要明显快于垂直飞行,所以它更适合在空旷的室外环境下试飞。还有一点需要注意,就是硕大的X翼结构让Swing对环境和风力有着较高的要求,如果试飞周边有树木,要小心X翼卡在树枝上;如果风力较大,Swing在悬停时会让你感受到《一起摇摆》这首歌的真谛。
虽然Swing鹰击长空时对环境要求更高,但这并不影响Swing独特的飞行乐趣。希望Parrot今后可以多多挖掘X翼结构的飞行潜力,毕竟微型无人机传统的垂直飞行已经非常成熟了,唯有改变形态和结构,才能让微型无人机重启我们体内的荷尔蒙。
在上一章中,主要介绍了如何使用Java中的事件模型。通过学习读者已经初步知道了构造图形用户界面的基本方法。本章将主要介绍构造功能齐全的图形用户界面所需要的一些重要工具。
下面,首先概述一下Swing的基本体系结构。为了理解怎样高效地使用一些更高级的组件,必须了解“底层”的东西。然后,再讲述Swing中各种常用的用户界面组件的使用,如文本域、单选按钮以及菜单等等。接下来,介绍在不用考虑特定的用户界面观感(look and feel)的情况下,如何使用Java中的布局管理器特性在一个窗口中排列这些组件。最后,介绍如何在Swing中实现对话框。
本章覆盖了基本的Swing组件,如文本组件、按钮和滑块等,这些都是使用十分频繁的重要用户界面组件。Swing中的高级组件将在卷II中讨论。如果要详细深入地理解Swing框架,推荐参考Kim Topley的《Core JFC》和《Core Swing:Advanced Topics》(Prentice Hall PTR出版社出版)。
前面讲过,本章将从Swing组件的体系结构开始。在解释本节标题的含义之前,先看一下构成用户界面组件(如按钮、复选框、文本域或者复杂的树形控件等)的各个部分。每个组件都有三个要素:
• 内容,如按钮的状态(是否按下),或者文本域的文本。
• 外观(颜色,大小等等)。
• 行为(对事件的反应)。
这三个要素之间的关系是相当复杂的,即使最简单的组件(如按钮)也是如此。很明显,按钮的外观显示取决于观感。Metal按钮的外观不同于Windows按钮或者Motif按钮。另外,外观显示还要取决于按钮的状态:当按钮被按下时,按钮需要被重新绘制成另一种不同的外观。而状态取决于按钮接收到的事件。当用户用鼠标在按钮上点击时,按钮就被按下。
当然,在程序中使用按钮的时候,只需把它看成是一个按钮,而不需要去考虑它的内部操作和特性。毕竟,这些是实现按钮的程序员的工作。但是,实现按钮的程序员就要对这些按钮考虑得细一些了。毕竟,无论观感如何,他们必须实现这些按钮和其他用户界面组件,以便让这些组件正常地工作。
为了实现这样的需求,Swing设计者采用了一种著名的设计模式(design pattern):模型-视图-控制器(model-view-controller)模式。该设计模式同其他许多设计模式一样,都遵循第5章中介绍的面向对象设计中的一个基本原则:限制一个对象拥有的功能数量。不要用一个按钮类完成所有的事情,而是应该让一个对象负责组件的观感,另一个对象负责存储内容。模型-视图-控制器(MVC)设计模式将告诉我们如何实现这种设计,实现三个独立的类:
• 模型(model):存储内容。
• 视图(view):显示内容。
• 控制器(controller):处理用户输入。
这个模式明确地规定了三个对象如何进行交互。模型存储内容,它没有用户界面。按钮的内容非常简单,只有几个用来表示当前按钮是否按下,是否处于活动状态的图标等。文本域内容稍稍复杂一些。它是容纳当前文本的字符串对象,与视图显示的内容并不一致—如果内容的长度大于文本域的显示长度,用户只能看到显示出来的那一部分,如图9-1所示。
模型必须实现改变内容和查找内容的方法。例如,一个文本模型中的方法有:在当前文本中添加或者删除字符以及把当前文本作为一个字符串返回等。记住:模型是完全不可见的。显示存储在模型中的数据是视图的工作。
注意:“模型”这个术语可能不太贴切,因为人们通常把模型视为一个抽象概念的具体表示。汽车和飞机的设计者构造模型来模拟真实的汽车和飞机。但这种类比可能会使你对模型-视图-控制器模式产生错误的理解。在设计模式中,模型存储完整的内容,视图给出了内容的可视化显示(完整或者不完整)。一个更恰当的类比应当是摆好姿势给画家作画的模特(model)。此时,取决于画家是如何看模特的,并据此来作一张画。那张画是一幅正规的肖像画,还是一幅印象派作品,还是一幅立体派作品(以古怪的曲线来描画四肢)完全取决于画家。
模型-视图-控制器模式的一个优点是一个模型可以有多个视图,其中每个视图可以显示全部内容的不同部分或不同方面。例如,一个HTML编辑器常常为同一内容提供两个同时的视图:
一个WYSIWYG(所见即所得)视图和一个“原始标记”视图(见图9-2)。
当通过某一个视图的控制器对模型进行更新时,模型会把这种改变通知给两个视图。视图得到通知以后就会自动地刷新。当然,对于一个简单的用户界面组件如按钮来说,不需要为同一模型提供多个视图。
控制器负责处理用户输入事件,如点击鼠标和敲击键盘。然后决定是否把这些事件转化成对模型或视图的改变。例如,如果用户在一个文本框中按下了一个字符键,控制器调用模型中的“插入字符”命令,然后模型告诉视图进行更新。而视图永远不会知道文本为什么改变了。
但是如果用户按下了一个光标键,控制器就会通知视图进行卷屏。卷动视图对实际文本不会有任何影响,因此模型永远不会知道该事件的发生。
设计模式
在解决一个问题时,不需要从头做起,而是参考过去的经验,或者向做过相关工作的专家请教。设计模式是一种方法,该方法以一种结构化的形式展示了专家们的心血。
近几年来,软件工程师们开始对这些模式进行汇总分类。这个领域的先行者的灵感来源于建筑师Christopher Alexander的设计模式。他在《The Timeless Way of Building》(Oxford University Press, 1979)一书中,为公共和私人生活空间的建筑设计模式进行了分类。下面是一个典型的例子:
窗户位置
人人都喜欢靠窗户的座位,可以画上凸窗、低窗台的大窗户以及放在这里的舒适的椅子。如果一个房间没有这样的地方,那么很少有人会感到舒服和安逸。
如果这个房间没有一个像这样“位置”的窗户,那么房间里的人就可能会面对下面的选择左右为难:
1)舒服地坐下。
2)要充足的光线。
很明显,如果舒适的位置—该房间内最想坐的位置—远离窗户的话,那么冲突就不可避免。
因此,对于白天长时间呆的房间,至少要把一个窗户设计成“窗户位置”。
在Alexander的模式分类以及软件模式的分类中,每个模式都遵循一种特定的格式。模式首先说明使用环境,即产生设计问题的背景。接着解释问题,通常这里会有几个冲突的因素。最终,权衡这些冲突,给出问题的解决方案。
在“窗户位置”模式中,其使用环境就是白天大部分时间呆着的房间。冲突因素就是想舒服地坐下和充足的光线。而解决方案就是找到一个“窗户位置”。
在模型-视图-控制器模式中,使用环境就是表示信息和接收用户输入的用户界面系统。
这里有若干冲突因素:对于同一数据来说,可能同时需要更新多个可视化表示,而可视化表示方式可能会改变,例如,适应不同的观感标准。交互机制也可能改变,例如,支持语音命令等。解决方案是把这些功能分布到三个独立的交互组件:模型、视图和控制器。
当然,模型-视图-控制器模式要比“窗户位置”模式复杂得多,它需要详细地说明如何分布这些功能。
可以在由Erich Gamma等编写的《Design Patterns—Elements of Reusable ObjectOriented Software》(Addisom-Wesley出版社,1995年出版 )一书中找到模型-视图-控制器模式和其他大量实用的软件模式的规范描述。这是一本研究模式运动的书籍。
另外,我们强烈推荐另一本由Frank Buschmann等编写的《A System of Patterns》,JohnWiley & Sons出版社于1996年出版。这是一本不错的书,相对上一本来说,这本书更容易读懂。
模型-视图-控制器模式并不是Java设计中所使用的唯一模式。例如,AWT事件处理机制采用了“观察者”(observer)模式。
设计模式的另一个重要特点就是它们已经成为文化的一部分。当你谈论模型-视图-控制器模式或者“观察者”模式时,全世界的程序员都能明白你的意思。因而,模式已经成为探讨设计问题的有效方法。
图9-4给出了模型、视图、控制器对象之间的交互。
程序员使用Swing组件,通常不需要考虑它们的模型-视图-控制器体系结构。每个用户界面元素都有一个包装器类(如JButton或JTextField)来保存模型和视图。
当需要查询内容(如文本域中的文本)时,包装器类会向模型询问并且返回所要的结果。当想改变视图时(例如,在一个文本域中移动光标位置),包装器类会把此请求转发给视图。然而,有时候包装器转发命令并不卖力。在这种情况下,就不得不直接同模型打交道。(不必直接操作视图—这是观感代码的工作。)
模型-视图-控制器模式吸引Swing设计者的一个重要原因是该模式允许他们实现可插观感。每个按钮或者文本域的模型是独立于观感的。当然可视化表示是完全依赖于特殊观感的用户界面设计的,且控制器也能改变它。例如,在一个语音控制设备中,控制器需要处理的各种事件与使用键盘和鼠标的标准计算机完全不同。通过把底层模型与用户界面分离开,Swing设计者就能够重用模型的代码,甚至在程序运行时对观感进行切换。
当然,模式只能作为一种指导性的建议而并没有严格的戒律。没有一种模式能够适用于所有情况。例如,使用“窗户位置”模式(设计模式中并非主要成分)来安排小卧室就不太合适。同样地,Swing设计者发现对于可插观感实现来说,使用模型-视图-控制器模式并非都是完美的。
模型容易分离开,每个用户界面组件都有一个模型类。但是,视图和控制器的职责分工有时并不很明显,这样将会导致产生很多不同的类。当然,作为这些类的使用者来说,不必为这些细节问题费心。前面已经说过,这些类的使用者根本无需为模型操心—只是使用组件包装器类。
Swing按钮的模型-视图-控制器分析
前一章已经介绍了如何使用按钮,当时没有考虑模型、视图和控制器。按钮是最简单的用户界面元素,所以我们从按钮开始学习模型-视图-控制器模式。对于更加复杂的Swing组件来说,所遇到的类和接口都是类似的。
对于大多数组件来说,模型类实现了名字结尾为Model的接口,例如,按钮就实现了ButtonModel接口。实现了此接口的类可以定义按钮的多种状态。实际上,按钮并不复杂,Swing库包含了一个名为DefaultButtonModel的类,该类实现了这个接口。
我们可以通过查看ButtonModel接口中的方法来获知按钮模型维护的是哪种类型的数据。表9-1列举了访问性方法。
每个JButton对象存储一个按钮模型对象,可以用下列形式得到它的引用。
JButton button = new JButton("Blue");
ButtonModel model = button.getModel( );
实际上,我们不必关心按钮状态的琐碎信息,只有绘制它的视图才对此感兴趣。而像按钮是否可用这样的重要信息可以从JButton类中得到。(当然,JButton类也通过向它的模型询问来获得这些信息。)
重新查看ButtonModel接口中不包含的信息。模型不存储按钮标签或者图标。对于一个按钮来说,由模型无法知道它的外观。(在关于单选按钮组的一节中会看到,这种纯粹的设计会为程序员带来一些麻烦。)
值得注意的是,同样的模型(即DefaultButtonModel)可用于下压按钮、单选按钮、复选框,甚至是菜单项。当然,这些按钮都有各自不同的视图和控制器。当使用Metal观感时,JButton类用BasicButtonUI类作为其视图;用ButtonUIListener类作为控制器。一般来说,每个Swing组件都有一个相关的后缀为UI的视图对象,但并不是所有的Swing组件都有专门的控制器对象。
所以,在给出JButton底层工作的简短介绍之后,你可能会想:JButton究竟是什么?事实上,它仅仅是一个继承了JComponent的包装器类,JComponent包含了一个DefaultButtonModel对象,一些视图数据(例如按钮标签和图标)以及一个负责按钮视图的BasicButtonUI对象。
下篇文章介绍布局管理器概述的内容,不容错过!!!!
*请认真填写需求信息,我们会在24小时内与您取得联系。