如何使用 Bindings.when 将按钮 disableProperty 与 TableView Selecteditem 绑定 属性
How to use Bindings.when to bind button disableProperty with a TableView Selecteditem property
我有一个包含模型 class 的 TableView,它有一个布尔值属性,如下所示
@FXML
TableView<Model> tableView;
型号Class:
class Model{
BooleanProperty valid;
public Model()
{
valid = new SimpleBooleanProperty();
}
... getters and setters
}
我想要实现的是将按钮禁用 属性 与模型 class 中的选定项目有效 属性 从 table 视图绑定,我知道我可以通过监听器实现这一点,但是使用监听器需要首先正确设置初始值,因为在发生一些变化之前它们不会被触发,例如在这种情况下,如果 [=42 中没有选定的项目=] 并且按钮从一开始就设置为不禁用,它仍然是那样,直到监听器被触发,这就是为什么我更喜欢使用绑定,因为它不关心初始值。有什么办法也可以用 Bindings 做到这一点吗?
我试过的:
我试过这个:
transferButton.disableProperty().bind(Bindings.when(tableView.getSelectionModel().selectedItemProperty().isNotNull()).then(
tableView.getSelectionModel().getSelectedItem().valideProperty()
).otherwise(false));
但问题是我收到以下错误:
return value of "javafx.scene.control.TableView$TableViewSelectionModel.getSelectedItem()" is null
即使我为绑定设置了条件:Bindings.when(tableView.getSelectionModel().selectedItemProperty().isNotNull()
您可以使用实现侦听器的自定义绑定:例如:
transferButton.disableProperty().bind(new BooleanBinding() {
{
tableView.getSelectionModel().selectedItemProperty().addListener(obs, oldSelection, newSelection) -> {
if (oldSelection != null) unbind(oldSelection.validProperty());
if (newSelection != null) bind(newSelection.validProperty());
invalidate();
});
bind(tableView.getSelectionModel().selectedItemProperty());
}
@Override
protected boolean computeValue() {
Model selection = tableView.getSelectionModel().getSelectedItem();
if (selection == null) return true ;
return ! selection.isValid();
}
});
Bindings
API 中还有一个 selection
API 可以使用,尽管它不可靠并且会在选择为空时生成虚假警告:
transferButton.disableProperty().bind(Bindings.selectBoolean(
tableView.getSelectionModel().selectedItemProperty(),
"valid"
)).not());
这是自定义 select 绑定的方法,它使用函数提供嵌套属性(类似于核心 SelectBinding,只是通过提供嵌套属性的函数替换对嵌套属性的反射访问)
基本思路
- 从绑定到根开始
- 在依赖项中保留绑定链
- 在验证时更新绑定链(只要绑定无效就无需执行任何操作)
- 实施状态清理
代码示例(这里只有一个功能,可以扩展为更长的链,但是,通过添加更多功能并遍历供应商)
/**
* Custom binding to a nested property using a Function to provide the nested.
*/
public class XSelectBinding<R, T> extends ObjectBinding<T> {
private ObservableList<ObservableValue<?>> dependencies;
private Function<R, ObservableValue<T>> provider;
public XSelectBinding(ObservableValue<R> root, Function<R, ObservableValue<T>> provider) {
if (root == null) {
throw new NullPointerException("root must not be null");
}
if (provider == null) {
throw new NullPointerException("provider must not be null");
}
dependencies = FXCollections.observableArrayList(root);
this.provider = provider;
bind(root);
}
/**
* Implemented to update dependencies and return the value of the nested property if
* available
*/
@Override
protected T computeValue() {
onValidating();
ObservableValue<?> child = dependencies.size() > 1 ? dependencies.get(1) : null;
return child != null ? (T) child.getValue() : null;
}
/**
* Updates dependencies and bindings on validating.
*/
protected void onValidating() {
// grab the root
ObservableValue<R> root = (ObservableValue<R>) dependencies.get(0);
// cleanup bindings and dependencies
unbindAll();
// rebind starting from root
dependencies.add(root);
ObservableValue<T> nestedProperty = root.getValue() != null ?
provider.apply(root.getValue()) : null;
if (nestedProperty != null) {
dependencies.add(nestedProperty);
}
bind(dependencies.toArray(new ObservableValue<?>[dependencies.size()]));
}
/**
* Unbinds and clears dependencies.
*/
private void unbindAll() {
unbind(dependencies.toArray(new ObservableValue<?>[dependencies.size()]));
dependencies.clear();
}
@Override
public ObservableList<?> getDependencies() {
return FXCollections.unmodifiableObservableList(dependencies);
}
/**
* Implemented to unbind all dependencies and clear references to path providers.
*/
@Override
public void dispose() {
unbindAll();
provider = null;
}
}
在 OP 的上下文中使用:
// XSelectBinding
ObjectBinding<Boolean> xSelectBinding = new XSelectBinding<Model, Boolean>(
table.getSelectionModel().selectedItemProperty(),
item -> item.validProperty());
transferButton.disableProperty().bind(BooleanExpression.booleanExpression(xSelectBinding).not());
我有一个包含模型 class 的 TableView,它有一个布尔值属性,如下所示
@FXML
TableView<Model> tableView;
型号Class:
class Model{
BooleanProperty valid;
public Model()
{
valid = new SimpleBooleanProperty();
}
... getters and setters
}
我想要实现的是将按钮禁用 属性 与模型 class 中的选定项目有效 属性 从 table 视图绑定,我知道我可以通过监听器实现这一点,但是使用监听器需要首先正确设置初始值,因为在发生一些变化之前它们不会被触发,例如在这种情况下,如果 [=42 中没有选定的项目=] 并且按钮从一开始就设置为不禁用,它仍然是那样,直到监听器被触发,这就是为什么我更喜欢使用绑定,因为它不关心初始值。有什么办法也可以用 Bindings 做到这一点吗?
我试过的:
我试过这个:
transferButton.disableProperty().bind(Bindings.when(tableView.getSelectionModel().selectedItemProperty().isNotNull()).then(
tableView.getSelectionModel().getSelectedItem().valideProperty()
).otherwise(false));
但问题是我收到以下错误:
return value of "javafx.scene.control.TableView$TableViewSelectionModel.getSelectedItem()" is null
即使我为绑定设置了条件:Bindings.when(tableView.getSelectionModel().selectedItemProperty().isNotNull()
您可以使用实现侦听器的自定义绑定:例如:
transferButton.disableProperty().bind(new BooleanBinding() {
{
tableView.getSelectionModel().selectedItemProperty().addListener(obs, oldSelection, newSelection) -> {
if (oldSelection != null) unbind(oldSelection.validProperty());
if (newSelection != null) bind(newSelection.validProperty());
invalidate();
});
bind(tableView.getSelectionModel().selectedItemProperty());
}
@Override
protected boolean computeValue() {
Model selection = tableView.getSelectionModel().getSelectedItem();
if (selection == null) return true ;
return ! selection.isValid();
}
});
Bindings
API 中还有一个 selection
API 可以使用,尽管它不可靠并且会在选择为空时生成虚假警告:
transferButton.disableProperty().bind(Bindings.selectBoolean(
tableView.getSelectionModel().selectedItemProperty(),
"valid"
)).not());
这是自定义 select 绑定的方法,它使用函数提供嵌套属性(类似于核心 SelectBinding,只是通过提供嵌套属性的函数替换对嵌套属性的反射访问)
基本思路
- 从绑定到根开始
- 在依赖项中保留绑定链
- 在验证时更新绑定链(只要绑定无效就无需执行任何操作)
- 实施状态清理
代码示例(这里只有一个功能,可以扩展为更长的链,但是,通过添加更多功能并遍历供应商)
/**
* Custom binding to a nested property using a Function to provide the nested.
*/
public class XSelectBinding<R, T> extends ObjectBinding<T> {
private ObservableList<ObservableValue<?>> dependencies;
private Function<R, ObservableValue<T>> provider;
public XSelectBinding(ObservableValue<R> root, Function<R, ObservableValue<T>> provider) {
if (root == null) {
throw new NullPointerException("root must not be null");
}
if (provider == null) {
throw new NullPointerException("provider must not be null");
}
dependencies = FXCollections.observableArrayList(root);
this.provider = provider;
bind(root);
}
/**
* Implemented to update dependencies and return the value of the nested property if
* available
*/
@Override
protected T computeValue() {
onValidating();
ObservableValue<?> child = dependencies.size() > 1 ? dependencies.get(1) : null;
return child != null ? (T) child.getValue() : null;
}
/**
* Updates dependencies and bindings on validating.
*/
protected void onValidating() {
// grab the root
ObservableValue<R> root = (ObservableValue<R>) dependencies.get(0);
// cleanup bindings and dependencies
unbindAll();
// rebind starting from root
dependencies.add(root);
ObservableValue<T> nestedProperty = root.getValue() != null ?
provider.apply(root.getValue()) : null;
if (nestedProperty != null) {
dependencies.add(nestedProperty);
}
bind(dependencies.toArray(new ObservableValue<?>[dependencies.size()]));
}
/**
* Unbinds and clears dependencies.
*/
private void unbindAll() {
unbind(dependencies.toArray(new ObservableValue<?>[dependencies.size()]));
dependencies.clear();
}
@Override
public ObservableList<?> getDependencies() {
return FXCollections.unmodifiableObservableList(dependencies);
}
/**
* Implemented to unbind all dependencies and clear references to path providers.
*/
@Override
public void dispose() {
unbindAll();
provider = null;
}
}
在 OP 的上下文中使用:
// XSelectBinding
ObjectBinding<Boolean> xSelectBinding = new XSelectBinding<Model, Boolean>(
table.getSelectionModel().selectedItemProperty(),
item -> item.validProperty());
transferButton.disableProperty().bind(BooleanExpression.booleanExpression(xSelectBinding).not());