文章
Java
作者:James L. Weaver
本文是由两部分组成的系列文章的第一部分,重点介绍如何在 JavaFX 2.0 中使用最佳实践开发企业应用程序。
下载:
JavaFX 2.0 是一个用于创建富互联网应用程序 (RIA) 的 API 和运行时。JavaFX 于 2007 年推出,2011 年 10 月发布了 2.0 版本。JavaFX 2.0 的一个优点是可以使用成熟、熟悉的工具用 Java 语言编写代码。
本文是由两部分组成的系列文章的第一部分,重点介绍如何在 JavaFX 2.0 中使用最佳实践开发企业应用程序。
为说明 JavaFX 2.0 企业应用程序开发中的一些最佳实践,我们将探讨一个名为 TweetBrowser 的示例应用程序。如图 1 所示,该应用程序包含以下内容:
您将在下一节中下载 TweetBrowser 项目,其中包含该应用程序的代码,本文将着重探讨其部分代码。
图 1:TweetBrowser 应用程序启动时的屏幕截图
单击 #hashtag 或 @screenname 时,将在 UI 右上角显示一个旋转进度指示器(如图 2 所示),指示正在进行搜索。还可以在文本域键入一个 #hashtag、@screenname 或文字,然后按 Enter 键或单击 Search 按钮。无论用哪种方式,Search 按钮的显示都将变成 X,指示您可以通过单击该按钮取消搜索并禁用大部分 UI。
图 2:TweetBrowser 搜索时的屏幕截图
单击某条微博中的 Web 链接将打开一个弹出式窗口,其中包含显示所选页面的 WebView,如图 3 所示。

图 3:单击某个超链接后的 WebView
注:可以从 NetBeans 站点获取 NetBeans IDE。

图 4:在 NetBeans 中打开 TweetBrowser 项目

图 5:在 NetBeans 中运行 TweetBrowser 程序
TweetBrowser 应用程序应显示在一个窗口中,如前面图 1 中所示。继续试用该应用程序,浏览屏幕名称、hashtag 和 Web 链接。下面我们将分析该应用程序并探讨其中一些代码。
在深入研究代码之前,我们先来分析图 6 所示的各个片段,这些片段共同组成了 TweetBrowser 应用程序。
图 6:TweetBrowser 应用程序示意图
从图 6 右上角的 TweetBrowser 主页开始,用户可以通过在其中单击大眼鸟图标启动应用程序。如果尚未运行 TweetBrowser 的实例,这会通过 Java Web Start 调用应用程序。有关 TweetBrowser 主页的 URL,请参考“另请参见”一节。
图 6 左下部代表 tweetbrowser.ui 软件包,它包含 2 个 Java 类和 1 个 JavaFX 级联样式表 (CSS):
图 6 中下部代表 tweetbrowser.model 软件包,它包含 3 个 Java 类:
如图 6 所示,tweetbrowser.ui 软件包中的类调用 tweetbrowser.model 软件包中的类的方法。此外,tweetbrowser.ui 软件包中的类将模型的状态呈现到 UI,这主要是通过利用 JavaFX 的绑定功能实现的。
下面将讨论 TweetBrowser 应用程序中使用的一些技巧和最佳实践:
首先从列表中的第一项开始:从应用程序主页通过 Java Web Start 调用应用程序。
基于浏览器的应用程序有一个吸引人的特性,就是这些应用程序可以通过给定的 Web 页面即时访问。用户对此已有期待,因此为了让访问富客户端 Java 应用程序的用户感觉更加舒适,可以在 Web 页面上提供一个 Java Web Start 链接。通过这种方式,用户可能感觉很像是在运行一个 Web 应用程序,因为单击一个图标即会打开一个包含应用程序的窗口。在用户看来,新窗口包含了应用程序,而他们并不关心窗口是什么类型(浏览器窗口或 Java 应用程序窗口)。
清单 1 显示了 TweetBrowser 应用程序主页的 HTML 和 JavaScript 源代码,是对 NetBeans 中构建的 TweetBrowser 项目的输出进行修改的结果。
<html><head>
<script src="http://java.com/js/dtjava.js"></script>
<script>
function launchApplication(jnlpfile) {
dtjava.launch( {
url : 'TweetBrowser.jnlp'},
{
javafx : '2.0+'
},
{}
);
return false;
}
</script>
</head>
<body style="font-family: Arial; font-size: 12pt;">
<h2 >TweetBrowser Home Page</h2>
<a href='#'><img title="Launch TweetBrowser app"
src="img/tweetbrowser-logo-100.png"
onclick="return launchApplication('TweetBrowser.jnlp');"/></a>
<p>Click the icon to launch TweetBrowser via Java Web Start</p>
</body></html>
清单 1:应用程序主页的示例 HTML 和 JavaScript 代码
清单 2 包含用于启动 TweetBrowser 应用程序的 Java 网络启动协议 (JNLP) 的示例源代码,也是对 NetBeans 中构建的 TweetBrowser 项目的输出进行修改的结果。
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0" xmlns:jfx="http://javafx.com" href="TweetBrowser.jnlp">
<information>
<title>TweetBrowser</title>
<vendor>Jim Weaver</vendor>
<description>Sample JavaFX 2.0 application.</description>
<offline-allowed/>
</information>
<resources os="Windows" arch="x86">
<jfx:javafx-runtime version="2.0+"
href="http://download.oracle.com/otn-pub/java/javafx/...code omitted..."/>
</resources>
<resources os="Windows" arch="x64">
<jfx:javafx-runtime version="2.0+"
href="http://download.oracle.com/otn-pub/java/javafx/...code omitted..."/>
</resources>
<resources>
<j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se"/>
<jar href="TweetBrowser.jar" size="49305" download="eager" />
<jar href="lib/restfx-1.0.jar" size="49092" download="eager" />
<jar href="lib/restfx-server-1.0.jar" size="6884" download="eager" />
</resources>
<jfx:javafx-desc width="800" height="600"
main-class="javafxpert.tweetbrowser.ui.TweetBrowserMain"
name="TweetBrowser" />
<update check="background"/>
</jnlp>
清单 2:启动应用程序的 JNLP 的示例代码
NetBeans 生成的源代码与清单 1 和 2 所示的源代码之间的主要差别就在于删除了与小程序相关的代码,这让 TweetBrowser 只能通过 Java Web Start 来访问。
有关如何通过 Java Web Start 启动 JavaFX 应用程序的详细说明,请参考“另请参见”一节提到的部署 JavaFX 应用程序 指南。
使用 Java Web Start 方法时要考虑的一个问题是确保只调用应用程序的一个实例,即,当已有一个实例在运行时,无论用户是否单击应用程序图标,都只运行一个实例。为此,TweetBrowser 应用程序利用了 javafx.jnlp 软件包中的一些类,如清单 3 中显示的 TweetBrowserMain.java 的 start() 方法中所示:
@Override public void start(final Stage primaryStage) {
stage = primaryStage;
try {
singleService =
(SingleInstanceService)ServiceManager
.lookup("javax.jnlp.SingleInstanceService");
singleListener = new SingleInstanceListener() {
@Override public void newActivation(String[] params) {
System.out.println("TweetBrowser instance already running");
primaryStage.toFront();
}
};
if (singleService != null) {
singleService.addSingleInstanceListener(singleListener);
}
}
catch (UnavailableServiceException use) {
singleService = null;
System.out.println("Single instance service not loaded");
}
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override public void handle(WindowEvent e) {
if (singleService != null) {
singleService.removeSingleInstanceListener(singleListener);
}
}
});
Scene scene = SceneBuilder.create()
.width(1000)
.height(660)
.stylesheets("javafxpert/tweetbrowser/ui/tweetbrowser.css")
.root(
BorderPaneBuilder.create()
.top(createToolBar())
.center(createListView())
.build()
)
.build();
listView.disableProperty().bind(TweetBrowserModel.instance
.queryActive.or(TweetBrowserModel.instance.webViewPopupVisible));
invokeSearch(FIRST_SEARCH_TERM, true);
createWebViewPopup();
progressIndicator.visibleProperty()
.bind(TweetBrowserModel.instance.queryActive
.or(TweetBrowserModel.instance.webViewPopupWebEngine
.getLoadWorker().runningProperty()));
stage.setScene(scene);
stage.setTitle("Tweet Browser");
stage.show();
}
清单 3:TweetBrowserMain.java start() 方法
通过 Java Web Start 启动运行一个实例后,如果用户试图启动应用程序,则会调用 SingleInstanceListener 的覆盖 newActivation() 方法,而不是启动另一个 TweetBrowser 实例。为了在应用程序关闭时进行清理,为主窗口的 setOnCloseRequest() 方法提供了一个事件处理器,它将删除 SingleInstanceListener。
注:为满足编译器的要求,项目在编译时使用了 jnlp.jar 文件,但在运行时可以使用 Java 部署工具包提供的 javafx.jnlp 类(如清单 3 所示)。
多年来,使用模型/视图/控制器(即 MVC)模式已成为软件开发中的一个常见做法。通过提供将 UI 属性绑定到模型中的属性的功能,JavaFX API 有助于采用 MVC 模式。
如清单 4 所示,TweetBrowser 应用程序实例化并引用名为 TweetBrowserModel 的主模型类。
public class TweetBrowserModel {
public static TweetBrowserModel instance = new TweetBrowserModel();
public BooleanProperty queryActive = new SimpleBooleanProperty(false);
public BooleanProperty webViewPopupVisible =
new SimpleBooleanProperty(false);
public ObservableList allTweets = FXCollections.observableArrayList();
...
}
清单 4:实例化并引用模型
TweetBrowserMain 和 TweetCell 类中使用该引用将 UI 绑定到模型。例如,清单 3 中 progressIndicator 的 visibleProperty 绑定到一个表达式,该表达式中包含清单 4 中模型的 queryActive 属性。
清单 5 是将 UI 绑定到模型的另一个示例,其中将 listView 的 items 属性绑定到清单 4 中的 allTweets ObservableList。
private Node createListView() {
listView = ListViewBuilder.create()
.items(TweetBrowserModel.instance.allTweets)
.editable(false)
.build();
listView.setCellFactory(new Callback<ListView<Tweet>, ListCell<Tweet>>() {
@Override
public ListCell<Tweet> call(ListView<Tweet> list) {
ListCell tweetCell = new TweetCell();
tweetCell.setEditable(false);
return tweetCell;
}
});
return listView;
}
清单 5:TweetBrowserMain.java createListView() 方法
注意,绑定行为内置在 ListView 控件的 items 属性中,因此在本例中不使用 bind 方法。
从应用程序主页通过 Java Web Start 调用应用程序,确保只启动应用程序的一个实例,将 UI 绑定到模型,这些技巧的使用让用户和开发人员的生活更加轻松。
在本系列文章的第 2 部分,我们将探讨 TweetBrowser 示例应用程序中使用的更多技巧和最佳实践。
James L. (Jim) Weaver 是一位 Java 和 JavaFX 开发人员、作者和演讲者,积极致力于促进富客户端 Java 和 JavaFX 成为新应用程序开发的首选技术。Jim 撰写的著作包括《Inside Java》、《Beginning J2EE》和《Pro JavaFX 2》。他的专业背景包括 15 年的 EDS 系统架构师,以及同样年数的独立开发人员。作为一名 Oracle Java 宣讲师,Jim 在许多国际软件技术会议上发表过演讲,包括在旧金山和圣保罗的 JavaOne 大会。Jim 的博客为 http://javafxpert.com,Tweet 为 @javafxpert,电子邮件联系方式为 james.weaver AT oracle.com。