Sun推JavaFX,RIA之战进入白热化(2)

ZDNet软件频道 时间:2009-02-04 作者: |  我要评论()
本文关键词:Sun RIA JavaFX 软件
Sun打算让JavaFX提供比Java更多的快速用户接口开发功能。



六、探索JavaFX语言 – 声明语法

Sun打算让JavaFX提供比Java更多的快速用户接口开发功能。同时,这个脚本语言可
以被使用在应用需要的各个方面。在本文的例子中使用JavaFX开发了一个用户接口,一个登录窗口。本例还使用了Java程序实现了同一个登录窗口。这两个文件的代码如下:
JavaFX实现的登录窗口代码:
import JavaFX.ui.*;
Frame {
title:  "Authenticate Please"
    width:  300
    height:  125
    visible: true
    content: GridBagPanel {
border: EmptyBorder {
top: 5
                            left: 5
                            bottom: 5
                            right: 5}
cells: [GridCell {
anchor: EAST
gridx: 0
                            gridy: 0
                            insets: {top: 2}
content: SimpleLabel {text: "Username: "}},
GridCell {
anchor: WEST
fill: HORIZONTAL
weightx: 1
                            gridx: 1
                            gridy: 0
                            content: TextField {}},
GridCell {
anchor: EAST
gridx: 0
                            gridy: 1
                            insets: {top: 2}
content: SimpleLabel {text: "PasswordField: "}},
GridCell {
anchor: WEST
fill: HORIZONTAL
gridx: 1
                            gridy: 1
                            weightx: 1
                            content: PasswordField {}},
GridCell {
gridx: 1
                            gridy: 2
                            content:  Button {text: "Login"}}]}
}
用Java实现同样的登录窗口的代码:
public class Login extends javax.swing.JFrame {
/** Creates new form Login */
    public Login()
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">                         
    private void initComponents() {
usernameField = new javax.swing.JTextField();
usernameLabel = new javax.swing.JLabel();
passwordLabel = new javax.swing.JLabel();
passwordField = new javax.swing.JPasswordField();
loginButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Authenticate Please");
setName("loginFrame");
usernameField.setColumns(15);
usernameLabel.setText("Username:");
passwordLabel.setText("Password:");
passwordLabel.setRequestFocusEnabled(false);
passwordLabel.getAccessibleContext().setAccessibleName("Password:");
loginButton.setLabel("Login");
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.addContainerGap()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
.add(usernameLabel)
.add(19, 19, 19))
.add(layout.createSequentialGroup()
.add(passwordLabel)
.add(23, 23, 23)))
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
.add(passwordField)
.add(usernameField)))
.add(layout.createSequentialGroup()
.add(147, 147, 147)
.add(loginButton)))
.addContainerGap(92, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.addContainerGap()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(usernameField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(usernameLabel))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(passwordLabel)
.add(passwordField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 19, Short.MAX_VALUE)
.add(loginButton)
.addContainerGap())
);
pack();
}// </editor-fold>                       
/**
* @param args the command line arguments
*/
    public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Login().setVisible(true);
}
});
}
// VaRIAbles declaration - do not modify                    
    private javax.swing.JButton loginButton;
private javax.swing.JPasswordField passwordField;
private javax.swing.JLabel passwordLabel;
private javax.swing.JTextField usernameField;
private javax.swing.JLabel usernameLabel;
// End of vaRIAbles declaration                  
}
从上面的代码可以看出,JavaFX和传统的Java代码有些类似的地方,如类名上,但从总体结构上看还是有很大的差别。图5显示了这两种方式建立的登录窗口,上面的是用JavaFX建立的,下面的是用传统的Java代码建立的。
 
 
                                           图5 登录窗口:
    这个小例子很清楚地揭示了JavaFX和传统的Java的第一个主要的不同。JavaFX使用了类似于HTML的语法形式来建立用户接口。在JavaFX的语法中,开发人员只是定义了应该显示些什么东西,而不是用程序来指定需要如何建立。很显然,象JavaFX风格(有时这种风格也叫做声明语法)的语法更容易建立维护。
   当然,在JavaFX中也可以使用类似于Java的方式来建立相同的登录窗口。如下面的代码所示:
import JavaFX.ui.*;
var frame = new Frame();
frame.title = "Authenticate Please";
frame.width = 300;
frame.height = 125;
var panel = new GridBagPanel();
var border = new EmptyBorder();
border.bottom=5;
border.top=5;
border.left=5;
border.right=5;
panel.border = border;
var inset = new Insets();
inset.top=2;
var gcUserLabel = new GridCell();
gcUserLabel.anchor = EAST;
gcUserLabel.gridx=0;
gcUserLabel.gridy=0;
gcUserLabel.insets=inset;
var usernameLabel = new SimpleLabel();
usernameLabel.text = "Username:  ";
gcUserLabel.content = usernameLabel;
var gcUserField = new GridCell();
gcUserField.anchor = WEST;
gcUserField.fill=HORIZONTAL;
gcUserField.weightx=1;
gcUserField.gridx=1;
gcUserField.gridy=0;
gcUserField.insets=inset;
gcUserField.content = new TextField();
var gcPassLabel = new GridCell();
gcPassLabel.anchor = EAST;
gcPassLabel.gridx=0;
gcPassLabel.gridy=1;
gcPassLabel.insets=inset;
var passwordLabel = new SimpleLabel();
passwordLabel.text = "Password:  ";
gcPassLabel.content = passwordLabel;
var gcPassField = new GridCell();
gcPassField.anchor = WEST;
gcPassField.fill=HORIZONTAL;
gcPassField.weightx=1;
gcPassField.gridx=1;
gcPassField.gridy=1;
gcPassField.insets=inset;
gcPassField.content = new PasswordField();
var gcButton = new GridCell();
gcButton.gridx=1;
gcButton.gridy=2;
var loginButton = new Button();
loginButton.text = "Login";
gcButton.content = loginButton;
panel.cells = [gcUserLabel, gcUserField, gcPassLabel, gcPassField, gcButton];
frame.visible = true;
frame.content = panel;七、执行JavaFX程序
    JavaFX应用程序在桌面上可以被FXShell执行。FXShell是一个在OpenJFX上提供的一个类。为了在NetBeans中运行JavaFX文件,在Projects窗口中右击,然后选择Properties。在打开的Project Properties窗口(如图6)中,在Categories列表中选择Run,然后输入net.java.JavaFX.FXShell作为Main类,以及我们要运行的JavaFX程序的名子,在这里是Login.fx。
 
图6 在NetBeans中运行FXShell
 
    为了在Eclipse中运行JavaFX,右击在Package ExplorerView中的JavaFX文件,选择"Run As"->"Run...",如图7所示:
 

 图7 在Eclipse中运行JavaFX

    在打开Run对话框后,从左侧的列表中选择JavaFX应用程序,然后按New launch configuration图标。最后"New_configuration"被建立。选中New_configuration,然后点Run来运行JavaFX程序。
八、Java类、对象和自动数据绑定
 
    JavaFX不仅限于用户接口,它还可以定义类。在接下来的例子中,我们将建立个用于计算投资的计算器。这个用户接口允许用户输入最初资金、年汇报率,返还比率和投资时间来计算投资汇报率(界面如图8所示),源程序的代码可参考InvestmentCalculator.fx文件。
 

图8 投资计算器界面.

在这个程序中我们定义了一个InvestmentTool类。在InvestmentTool类中的每一个属性定义将使用如下的语法:
 
attribute AttributeName : AttributeType Cardinality;
 
    在JavaFX中,"methods"被定义为functions或operations。一个函数是一个只包含一系列变量表达式和返回表达式的方法。如下面代码定义了一个计算直角三角形斜边长度的函数:

function hypotenuseLength (side1, side2){
 var a = side1 * side1;
 var b = side2 * side2;
 var c = Math.sqrt(a+b);
 return c;
}
    一个操作,换句话说,就是可以包含任意数量表达式(包括变量声明、循环、条件等)。另外,也可以和JavaScript的操作和函数类似,可以先是一个类对象,但无需和类发生关系。
    InvestmentTool计算器的实例和var calculator = InvestmentTool表达式有关。当JavaFX类没有显式声明构造方法时,这个实例将使用如上的符号创建。
    那么JavaFX类和objects如何被使用呢?如InvestmentTool实例如何被一个JavaFX用户接口使用呢?我们可以使用JavaFX强有力的自动数据绑定来处理这个问题,InvestmentTool的属性值可以和用户接口组件相关联。当对象变化时,组件值就跟着变化。在下面的代码中将演示如何进行数据绑定(注意下面代码的bind关键字的使用),更详细的代码可以查看InvestmentCalculator.fx。

Spinner {
       min: 0
 max: 1000000
 stepSize: 100
 value: bind calculator.contributionAnnual
 font: Font{faceName: "ARIAl", size: 18}
九、触发器
    自动绑定将使用户接口和对象同步。但如何处理象本例子的事件呢?我们可以注意到,在界面上没有按钮来响应用户的动作。JavaFX的另一个特性就是这个本节要讲的触发器。触发器是数据编辑时引发的事件。它们类似于监听方法,但是要比使用监听方法更简单。在这个例子中,触发器和属性的更新变化进行绑定。也就是说,在任何时候,INvestmentTool实例的属性的值发生改变,"update"触发器就会被引发,并调用getReturn()方法。代码如下:

trigger on InvestmentTool.numberOfYears = value
    然而,一个触发器可以被安装在任何类型上来监视它们的变化。触发器甚至还可以被安装在实例创建甚至在多值属性(如数组)的插入、替换或删除上。

十、静态类型
    当我们在查看InvestmentTool类的定义时,类的属性都是静态类型的。因此,在JavaFX中和JavaScript不同,JavaFX是一种静态类型语言。类似JavaScript,我们也可以不声明变量的类型,在这种情况下,变量就被指定为所使用的类型。在下面的代码中x将被指定为Integer类型:
   
var x;
x = 3;
 
然而,由于它是静态类型,变量一但指定类型,在JavaFX中这个变量就不能被赋予其
他类型的值。如下面的代码在JavaScript中是合法的,但在JavaFX中,将会抛出"IncompatiableTypes"编译错误。

var x;
x = 3;
x = "hello";
    在类、对象中,JavaFX支持四种初级类型:String、Boolean、Number和Integer。这些分别和Java的java.lang.String, java.lang.Boolean, java.lang.Number,以及和byte, short, int, long, 或 java.math.BigInteger中的任何类型对应。

十一、在JavaFX中使用Java 类
 
    我们可以从上面的代码中已经注意到了getReturn()或hypotenuseLength(a, b)方法,这两个方法都是java的java.lang.Math类方法的引用。为了引用java类,在InvestmentCalculator.fx中包含了import表达式,代码如下所示:

import JavaFX.ui.*;
import java.lang.Math;
    事实上,JavaFX可以导入所有的Java类和接口,就象它们在标准Java应用程序中使用的一样。JavaFX的支持者确信这个特性可以使JavaFX重用很多已经存在的Java代码,这样可以降低学习另一种脚本语言的曲线。

十二、JavaFX仍然年轻
    从上面的代码可以看出,用JavaFX开发GUI程序,即快速,又容易。几乎和大名鼎鼎的SWING具有同样的功力。同时由于它可以使用Java的资源变得更加强大和更有弹性。但JavaFX仍然非常年轻,它仍然有很多的路要走。我们在采用JavaFX实现自己的项目之前还需要仔细了考虑一下,是否真的有必要。就JavaFX目前的状态,仍处在测试阶段,这种语言已经被暗示并不能完全使开发人员解决他们未解决的问题。而JavaFX现在存在的目的就是为了使已经存在的Java技术变得更容易使用。

到现在为止,JavaFX还没有可视化的开发环境。对于一种定位于使用户满意的用户接口和RIA开发需要的语言或技术,就必须有相关的可视化环境,否则毫无意义。而Chris Oliver也在他的weblog中提到,虽然我现在并未开时间来开发一个强大的支持JavaFX的开发环境,但一但它的语言和API未定后,我将会为其披上华丽的外衣。
    顺便说一句,有很多人期望SunJavaFX来替换Swing。但Sun强调并不会这样做。我们可以直接从OpenJFX FAQ页上看到Sun的留言“我们并不会使用JavaFX来代替Swing,而只是通过JavaFX脚本使Swing在使用上变得更容易”。

现在关于JavaFX的开发文档和IDE支持还非常少。即使支持NetBeans和Eclipse的插
件的功能和数量也非常有限,如只有简单的编程特性。而一些高级的特性,如语法颜色高亮显示和代码格式化现在还没有。而唯一的高级特性“代码助手”的功能也十分有限。图9是使用插件编辑JavaFX代码的截图。

Sun

RIA

JavaFX

软件


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134