基于 Bindings.size() 的 JavaFX 绑定未被触发
JavaFX Bindings based on Bindings.size() is not getting triggered
是的,这个问题和几年前问的很相似。事实上,我的示例代码也是基于那个代码的。我也尝试了那里给出的答案,但没有用。
示例代码如下:
package com.example.bindingssize;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.IntegerBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class HelloApplication extends Application {
private IntegerBinding sizeBinding;
private BooleanBinding isEven;
@Override
public void start(Stage primaryStage) {
final ObservableList<String> list = FXCollections.observableArrayList();
primaryStage.setTitle("Demonstrator");
// Button
Button addButton = new Button();
addButton.setText("Add Element");
addButton.setOnAction(event -> list.add("TEST"));
// ListView
ListView<String> lv = new ListView<>();
lv.setItems(list);
// Add elements to root
VBox root = new VBox();
root.getChildren().add(addButton);
root.getChildren().add(lv);
// Show scene
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
sizeBinding = Bindings.size(list);
isEven = Bindings.createBooleanBinding(() -> {
System.out.println(sizeBinding.get()); // key line 1 of 2
System.out.println("inside isEven");
return list.size() % 2 == 0;
}, sizeBinding);
// key line 2 of 2
isEven.addListener((obs, o, n) -> System.out.println(isEven.get() ? "Even" : "Odd"));
}
public static void main(String[] args) {
launch();
}
}
以上代码有效。每次单击添加按钮时,'isEven' 中的打印语句都会按预期打印。但是,此行为完全取决于 2 个关键行。如果缺少一个或两个关键行,打印语句将不会打印任何内容。在这里,我将所有内容都设为 class 的字段,因此它们不应该被垃圾收集。那么这种行为的原因是什么?
这是 JavaFX 11.0.2,AdoptOpenJDK-11.0.11+9,在 macOS Catalina 上。
绑定是惰性的
在 JavaFX 中,绑定具有“有效”状态。当绑定处于有效状态时值可能发生更改,则绑定会触发失效事件。但是,如果绑定当前无效,则不会触发任何失效事件。 “验证”绑定的方法是查询它的值。此设置允许绑定仅在需要该值时计算其值。
取决于绑定
您的 isEven
绑定依赖于 sizeBinding
绑定。这是通过 isEven
绑定通过 InvalidationListener
观察 sizeBinding
绑定来实现的。如上所述,仅当绑定从有效状态变为无效状态时才会触发失效事件。
问题是,除了你的 println(sizeBinding.get())
调用,你从不查询 sizeBinding
的值。这意味着您永远不会验证绑定,这意味着 isEven
绑定永远不知道要重新计算它的值。如果你有:
isEven = Bindings.createBooleanBinding(() -> sizeBinding.get() % 2 == 0, sizeBinding);
那就可以了。请注意,它查询 sizeBinding
值。
更改监听器
如果将 ChangeListener
添加到绑定中,则会立即计算该值。原因很简单:监听器同时传递了旧的 和新的 值。如果没有将 ChangeListener
添加到 isEven
绑定,绑定将保持惰性。而且由于您从不验证 isEven
绑定,因此它永远不需要(重新)计算其值。
但是,添加 ChangeListener
后,会急切地(重新)计算该值。但请注意 isEven
绑定只有在知道值已更改时才会重新计算其值。换句话说,您仍然必须确保 sizeBinding
绑定在适当的时候得到验证。
是的,这个问题和
示例代码如下:
package com.example.bindingssize;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.IntegerBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class HelloApplication extends Application {
private IntegerBinding sizeBinding;
private BooleanBinding isEven;
@Override
public void start(Stage primaryStage) {
final ObservableList<String> list = FXCollections.observableArrayList();
primaryStage.setTitle("Demonstrator");
// Button
Button addButton = new Button();
addButton.setText("Add Element");
addButton.setOnAction(event -> list.add("TEST"));
// ListView
ListView<String> lv = new ListView<>();
lv.setItems(list);
// Add elements to root
VBox root = new VBox();
root.getChildren().add(addButton);
root.getChildren().add(lv);
// Show scene
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
sizeBinding = Bindings.size(list);
isEven = Bindings.createBooleanBinding(() -> {
System.out.println(sizeBinding.get()); // key line 1 of 2
System.out.println("inside isEven");
return list.size() % 2 == 0;
}, sizeBinding);
// key line 2 of 2
isEven.addListener((obs, o, n) -> System.out.println(isEven.get() ? "Even" : "Odd"));
}
public static void main(String[] args) {
launch();
}
}
以上代码有效。每次单击添加按钮时,'isEven' 中的打印语句都会按预期打印。但是,此行为完全取决于 2 个关键行。如果缺少一个或两个关键行,打印语句将不会打印任何内容。在这里,我将所有内容都设为 class 的字段,因此它们不应该被垃圾收集。那么这种行为的原因是什么?
这是 JavaFX 11.0.2,AdoptOpenJDK-11.0.11+9,在 macOS Catalina 上。
绑定是惰性的
在 JavaFX 中,绑定具有“有效”状态。当绑定处于有效状态时值可能发生更改,则绑定会触发失效事件。但是,如果绑定当前无效,则不会触发任何失效事件。 “验证”绑定的方法是查询它的值。此设置允许绑定仅在需要该值时计算其值。
取决于绑定
您的 isEven
绑定依赖于 sizeBinding
绑定。这是通过 isEven
绑定通过 InvalidationListener
观察 sizeBinding
绑定来实现的。如上所述,仅当绑定从有效状态变为无效状态时才会触发失效事件。
问题是,除了你的 println(sizeBinding.get())
调用,你从不查询 sizeBinding
的值。这意味着您永远不会验证绑定,这意味着 isEven
绑定永远不知道要重新计算它的值。如果你有:
isEven = Bindings.createBooleanBinding(() -> sizeBinding.get() % 2 == 0, sizeBinding);
那就可以了。请注意,它查询 sizeBinding
值。
更改监听器
如果将 ChangeListener
添加到绑定中,则会立即计算该值。原因很简单:监听器同时传递了旧的 和新的 值。如果没有将 ChangeListener
添加到 isEven
绑定,绑定将保持惰性。而且由于您从不验证 isEven
绑定,因此它永远不需要(重新)计算其值。
但是,添加 ChangeListener
后,会急切地(重新)计算该值。但请注意 isEven
绑定只有在知道值已更改时才会重新计算其值。换句话说,您仍然必须确保 sizeBinding
绑定在适当的时候得到验证。