JavaFX属性与绑定详解
立即解锁
发布时间: 2025-08-19 02:09:15 阅读量: 2 订阅数: 5 


JavaFX 9:构建现代Java客户端应用的权威指南
# JavaFX 属性与绑定详解
## 1. 属性绑定基础规则
在 JavaFX 中,每个 `Property` 对象一次最多只能有一个活跃的单向绑定,但可以有任意数量的双向绑定。`isBound()` 方法仅适用于单向绑定。若在单向绑定已生效时,再次使用不同的 `ObservableValue` 参数调用 `bind()` 方法,会解除现有的绑定并替换为新的绑定。
## 2. 理解 Binding 接口
`Binding` 接口定义了四个方法,揭示了该接口的用途。`Binding` 对象是一个 `ObservableValue`,其有效性可以通过 `isValid()` 方法查询,通过 `invalidate()` 方法设置。它有一个依赖项列表,可通过 `getDependencies()` 方法获取。最后,`dispose()` 方法表示该绑定将不再使用,其占用的资源可以被清理。
从 `Binding` 接口的简要描述中,我们可以推断它代表具有多个依赖项的单向绑定。每个依赖项可能是一个 `ObservableValue`,`Binding` 会注册到这些依赖项以接收失效事件。当调用 `get()` 或 `getValue()` 方法时,如果绑定失效,会重新计算其值。
JavaFX 属性和绑定框架没有提供实现 `Binding` 接口的具体类,但提供了多种轻松创建自定义 `Binding` 对象的方法:
- 扩展框架中的抽象基类。
- 使用工具类 `Bindings` 中的一组静态方法,从现有的常规 Java 值(即不可观察的值)、属性和绑定创建新的绑定。
- 使用各种属性和绑定类中提供的一组方法,形成一个流畅的接口 API 来创建新的绑定。
下面是一个通过扩展 `DoubleBinding` 抽象类创建绑定的示例,用于计算矩形的面积:
```java
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
public class RectangleAreaExample {
public static void main(String[] args) {
System.out.println("Constructing x with initial value of 2.0.");
final DoubleProperty x = new SimpleDoubleProperty(null, "x", 2.0);
System.out.println("Constructing y with initial value of 3.0.");
final DoubleProperty y = new SimpleDoubleProperty(null, "y", 3.0);
System.out.println("Creating binding area with dependencies x and y.");
DoubleBinding area = new DoubleBinding() {
private double value;
{
super.bind(x, y);
}
@Override
protected double computeValue() {
System.out.println("computeValue() is called.");
return x.get() * y.get();
}
};
System.out.println("area.get() = " + area.get());
System.out.println("area.get() = " + area.get());
System.out.println("Setting x to 5");
x.set(5);
System.out.println("Setting y to 7");
y.set(7);
System.out.println("area.get() = " + area.get());
}
}
```
在这个匿名内部类中,我们调用了父类 `DoubleBinding` 中的受保护 `bind()` 方法,告知父类我们希望监听 `DoubleProperty` 对象 `x` 和 `y` 的失效事件。最后,我们实现了父类 `DoubleBinding` 中的受保护抽象方法 `computeValue()`,以便在需要重新计算时进行实际计算。
运行上述程序,控制台输出如下:
```
Constructing x with initial value of 2.0.
Constructing y with initial value of 3.0.
Creating binding area with dependencies x and y.
computeValue() is called.
area.get() = 6.0
area.get() = 6.0
Setting x to 5
Setting y to 7
computeValue() is called.
area.get() = 35.0
```
注意,当我们连续两次调用 `area.get()` 时,`computeValue()` 只被调用了一次。
需要注意的是,`DoubleBinding` 抽象类包含一个空的 `dispose()` 默认实现和一个返回空列表的 `getDependencies()` 默认实现。为了使这个示例成为一个正确的 `Binding` 实现,我们应该重写这两个方法以使其行为正确。
## 3. 关键接口的特定类型专业化
除了 `Observable` 和 `InvalidationListener`,其余接口都是带有类型参数 `<T>` 的泛型接口。在这部分,我们将研究这些泛型接口如何专门化为特定类型:`Boolean`、`Integer`、`Long`、`Float`、`Double`、`String` 和 `Object`。
### 3.1 特定类型接口的通用主题
虽然泛型接口并非都以完全相同的方式进行专业化,但存在一个共同的主题:
- `Boolean` 类型直接进行专业化。
- `Integer`、`Long`、`Float` 和 `Double` 类型通过 `Number` 超类型进行专业化。
- `String` 类型通过 `Object` 类型进行专业化。
这个主题存在于所有关键接口的特定类型专业化中。例如,`ObservableValue<T>` 接口的子接口:
| 接口名称 | 扩展接口 | 额外方法 |
| ---- | ---- | ---- |
| `ObservableBooleanValue` | `ObservableValue<Boolean>` | `boolean get();` |
| `ObservableNumberValue` | `ObservableValue<Number>` | `int intValue(); long longValue(); float floatValue(); double doubleValue();` |
| `ObservableObjectValue<T>` | `ObservableValue<T>` | `T get();` |
| `ObservableIntegerValue`、`ObservableLongValue`、`ObservableFloatValue`、`ObservableDoubleValue` | `ObservableNumberValue` | 各自提供一个返回相应基本类型值的 `get()` 方法 |
| `ObservableStringValue` | `ObservableObjectValue<String>` | 继承返回 `String` 的 `get()` 方法 |
我们在示例中使用的 `get()` 方法定义在特定类型的 `ObservableValue` 子接口中,类似地,`set()` 方法定义在特定类型的 `WritableValue` 子接口中。
### 3.2 数值属性的绑定
这种派生层次结构的一个实际结果是,任何数值属性都可以对任何其他数值属性或绑定调用 `bind()` 方法。实际上,任何数值属性上的 `bind()` 方法签名如下:
```java
void bind(ObservableValue<? extends Number> observable);
```
任何数值属性和绑定都可以赋值给泛型参数类型。下面的示例展示了不同具体类型的数值属性可以相互绑定:
```java
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.FloatProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.p
```
0
0
复制全文
相关推荐










