java

位置:IT落伍者 >> java >> 浏览文章

JavaFX绑定探究


发布日期:2023年02月07日
 
JavaFX绑定探究

数据绑定连接一些对象并且使它们同步尽管Swing的开发者们取决于额外的类库但是绑定是完全融入了JavaFX Script编程语言仔细看一看它运行的库显示了一个完全绑定构架其基本概念与JGoodies Binding 和 Beans Binding很相似(在我以前的文章Binding Beans中有做过比较)JSR (Beans Binding)可能不会成为Java的一部分所以一直寻找可代替品的开发者们会问自己JavaFX绑定构架是否可以通过简单的Java程序而进行使用

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

JavaFX SDK基础目录

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

Locations

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

一个Location的类型是通过子接口来决定的;例如IntLocation如果你要在srczip中查询IntLocationjava你不会看到它这是因为它的来源是来自两个文件XxxLocationst 和XxxTemplatestg每个子接口为类型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 i = IntVariablemake();

iaddChangeListener(new ChangeListener() {

@Override

public boolean onChange() {

Systemoutprintln(onChange(): + iget());

return false;

}

});

Systemoutprintln(iget() +

isMutable(): + iisMutable());

IntLocation i = IntConstantmake();

Systemoutprintln(iget() +

isMutable(): + iisMutable());

iset(iget());

}

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

LocationDemo输出

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

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

建立绑定

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

public class BindingDemo {

private static IntLocation i i;

public static void main(String[] args) {

i = IntVariablemake();

i = IntVariablemake();

BindingsbijectiveBind(i i);

showValues();

isetAsInt();

showValues();

isetAsInt();

showValues();

}

private static void showValues() {

Systemoutprintln(i: + iget());

Systemoutprintln(i: + iget());

}

}

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

i = IntVariablemake();

i = BindingsmakeBijectiveBind(i);

BindingDemo展示了如何使用它它包含在/today////sourceszip中具体细节请参考Resources显示了它的输出

BindingDemo输出

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

ObjectLocation loc = IntVariablemake();

ObjectLocation loc = BooleanVariablemake();

BindingsbijectiveBind(loc loc);

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

绑定Swing组件

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

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

在Eclipse的Members视图中SwingLabel

考虑到这个接口属于comsunjavafxruntimelocation包它是安全的假设这样的Locations可以绑定到其他的变量上以下的程序展示你是如何做到这个的为了编译并运行这个示例请添加lib/shared/javafxrtjar lib/desktop/javafxswingjar lib/desktop/Scenariojar 以及 lib/desktop/javafxguijar到你的类路径上

public class SwingDemo {

public static void main(String[] args) {

JFrame f = new JFrame();

fsetDefaultCloseOperation(JFrameEXIT_ON_CLOSE);

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

fsetContentPane(p);

SwingLabel label = new SwingLabel();

ObjectLocation text =

BindingsmakeBijectiveBind(label$text);

padd(labelgetJComponent() BorderLayoutCENTER);

fpack();

fsetVisible(true);

textset(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如图所示它通过一个复选框和一个滑块进行操作标签显示现在的volume值除此之外mute控制音量是否调整

音量控制示例

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

复选框设置mute

滑块设置volume

Mute选择或不选择复选框

Volume设置成滑块的位置

Mute启用或禁用滑块

Volume设置标签文本

完整的来源包含在sourceszip中细节请参考Resources部分它的结构很像我以前的文章中的版本所以很容易比较不同的版本为了编译并运行VolumeControl请添加lib/shared/javafxrtjar lib/desktop/javafxswingjar lib/desktop/Scenariojar 和lib/desktop/javafxguijar到你的类路径

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

sliderVolume = new SwingSlider();

sliderVolume$verticalset(true);

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

volumemuteaddChangeListener(new ChangeListener() {

@Override

public boolean onChange() {

sliderVolume$enabledset(! volumemuteget());

return true;

}

});

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

public boolean onChange() {

labelInfo$textset(volumevolumeget()toString());

return true;

}

通过使用toString()get()结果变成a String并传递labelInfo$textset()

总结

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

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

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

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

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

               

上一篇:Java:并发使一切变得简单

下一篇:Java应用的动态扩展