利用JavaFX工具构建Reactive系统
JavaFX是Java中用来构建图形应用程序的新的标准库,但许多程序员仍然坚持在使用Swing甚至AWT。关于如何利用JavaFX工具集中的新的超棒特性来构建响应式的快速应用程序,这里有一些建议!
1.属性值
如果你对JavaFX组件做过完整的了解,移动遇到过属性(Property)这个东西。FX库中几乎每个值都可以被观察,分区(divider)的宽度,图片的尺寸,文本标识(label)中的文字,一个列表中的子项以及复选框(checkbox)的状态。属性分成另类:可写属性和可读属性。可写值可以被修改,使用设置器方法或者直接修改。JavaFX会处理事件处置过程并确保每个依赖于此属性的组件都会被通知到。可读属性拥有能让你在其值被修改时接收到通知的方法。
示例:
//可读-且可写 StringPropertyname=newSimpleStringProperty("Emil"); //只读 ObservableBooleanValuenameIsEmpty=name.isEmpty();
2.绑定值
当你拥有一个可写和可读值的时候,你可以开始就这些值如何关联定义规则。一个可写属性可以被绑定到一个可读属性,如此其值总是会匹配到可读的这个。绑定并不会立即发生,不过它们会在值被观察之前进行(看看我在那里做的就明白了)。绑定可以是单向或者双向的。当然,如果它们之间是双向的,就需要两个属性都是可写的。
示例:
TextFieldfieldA=newTextField(); TextFieldfieldB=newTextField(); fieldA.prefWidthProperty().bind(fieldB.widthProperty());
3.可观察的列表
属性并不是唯一可以被观察的东西。如果列表是被封装到了一个ObservableList中,那么列表的成员同样也是可以被观察到的。ObservableList的响应模型是相当先进的。你不仅能在列表被修改时收到通知,也可以看到列表具体是如何被修改的。
示例:
List<String>otherList=Arrays.asList("foo","bar","bar"); ObservableList<String>list=FXCollections.observableList(otherList); list.addListener((ListChangeListener.Change<?extendsString>change)->{ System.out.println("Receivedevent."); while(change.next()){ if(change.wasAdded()){ System.out.println( "Items"+change.getAddedSubList()+"wasadded."); } if(change.wasRemoved()){ System.out.println( "Items"+change.getRemoved()+"wasremoved."); } } }); System.out.println("Oldlist:"+list); list.set(1,"foo"); System.out.println("Newlist:"+list);
上面代码的运行输出如下:
Oldlist:[foo,bar,bar] Receivedevent. Items[foo]wasadded. Items[bar]wasremoved. Newlist:[foo,foo,bar]
如你所见,设置操作只会触发一次事件。
4.StringConverter
有时你会发现自己要创建一个绑定时无需去提取一个组件中的值。这个的典型示例就是你有了一个从一个文本域(TextField)获取到的带有path的StringProperty。如果你想要有一个带有表示为Path的这个值的可观察属性,就需要去为它创建一个StringConverter。
示例:
TextFieldfileLocation=newTextField(); StringPropertylocation=fileLocation.textProperty(); Property<Path>path=newSimpleObjectProperty<>(); Bindings.bindBidirectional(location,path,newStringConverter<Path>(){ @Override publicStringtoString(Pathpath){ returnpath.toString(); } @Override publicPathfromString(Stringstring){ returnPaths.get(string); } });
对象属性并不是跟文本域的值进行的双向绑定。
5.Expressions
使用上述的Bindings类,你可以创建出任何类型的表达式。比如说你有了两个可以让用户输入信息的文本域。现在想要定义一个只读域,其中总是会包含一个字符串,如果两个串的长度相等,将会是两个串逐个字符间隔混在一起进行显示。如果长度不等,则显示一条帮助信息。
示例:
TextFieldfirst=newTextField(); TextFieldsecond=newTextField(); TextFieldmix=newTextField(); mix.textProperty().bind( Bindings.when( first.lengthProperty().isEqualTo(second.lengthProperty()) ).then(Bindings.createStringBinding( ()->{ intlength=first.lengthProperty().get(); StringfirstText=first.textProperty().get(); StringsecondText=second.textProperty().get(); char[]result=newchar[length*2]; for(inti=0;i<length;i++){ result[i*2]=firstText.charAt(i); result[i*2+1]=secondText.charAt(i); } returnnewString(result); }, first.textProperty(), second.textProperty() )).otherwise("Pleaseentertwostringsofexactlythesamelength.") );
这里只是JavaFX诸多特性的其中一点点。希望你可以找到更多利用这个事件系统的创造性方式!