JavaFX学习之道:使用JavaFX2.0的属性和绑定

目录(?)[+]

                                    (原文:斯科特霍梅尔/甲骨文高级技术专家)

原文地址:http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm

本教程通过一些可以编译和运行的例子描述了JavaFX的属性和绑定。关于JavaFX的安装,请参阅JavaFX安装指南。

概述

很多年以来,Java语言一直使用JavaBean来表示对象的属性,这种模式既包含API,也包含设计模式,它已经广泛地被Java应用程序开发者所熟知,开发工具也一直使用这种模式。 这个版本将属性支持引入到了JavaFX中,它基于经过验证的JavaBean的模式,但做了扩展和改进。

JavaFX的属性经常通过绑定来综合,这是一种表达变量间关系的强大的机制。当对象被绑定后,一个对象的改变会自动被反射到另一个对象。对应用程序来说,这是非常有用的。例如,绑定可以用在帐单票据跟踪程序中。在这种情况下,当一个独立的帐单改动后,总帐单将会自动改变。另外,绑定还可以应用到图形用户界面(GUI)中,用来将应用程序的基础数据的改变同步显示出来。

绑定集成了一个或多个资源,也称为“依赖关系”,绑定观察者保存依赖关系的列表,当检测到变化时自动更新列表。

绑定的API分为两大类:

1.高级别的API:提供了一种简单的方法来创建最常见的绑定用例。它的语法很容易学习和使用,特别是在支持自动完成功能的环境中。比如NetBeans IDE中。

2.低级别的API:提供额外的灵活性,可供高级开发人员在高级别API不能满足需要时使用。低级别的API是专为快速执行和小内存占用设计的。

本教程的所面部分将介绍这些API,并提供代码示例,您可以编译和运行它们。有关其他信息,请参阅JavaFX API文档。

理解属性

理解JavaFX的属性需要学习一些新的API和命名约定。你完全有可能只对使用包含属性的类感兴趣(反对在你自已的类中实现属性)。但例1将让你熟悉一种新的来自属性模式的命名规则。它定义了一个名为Bill的类,实现了一个名为amoutDue的属性。

例1:定义一个属性

import javafx.beans.property.DoubleProperty;

class Bill {

//定义一个变量来保存属性

private DoubleProperty amountDue = new DoubleProperty();

//定义一个getter方法来获取属性的值

public final double getAmountDue(){return amountDue.get();}

//定义一个setter来设定属性的值

public final void setAmountDue(double value){amountDue.set(value);}

//定义一个getter来访问属性

public DoubleProperty amountDueProperty() {return amountDue;}

}

amountDue对象是一个javafx.beans.property.DoubleProperty的类实例,被标以private来限制外部访问。这在Java或JavaBean程序开发中是一种标准做法。但是请注意,该对象的不是一个标准的Java基本数据类型,而是封装了Java基本数据类型,并增加了一些额外功能的封装类。(javafx.beans.property包中的类都内置了观察和绑定作为设计的一部分)。

属性方法命名规则如下:

l  getAmountDue()是一个标准的getter方法,返回当前值amountDue属性的值。按照惯例,它被声明为final。注意,此方法返回类型是双精度数值而不DoubleProperty类型。

l  setAmountDue(double)方法(也被声明为final)是一个标准的setter方法,用来设置属性的值。setter方法是可选的,其参数的类型也是双精度数值。

l  最后,amountDueProperty()方法定义了属性的getter。这是一种新的命名约定,方法中包含了属性的名称(在本例中是amountDue),然后加上“Property”。 返回类型是属性本身的类型(本例中是DoubleProperty)。

在用JavaFX构建GUI应用程序时,你会注意到某些API里的类已经实现了属性。例如:javafx.scene.shape.Rectangle类包含的属性arcHeight,arcWidth,height,width,x,y。对于这些属性,都有与前面提到的命名规则相对应的方法。例如,getArcHeight(),setArcHeight(double),arcHeightProperty()。 它们共同说明(对开发人员和工具),给定的属性存在。

例2:使用ChangeListener

import javafx.beans.value.ObservableValue;

import javafx.beans.value.ChangeListener;

public class Main {

public static void main(String[] args) {

Bill electricBill = new Bill();

electricBill.amountDueProperty().addListener(new ChangeListener(){

@Override public void changed(ObservableValue o,Object oldVal,

Object newVal){

System.out.println("Electric bill has changed!");

}

});

electricBill.setAmountDue(100.00);

}

}

运行该示例将在标准输出中打印消息“帐单已经改变”,证明更改侦听的起作用了。

使用高级别绑定API

高级别API是在你的应用程序中使用绑定的最快和最简单的方式。 它包括两个部分:Fluent API和绑定类。Fluent API将方法向各种依赖对象公开,而绑定类提供静态工厂方法。

要开始使用Fluent API,考虑一个简单的用例。其中两个整数是绑定的,以使他们的值观总是加在一起。在例3中,涉及三个变量:num1(依赖者),num2(依赖者)和sum(绑定)。依赖类型都IntegerProperty,绑定类型是NumberBinding。

例3:使用Fluent API

package bindingdemo;

import javafx.beans.property.IntegerProperty;

import javafx.binding.NumberBinding;

public class Main {

public static void main(String[] args) {

IntegerProperty num1 = new IntegerProperty(1);

IntegerProperty num2 = new IntegerProperty(2);

NumberBinding sum = num1.add(num2);

System.out.println(sum.getValue());

num1.set(2);

System.out.println(sum.getValue());

}

}

此代码绑定两个依赖,打印其总和。改变值num1并再次打印总和,结果是“3”和“4”,这证明了绑定起作用了。

也可以使用绑定类来做同样的事,如例4所示。

例4:使用绑定类

import javafx.beans.property.IntegerProperty;

import javafx.binding.NumberBinding;

import javafx.binding.Bindings;

public class Main {

public static void main(String[] args) {

IntegerProperty num1 = new IntegerProperty(1);

IntegerProperty num2 = new IntegerProperty(2);

NumberBinding sum = Bindings.add(num1,num2);

System.out.println(sum.getValue());

num1.setValue(2);

System.err.println(sum.getValue());

}

}

例5使用了两种方法。

例5:使用两种方法

import javafx.beans.property.IntegerProperty;

import javafx.binding.NumberBinding;

import javafx.binding.Bindings;

public class Main {

public static void main(String[] args) {

IntegerProperty num1 = new IntegerProperty(1);

IntegerProperty num2 = new IntegerProperty(2);

IntegerProperty num3 = new IntegerProperty(3);

IntegerProperty num4 = new IntegerProperty(4);

NumberBinding total =  Bindings.add(num1.multiply(num2),num3.multiply(num4));

System.out.println(total.getValue());

num1.setValue(2);

System.err.println(total.getValue());

}

}

例5修改代码来调用Fluent API的multiply和绑定类的add方法。你也应该知道,高级别API允许你定义算术运算时混合类型。结果类型的定义为采用与Java编程语言相同的规则:

1.   如果操作数是双精度,则结果也是双精度。

2.   如果不是双精度而是浮点型,其结果是一个浮点型。

3.   如果不是浮点型而是长整型,则结果是长整型。

4.   其他情况,结果是一个整数。

下一节探讨观察者,并演示失效监听与改变监听的不同。

探索ObservableValue,InvalidationListener和ChangeListener

属性和绑定类都实现了ObservableValue<T>接口,ObservableValue包装了值并允许它观察改变。JavaFX绑定和属性实现都支持懒惰计算,这意味着当变化发生时,该值不立即重新计算。重新计算稍后发生,也就时当再次请求时。

在例6中,帐单总数(一个绑定)在它检测到其中的一个依赖的第一时间被标记为无效。无论如何,只有当帐单总数被再次请求时,绑定对象才被重新计算。

例6:使用InvalidationListener

import javafx.beans.property.DoubleProperty;

import javafx.binding.NumberBinding;

import javafx.binding.Bindings;

import javafx.beans.value.InvalidationListener;

import javafx.beans.value.ObservableValue;

class Bill {

// Define the property

private DoubleProperty amountDue = new DoubleProperty();

// Define a getter for the property‘s value

public final double getAmountDue(){return amountDue.get();}

// Define a setter for the property‘s value

public final void setAmountDue(double value){amountDue.set(value);}

// Define a getter for the property itself

public DoubleProperty amountDueProperty() {return amountDue;}

}

public class Main {

public static void main(String[] args) {

Bill bill1 = new Bill();

Bill bill2 = new Bill();

Bill bill3 = new Bill();

NumberBinding total =          Bindings.add(bill1.amountDueProperty().add(bill2.amountDueProperty()),

bill3.amountDueProperty());

total.addListener(new InvalidationListener() {

@Override public void invalidated(ObservableValue o) {

System.out.println("The binding is now invalid.");

}

});

//第一次调用使绑定失效

bill1.setAmountDue(200.00);

//绑定现在无效

bill2.setAmountDue(100.00);

bill3.setAmountDue(75.00);

//绑定现在有效

System.out.println(total.getValue());

//再次使用失效

bill3.setAmountDue(150.00);

//使它有效

System.out.println(total.getValue());

}

}

通过改变单一帐单的值,绑定变为无效,无效监听器触发。但是,如果绑定已经无效,无效监听器将会再次被触发,即使其他帐单发生了变化。(在例6中,调用total.getValue()使绑定从无效变为有效)。我们知道这个是因为随后对依赖列表中任一帐单的改变导致了无准备监听器的再次触发。如果绑定仍然无效,则触发不会发生。

ObservableValue,InvalidationListener和ChangeListener的方法签名如下:

ObservableValue

l  public void addListener(ChangeListener listener)

l  public void addListener(InvalidationListener listener)

l  public T getValue()

l  public void removeListener(ChangeListener listener)

l  public void removeListener(InvalidationListener listener)

InvalidationListener

l  public void invalidated(ObservableValue observable)

ChangeListener

l  public void changed(ObservableValue observable, T oldValue, T newValue)

请注意,注册一个ChangeListener将强制执行急迫计算,即使ObservableValue的实现支持懒惰计算。对于一个懒惰计算值,在它被重新计算前,是不可能知道一个无效值是否已经被改变的。出于这个原因,产生改变事件需要急迫计算。而失效的事件,可以通过急迫实现产生,也可以通过懒惰实现产生。

使用低级别绑定API

如果高级别API不够满足您的需求,你总是可以使用低级别的API来代替。低级别的API是为那些需要更多灵活性(或更好性能)的开发者准备的,这些特性在高级API中没有提供。

示例7展示了使用低级别的API基本的例子。

例7:使用低级别API

import javafx.beans.property.DoubleProperty;

import javafx.binding.DoubleBinding;

public class Main {

public static void main(String[] args) {

final DoubleProperty a = new DoubleProperty(1);

final DoubleProperty b = new DoubleProperty(2);

final DoubleProperty c = new DoubleProperty(3);

final DoubleProperty d = new DoubleProperty(4);

DoubleBinding db = new DoubleBinding() {

{

super.bind(a, b, c, d);

}

@Override

protected double computeValue() {

return (a.get() * b.get()) + (c.get() * d.get());

}

};

System.out.println(db.get());

b.set(3);

System.out.println(db.get());

}

}

使用低级别的API调用继承自绑定类的一个方法并且覆写了computeValue()方法,返回当前绑定的值。例7通过这一个自定义的DoubleBinding子类完成这一工作。调用super.bind()向上将依赖传递给DoubleBinding,以便默认无效行为被保留。它通常没有必要为你检查绑定是否无效,这些行为通过基类来提供。

现在你已经有足够的信息来使用低级别API了,本文的后续版本将扩展这部份内容来说明如何展现各种不周的优化策略以使你自定义的绑定更有效率。

JavaFX学习之道:使用JavaFX2.0的属性和绑定

时间: 2024-11-09 00:39:37

JavaFX学习之道:使用JavaFX2.0的属性和绑定的相关文章

JavaFx学习之道:JavaFx初步了解

因为项目的需要,实在是没有办法了,试了很多种方案(RCP,SWT,Flex,Smartinvoke...),最终还是决定开始研究JavaFx...为了给用户更好地体验我们的"智能家居"! 以下是最近搜索得到的一些资料: 1.Oracle 上 JavaFx的下载页面:http://www.oracle.com/technetwork/java/javafx/overview/index.html 目前最新版本的SDK是2.1 JavaFX 2.1 Developer Preview -

JavaFX学习之道:文本Text及其特效

原文地址http://download.oracle.com/javafx/2.0/text/jfxpub-text.htm 文本讲述如何在JavaFX2.0应用中加入文本和如何为文本提供花俏的效果. 引子 JavaFX 2.0应用的图形内容包含一些对象,它们被组织在一个成为场景图的类树结构中.场景图中的每个元素成为一个结点,结点可以管理很多不同种类的内容,包括文本.结点可以转换和移动,也可以应用多种效果.为所有结点类型使用共同特点使得可以提供复杂的文本内容来满足现在的富网络应用(RIAs).

JavaFX学习之道:JavaFX之TableView

TableView表 TableColumn列 构建一个表主要有TableView,TableColumn,ObservableList,Bean. 添加列table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); ObservableList里面是存放的数据 table.setItems(observableList);添加数据 observableList里面一般是存放的Bean,列与Bean之间建立联系,从而获取值. 列与

JavaFX学习之道:FileChooser 、POI导出Excel文件

以下是JavaFX中导出Excel的核心代码: private HSSFWorkbook workbook; /* Build Operation Button Area */ Button exportBn = ButtonBuilder.create().text("导出Excel").prefWidth(80).prefHeight(30).build(); exportBn.setDefaultButton(true); exportBn.setOnAction(new Eve

JavaFX学习之道:FXML入门

FXML是JavaFX 2.0提供的新技术.你可能会问"什么是FXML?","对我来说有什么用?". FXML是一种在JavaFX应用程序中定义用户界面的,基于XML的声明性标记语言.FXML非常适合用来静态布局,如表单.控件和表格.使用FXML,您还可以通过脚本动态地构建布局. FXML的优势之一是基于XML,是大多数开发人员所熟悉的,尤其是Web开发人员和使用其他RIA平台的开发人员.另一个优点是,FXML是不是编译语言,你不需要重新编译代码就可看到您所做的更改

JavaFX学习之道:JavaFX API详解之Window,Stage,PopupWindow

stage包中包含 Window, Stage, PopupWindow, Popup, FileChooser, DirectoryChooser, Screen等类. 其中Window类可理解成一个窗体,用于存放Scene,并与用户操作.一般window作为窗体,都用其子类Stage和PopupWindow. 看一下Window作为窗体的顶级类包含的一些共同属性 eventDispatcher setEventDispatcher(EventDispatcher value) focused

JavaFX学习之道:详解JavaFX架构与框架

JavaFX 2.0平台是基于Java技术的富客户端平台.它使应用程序开发者更加容易的开发和部署跨平台的富互联网应用(RIA).JavaFX 2.0文档包含了JavaFX 2.0所提供的功能的概述. 图1描述了JavaFX 2.0平台的架构组件.后面的部分将对每一个组件进行逐一的描述.在JavaFX通用API的下面是用来运行JavaFX代码的引擎.这个引擎包括以下子组件:JavaFX高性能图形引擎(Prism);新的更小但更有效率的窗体系统(Glass);媒体引擎和Web引擎.虽然这些组件不是包

JavaFX学习之道:文本框TextField

原文地址http://download.oracle.com/javafx/2.0/ui_controls/text-field.htm TextField类实现了一种可以接受和显示文本输入的UI控件,它提供了接受用户输入的功能.和另一个文本输入控件PasswordField一起都继承了TextInput这个类,TextInput是所有文本控件的父类. Figure 8-1 是一个带有标签的典型文本框. Figure 8-1 Label and Text Field Description of

JavaFX学习之道:File Chooser

This chapter explains how to use the FileChooser class to enable users to navigate the file system. The samples provided in this chapter explain how to open one or several files, configure a file chooser dialog window, and save the application conten