仅使用标准 JavaFX API,您就可以利用这些Bindings.selectXXX
方法来观察“属性的属性”。
例如:
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.paint.Color;
public class Cell {
private final ObjectProperty<Shape> shape = new SimpleObjectProperty<>(new Shape());
public final ObjectProperty<Shape> shapeProperty() {
return this.shape;
}
public final Cell.Shape getShape() {
return this.shapeProperty().get();
}
public final void setShape(final Cell.Shape shape) {
this.shapeProperty().set(shape);
}
public static class Shape {
private final IntegerProperty size = new SimpleIntegerProperty(0);
private final ObjectProperty<Color> color = new SimpleObjectProperty<>(Color.BLACK);
public final IntegerProperty sizeProperty() {
return this.size;
}
public final int getSize() {
return this.sizeProperty().get();
}
public final void setSize(final int size) {
this.sizeProperty().set(size);
}
public final ObjectProperty<Color> colorProperty() {
return this.color;
}
public final javafx.scene.paint.Color getColor() {
return this.colorProperty().get();
}
public final void setColor(final javafx.scene.paint.Color color) {
this.colorProperty().set(color);
}
}
public static void main(String[] args) {
Cell cell = new Cell();
Bindings.selectInteger(cell.shapeProperty(), "size").addListener(
(obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));
cell.getShape().setSize(10);
cell.setShape(new Shape());
Shape s = new Shape();
s.setSize(20);
cell.setShape(s);
}
}
将产生(期望的)输出
Size changed from 0 to 10
Size changed from 10 to 0
Size changed from 0 to 20
这个 API 有一点遗留的感觉,因为它依赖于将属性名称作为字符串传递,因此不是类型安全的,无法在编译时检查。此外,如果任何中间属性为空(例如,如果cel.getShape()
在此示例中返回 null),则绑定会生成烦人且冗长的警告消息(即使这应该是受支持的用例)。
Tomas Mikula 在他的ReactFX 库中有一个更现代的实现,请参阅这篇文章以获得描述。使用 ReactFX,您可以:
public static void main(String[] args) {
Cell cell = new Cell();
Var<Number> size = Val.selectVar(cell.shapeProperty(), Shape::sizeProperty);
size.addListener(
(obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));
cell.getShape().setSize(10);
cell.setShape(new Shape());
Shape s = new Shape();
s.setSize(20);
cell.setShape(s);
}
最后,如果您要创建一个单元格列表,您可以创建一个ObservableList
指定的extractor
. 提取器是将列表中的每个元素 (each Cell
) 映射到 s 数组的函数Observable
。如果这些Observable
s 中的任何一个发生更改,则列表会触发更新事件。所以你可以做
ObservableList<Cell> cellList =
FXCollections.observableArrayList(cell -> new Observable[] {Bindings.selectInteger(cell.shapeProperty(), "size")});
使用标准 API,或
ObservableList<Cell> cellList =
FXCollections.observableArrayList(cell -> new Observable[] {Val.selectVar(cell.shapeProperty(), Shape::sizeProperty)});
使用 ReactFX。然后只需将 a 添加ListChangeListener
到列表中,如果大小发生变化(或形状更改为具有不同大小的新形状),它将被通知。您可以根据需要在返回的数组中添加任意数量的作为单元格的属性(或属性的属性)的可观察对象。