1.Scene Graph体系结构浅析
javafx以tree的形式组织nodes,每一个node就是一个control,即UI组件。
node分为leaf node与branch node, root node。
scene体系中最关键的类:
Scene:代表包含所有UI组件的顶级容器
Node:是一个抽象类,代表UI组件的基类
Parent:是一个抽象类,代表branch node的基类。
类层次结构:
Group用于为child nodes集合统一应用effects and transfroms
Region则是包含layout,及css样式的Controls
2.Properties与Binding
秒懂javafx中property的规范:
package propertydemo;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
class Bill {
// Define a variable to store the property
private DoubleProperty amountDue = new SimpleDoubleProperty();
// 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;}
}
理解监听机制:
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);
Bindings与property的关系
IntegerProperty num1 = new SimpleIntegerProperty(1);
IntegerProperty num2 = new SimpleIntegerProperty(2);
NumberBinding sum = num1.add(num2);
//也可以是这种方式:NumberBinding sum = Bindings.add(num1,num2);
System.out.println(sum.getValue());
num1.set(2);
System.out.println(sum.getValue());
Observable,ObservableValue,InvacationListener,ChangeListener
Observable与ObservableValue接口负责fire触发property改变通知。Observable触发InvacationListener,而ObservableValue负责触发ChangeListener.
我们知道几乎所有的javafx.beans.property包中的类都实现了ObservableValue接口,而ObservableValue接口又是Observable的子接口。所以每一个property类又是一个Observable(Value).
几点需要注意的:
Observable支持lazy compute懒提交。也就是当值改变之后,不会立即提交计算,只有当需要时在进行compute。
所以当值改变之后,该property就会处于invalid状态,会触发InvacationListener.
但是假如你的ObservableValue对象,添加的ChangeListener,这个lazy compute就会失效。
NumberBinding total =
Bindings.add(bill1.amountDueProperty().add(bill2.amountDueProperty()),
bill3.amountDueProperty());
total.addListener(new InvalidationListener() {
@Override public void invalidated(Observable o) {
System.out.println("The binding is now invalid.");
}
});
// First call makes the binding invalid
bill1.setAmountDue(200.00);
// The binding is now invalid
bill2.setAmountDue(100.00);
bill3.setAmountDue(75.00);
// Make the binding valid...
System.out.println(total.getValue());
自定义Bindings:
final DoubleProperty a = new SimpleDoubleProperty(1);
final DoubleProperty b = new SimpleDoubleProperty(2);
final DoubleProperty c = new SimpleDoubleProperty(3);
final DoubleProperty d = new SimpleDoubleProperty(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);
3.javaFx Collections
javafx Collections是基于java基础类库中的集合框架的,只不过是结合了javafx中的Observable,使之成为可以观察变化的集合。便于javafx的模型数据维护。
javafx.collections包中的主要类:
接口:
ObservableList, ObservableMap :被监听者集合
ListChangeListener MapChangeListener 监听器集合
类:
FXCollections:它是一个基于java.util.Collections的一比一复制品。只不过是做了一层javafx的本地化。但是它是最重要的类了,一切ObservableList/Map均由它的工厂方法产生。
ListChangeListener.Change MapChangeListener.Change:包含者列表或map中的所有变化。可以进行迭代操作。
Change类包含的变化种类有:排序变化,添加删除变化,更新变化。并有对应的判断方法。
// Use Java Collections to create the List.
List<String> list = new ArrayList<String>();
// Now add observability by wrapping it with ObservableList.
ObservableList<String> observableList = FXCollections.observableList(list);
observableList.addListener(new ListChangeListener() {
@Override
public void onChanged(ListChangeListener.Change change) {
System.out.println("Detected a change! ");
}
});
// Changes to the observableList WILL be reported.
// This line will print out "Detected a change!"
observableList.add("item one");
// This code will work with any of the previous ObservableList examples
observableList.addListener(new ListChangeListener() {
@Override
public void onChanged(ListChangeListener.Change change) {
System.out.println("Detected a change! ");
while (change.next()) {
System.out.println("Was added? " + change.wasAdded());
System.out.println("Was removed? " + change.wasRemoved());
System.out.println("Was replaced? " + change.wasReplaced());
System.out.println("Was permutated? " + change.wasPermutated());
}
}
});
ObservableList theList = ...;
theList.addListener(new ListChangeListener<Item>() {
public void onChanged(Change<tem> c) {
while (c.next()) {
if (c.wasPermutated()) {
for (int i = c.getFrom(); i < c.getTo(); ++i) {
//permutate
}
} else if (c.wasUpdated()) {
//update item
} else {
for (Item remitem : c.getRemoved()) {
remitem.remove(Outer.this);
}
for (Item additem : c.getAddedSubList()) {
additem.add(Outer.this);
}
但你要注意的是对这些集合的操作并不是线程安全的。所以你需要在必要时确保线程安全性。