JavaFX绑定探究

开发
本文向您介绍JavaFX的绑定,通过图文结合的方式和一些实例,对JavaFX SDK和如何建立JavaFX绑定等做出解释。

在进行JavaFX绑定之前,要明白,JavaFX建立在普通的Java SE运行上。为了在本文中展示这个示例,你需要为你的操作系统(在此只支持官方的Windows 和Mac OS X)下载合适的JavaFX SDK。具体请参考Resources。安装installation过程只需要几个步骤。在Windows的机器上,默认安装地址是C:\Program Files\JavaFX\javafx-sdk1.1. Mac OS X users should look at /Library/Frameworks/JavaFX.framework/Versions/1.1。

JavaFX SDK目录

图1. JavaFX SDK基础目录

  图1 显示了JavaFX SDK的基础目录。这个bin目录包括可执行编译并运行JavaFX Script程序。我们不使用它们。JavaFX(Script)documentation在docs中。文件src.zip包括部分JavaFX运行的来源。如果你打开它,你会注意到文件是以stg 和 .st结尾的。***lib和它的子目录包含库.jars。本文的示例取决于它们中的一些。

  Locations

  lib/shared/javafxrt.jar包含com.sun.javafx.runtime.location包。它的类和接口来自基本的JavaFX Binding的构建块。例如,Location接口代表一个值,它可能是可变的或是不能改变的,有效或无效的,空的或是非空。这样的状态可以通过相应的getters来查询,例如,isMutable()。如果Location的值是无效的,当update()方法被调用时,或该值被检索时,它会被更新。

  一个Location的类型是通过子接口来决定的;例如,IntLocation.。如果你要在src.zip中查询IntLocation.java,你不会看到它。这是因为它的来源是来自两个文件XxxLocation.st 和XxxTemplate.stg。每个子接口为类型XYZ添加getAsXYZ和and setAsXYZ()。还有DoubleLocation, FloatLocation, ShortLocation, CharLocation, LongLocation, BooleanLocation, ByteLocation和 ObjectLocation。

  其他的对象可能会附属于一个Location。当值与地址变化联系在一起的时候,change listeners可以接收到通知。***,Locations是很懒惰的:虽然当值无效的时候change listeners会得到通知,但是新的值不会被重新计算直到需要它的时候。到目前为止,我指谈论了接口的问题。当然,可以为我以上所提到的类型而随时执行Locations。

      public static void main(String[] args) {

  final IntVariable i1 = IntVariable.make(42);

  i1.addChangeListener(new ChangeListener() {

  @Override

  public boolean onChange() {

  System.out.println("onChange(): " + i1.get());

  return false;

  }

  });

  System.out.println(i1.get() +

  ", isMutable(): " + i1.isMutable());

  IntLocation i2 = IntConstant.make(24);

  System.out.println(i2.get() +

  ", isMutable(): " + i2.isMutable());

  i1.set(i2.get());

  }

  为了编译并运行LocationDemo1,请附加lib/shared/javafxrt.jar到你的类路径上。这个演示示例采用了IntVariable 和IntConstant类。两个都执行了IntLocation接口,因此是Locations。使用静态make()方法创建Instances。使用get()查询当前值。正如你在图2中所看到的,在初始化引发一个通知之后,设置一个值。它通过子抽象类ChangeListener来进行处理。

LocationDemo1输出

图2. LocationDemo1输出

  当地址内容已经改变的时候,它的onChange()方法被调用。该方法返回一个Boolean值,指示监听者是否仍然有效。返回false将导致监听者从监听者名单上删除。Javadoc建议,当相关的弱引用被报告清除的时候,那些做它们自己弱引用管理的监听者应该返回false。

  就像JGoodies Binding的ValueModel,还有Beans Binding的Property一样,Locations 读取和编写类型值提供了一个方法。它们也可以通知注册的监听者关于值的变化。***,你将会在以下的小节中看到它们用于建立绑定。

  建立Java绑定

  像Beans Binding 和JGoodies Binding一样,JavaFX运行包含一个辅助类来建立JavaFX绑定:com.sun.javafx.runtime.location.Bindings。它是用于在两个Locations之间建立bijective关系。这个意思是说如果一个值被更新,它所对应的也会被更新。在Locations被实例之后,它们被传递到bijectiveBind()。

  

      public class BindingDemo1 {

  private static IntLocation i1, i2;

  public static void main(String[] args) {

  i1 = IntVariable.make();

  i2 = IntVariable.make();

  Bindings.bijectiveBind(i2, i1);

  showValues();

  i1.setAsInt(10);

  showValues();

  i2.setAsInt(100);

  showValues();

  }

  private static void showValues() {

  System.out.println("i1: " + i1.get());

  System.out.println("i2: " + i2.get());

  }

  }

  bijectiveBind(i2, i1)在i1 和 i2之间建立两种依赖关系。如果其中一个被更新,例如,调用setAsInt(),其他的值也会变化。为了到达此目的,执行附加了两个监听者在Locations中分享状态。方便的方法makeBijectiveBind()创建一个新的Location并它绑定到现存的绑定上面。如下所示:

  i1 = IntVariable.make();

  i2 = Bindings.makeBijectiveBind(i1);

  BindingDemo2展示了如何使用它。它包含在/today/2009/06/02/sources.zip中。具体细节请参考Resources。图3显示了它的输出。

BindingDemo2输出

图3. BindingDemo2输出

  请注意只有可编译的类型才能使用bijectiveBind()来进行绑定。以下的代码行取自BindingDemo3.java(包含在sources.zip中的)。***眼看上去代码没什么问题。但是,它们会抛出ClassCastException异常。这里发生什么事情了呢?

  ObjectLocation loc1 = IntVariable.make();

  ObjectLocation loc2 = BooleanVariable.make();

  Bindings.bijectiveBind(loc1, loc2);

  在创建绑定的过程中,loc2.get()结果被传递到loc1的set()方法中。这个不会为Boolean 和 Integer工作的。为了避免这种问题,只要适当的确定参数泛型类型ObjectLocation。目前为止,我们已经看到两个变量是如何被同步的。以下的小节中将看一看Swing组件是如何被绑定的。

  绑定Swing组件

  几乎每个JavaFX Script教程都是由显示一个窗口,按钮或是标签的小程序开始的。JavaFX 使用Swing来构建并显示这些组件。因此,我们可以假设Swing融入了JavaFX运行。不久你将会看到,这个也会应用于绑定。

  lib/desktop/javafx-swing.jar文件包含javafx.ext.swing包。它的类包含了大多数常见的Swing组件。如果你检查它们,你将会注意到它们用$开始显示各区域。它们的类型是ObjectVariable,它可以执行ObjectLocation。

在Eclipse的Members视图中SwingLabel

图4. 在Eclipse的Members视图中SwingLabel

  考虑到这个接口属于com.sun.javafx.runtime.location包,它是安全的假设这样的Locations可以绑定到其他的变量上。以下的程序展示你是如何做到这个的。为了编译并运行这个示例,请添加lib/shared/javafxrt.jar, lib/desktop/javafx-swing.jar, lib/desktop/Scenario.jar, 以及 lib/desktop/javafxgui.jar到你的类路径上。

  

      public class SwingDemo1 {

  public static void main(String[] args) {

  JFrame f = new JFrame();

  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  JPanel p = new JPanel(new BorderLayout());

  f.setContentPane(p);

  SwingLabel label = new SwingLabel();

  ObjectLocation text =

  Bindings.makeBijectiveBind(label.$text);

  p.add(label.getJComponent(), BorderLayout.CENTER);

  f.pack();

  f.setVisible(true);

  text.set("Hello, JavaFX!");

  }

  }

  除了这个很有用的创建并显示窗口的Swing代码之外,还有三件比较重要的事情要做:

  SwingLabel被实例化并分配到label。

  Location被分配到test并绑定到label.的$text上。

  标签被有层次的添加到组件上。

  请注意你不能直接添加SwingLabel到容器中。相反。它的getJComponent()方法用来获取JComponent实例。

  虽然这个简单的例子展示了一个Swing组件如何被绑定到一个变量上的,但是却没有说明使用JavaFX 绑定的好处。在我以前的文章"Binding Beans,"中,我演示了如何使用JGoodies Binding 和 Beans Binding来执行一个简单的音量控制。

  VolumeControl示例

  音量控制是基于一个简单的特定应用的POJO叫做Volume。它有两个区域:volume 和mute。如图5所示,它通过一个复选框和一个滑块进行操作。标签显示现在的volume值。除此之外,mute控制音量是否调整。

 音量控制示例

图5. 音量控制示例

 涉及Swing组件和POJO区域之间的关系如下:

  复选框设置mute。

  滑块设置volume。

  Mute选择或不选择复选框。

  Volume设置成滑块的位置。

  Mute启用或禁用滑块。

  Volume设置标签文本。

  完整的来源包含在sources.zip中。细节请参考Resources部分。它的结构很像我以前的文章中的版本,所以很容易比较不同的版本。为了编译并运行VolumeControl,请添加lib/shared/javafxrt.jar, lib/desktop/javafx-swing.jar, lib/desktop/Scenario.jar, 和lib/desktop/javafxgui.jar到你的类路径。

  首先,所有相关的组件都要初始化。这个发生在initComponents()中。例如,垂直坏块被创建并有如下设置:

  sliderVolume = new SwingSlider();

  sliderVolume.$vertical.set(true);

  在initEventHandling()中建立绑定。例如,复选框与mute链接,用以下命令Bindings.bijectiveBind(checkboxMute.$selected, volume.mute); 当复选框被选择的时候禁用滑块是通过添加一个监听者到mute上实现的。

  

      volume.mute.addChangeListener(new ChangeListener() {

  @Override

  public boolean onChange() {

  sliderVolume.$enabled.set(! volume.mute.get());

  return true;

  }

  });

  每次volume.mute 改变的时候,onChange()就会被调用。如果它变成true,滑块就被禁用。如果变成false,滑块就再次使用。这个状态用sliderVolume.$enabled.set()来设置。相同的方法同样适用于创建标签文本。滑块的值用Integer代表,正如我们早前已经看到的,它不能绑定到Strings上。转换完成如下:

  

      public boolean onChange() {

  labelInfo.$text.set(volume.volume.get().toString());

  return true;

  }

  通过使用toString(),get()结果变成a String并传递labelInfo.$text.set()。

  总结

  很惊讶的看到JavaFX绑定在Swing应用程序中的使用是如此简单。虽然绑定构架还没有为这个所设计,但是它是一个相当体面的工作。尽管如此,本文还是故意忽视了一些问题:

  Sun会允许使用并可能重新分配部分JavaFX运行给非JavaFX应用程序吗?

  如何安全使用内部类?这里所描述的包还没有被设计成公共的APIS。

  为什么没有成熟的绑定构架给Swing开发者们使用?

  即使JavaFX绑定可以或是不能在产品环境中使用,但是对于它的内部研究还是充满乐趣和鼓舞的。

【编辑推荐】

  1. Red Hat CEO呼吁甲骨文继续保持Java开放
  2. 自学Javabean迅速成为Java高手
  3. Java通过JNI调用C语言的方法
  4. 高手Java核心技术学习笔记
  5. 成为Java高手需要注意的25个学习目标
责任编辑:王观 来源: 中国IT实验室
相关推荐

2014-10-20 13:57:59

JavaFX 8Java 8

2010-07-22 10:08:39

JavaFXJava

2010-03-03 09:38:05

JavaFX

2012-03-01 10:33:42

JavaJavaFX

2010-09-28 14:00:25

DOMAPI

2013-10-09 09:39:34

大数据

2022-08-12 12:23:55

golangmap数据结构

2017-05-18 15:02:36

AndroidGC原理JVM内存回收

2012-01-09 09:00:16

JavaJavaFX

2009-03-18 08:40:22

SunJava移动OS

2010-08-25 14:26:09

CSSdisplay

2010-11-26 14:33:10

MySQL系统变量

2022-11-02 15:11:44

LightHouseChrome插件

2009-10-16 16:32:42

中国布线市场

2010-08-26 10:08:50

CSSmargin

2013-09-09 16:46:38

Webkit内核

2013-06-04 15:41:31

iOS开发移动开发block

2017-03-06 16:13:41

深度学习人工智能

2017-02-15 09:25:36

iOS开发MQTT

2010-08-02 16:51:54

点赞
收藏

51CTO技术栈公众号