JavaFX 实现链接属性
JavaFX implementing linked properties
在 JavaFX 中实现链接或相互依赖的属性的最佳方法是什么?
例如,我有一个区间,我想用三个整数属性 lower
、upper
和 range
来表示,这样 range = upper - lower
如果你尝试设置它也设置上限的范围(到 lower + range
)。
这在传统的 Java Beans(set/get 方法)中很简单,但是 JavaFX 属性包括 Observable 概念和绑定,它似乎很快变得复杂。
我尝试过绑定,但这会使目标 属性 无法设置,双向绑定也是如此,但我只能绑定 'equality',不能绑定表达式。
我已经开始将 range
实现为 javafx.beans.property.IntegerProperty
,但处理听众等似乎需要大量工作。
有更简单的方法吗?
编辑:
这就是使用 JavaBean 模式的结果:
private int lower = 0;
private int upper = 0;
public int getLower() {
return lower;
}
public void setLower(int lower) {
this.lower = lower;
}
public int getUpper() {
return upper;
}
public void setUpper(int upper) {
this.upper = upper;
}
public int getRange() {
return upper - lower;
}
public void setRange(int range) {
upper = lower + range;
}
我如何以 JavaFX 方式执行此操作?
这是我试过的
IntegerProperty lower = new SimpleIntegerProperty(this, "lower", 0);
IntegerProperty upper = new SimpleIntegerProperty(this, "upper", 0);
IntegerProperty range = new SimpleIntegerProperty(this, "range", 0);
public LinkedPropTest() { // Constructor
lower.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
range.setValue(upper.getValue() - lower.getValue());
});
upper.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
range.setValue(upper.getValue() - lower.getValue());
});
range.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
upper.setValue(range.getValue() + lower.getValue());
});
}
我认为可行,但我必须定义一个 'dummy' 属性 并且(我认为)添加 ChangeListeners 会破坏任何使用惰性求值的机会。
好的,我们需要:
- 两个默认
IntegerProperty
对象作为 SimpleIntegerProperty
- 和一项源自
IntegerPropertyBase
的自定义 IntegerProperty
来实现一些满足您需要的特殊行为。
所以我们有您的属性作为成员:
private final IntegerProperty lower = new SimpleIntegerProperty(0);
private final IntegerProperty upper = new SimpleIntegerProperty(0);
private final IntegerProperty range = new IntegerPropertyBase() {
{
upper.addListener(obs -> update());
lower.addListener(obs -> update());
}
@Override
public String getName() {
return "range";
}
@Override
public Object getBean() {
return Main.this;
}
private void update() {
super.set(upper.get() - lower.get());
}
@Override
public void set(int newValue) {
upper.set(lower.get() + newValue);
}
};
我们的自定义 属性 基本上是一个可观察的合数,具有可设置的特殊情况。所以我们覆盖了一些方法并注册了必要的监听器。
以及一些示例代码来测试/验证这一点:
private void printStats() {
System.out.println("lower : " + lower.get() + " - upper: "
+ upper.get() + " - range: " + range.get());
System.out.println();
}
@Override
public void start(Stage primaryStage) {
lower.addListener(obs -> {System.out.println("Lower changed"); printStats();});
upper.addListener(obs -> {System.out.println("Upper changed"); printStats();});
range.addListener(obs -> {System.out.println("Range changed"); printStats();});
System.out.println(" ######### TEST #1 #############");
lower.set(5);
System.out.println(" ######### TEST #2 #############");
upper.set(5);
System.out.println(" ######### TEST #3 #############");
range.set(10);
}
在 JavaFX 中实现链接或相互依赖的属性的最佳方法是什么?
例如,我有一个区间,我想用三个整数属性 lower
、upper
和 range
来表示,这样 range = upper - lower
如果你尝试设置它也设置上限的范围(到 lower + range
)。
这在传统的 Java Beans(set/get 方法)中很简单,但是 JavaFX 属性包括 Observable 概念和绑定,它似乎很快变得复杂。
我尝试过绑定,但这会使目标 属性 无法设置,双向绑定也是如此,但我只能绑定 'equality',不能绑定表达式。
我已经开始将 range
实现为 javafx.beans.property.IntegerProperty
,但处理听众等似乎需要大量工作。
有更简单的方法吗?
编辑: 这就是使用 JavaBean 模式的结果:
private int lower = 0;
private int upper = 0;
public int getLower() {
return lower;
}
public void setLower(int lower) {
this.lower = lower;
}
public int getUpper() {
return upper;
}
public void setUpper(int upper) {
this.upper = upper;
}
public int getRange() {
return upper - lower;
}
public void setRange(int range) {
upper = lower + range;
}
我如何以 JavaFX 方式执行此操作? 这是我试过的
IntegerProperty lower = new SimpleIntegerProperty(this, "lower", 0);
IntegerProperty upper = new SimpleIntegerProperty(this, "upper", 0);
IntegerProperty range = new SimpleIntegerProperty(this, "range", 0);
public LinkedPropTest() { // Constructor
lower.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
range.setValue(upper.getValue() - lower.getValue());
});
upper.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
range.setValue(upper.getValue() - lower.getValue());
});
range.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
upper.setValue(range.getValue() + lower.getValue());
});
}
我认为可行,但我必须定义一个 'dummy' 属性 并且(我认为)添加 ChangeListeners 会破坏任何使用惰性求值的机会。
好的,我们需要:
- 两个默认
IntegerProperty
对象作为SimpleIntegerProperty
- 和一项源自
IntegerPropertyBase
的自定义IntegerProperty
来实现一些满足您需要的特殊行为。
所以我们有您的属性作为成员:
private final IntegerProperty lower = new SimpleIntegerProperty(0);
private final IntegerProperty upper = new SimpleIntegerProperty(0);
private final IntegerProperty range = new IntegerPropertyBase() {
{
upper.addListener(obs -> update());
lower.addListener(obs -> update());
}
@Override
public String getName() {
return "range";
}
@Override
public Object getBean() {
return Main.this;
}
private void update() {
super.set(upper.get() - lower.get());
}
@Override
public void set(int newValue) {
upper.set(lower.get() + newValue);
}
};
我们的自定义 属性 基本上是一个可观察的合数,具有可设置的特殊情况。所以我们覆盖了一些方法并注册了必要的监听器。
以及一些示例代码来测试/验证这一点:
private void printStats() {
System.out.println("lower : " + lower.get() + " - upper: "
+ upper.get() + " - range: " + range.get());
System.out.println();
}
@Override
public void start(Stage primaryStage) {
lower.addListener(obs -> {System.out.println("Lower changed"); printStats();});
upper.addListener(obs -> {System.out.println("Upper changed"); printStats();});
range.addListener(obs -> {System.out.println("Range changed"); printStats();});
System.out.println(" ######### TEST #1 #############");
lower.set(5);
System.out.println(" ######### TEST #2 #############");
upper.set(5);
System.out.println(" ######### TEST #3 #############");
range.set(10);
}