JavaFX中的多个布尔绑定 [英] Multiple Boolean Binding in JavaFX
问题描述
我正在尝试将复选框绑定到多个复选框,如下所示:
I am attempting to bind a checkbox to multiple checkbox as seen below:
private void bindPanelToPackages(CheckBox panel, CheckBox ...pkg){
BooleanProperty panelBinding = null;
BooleanBinding binder = null;
for(CheckBox p: pkg){
if(panelBinding == null){
panelBinding = p.selectedProperty();
}
else{
binder = panelBinding.and(p.selectedProperty());
}
}
if(binder != null){
panel.selectedProperty().bind(binder);
}
else if(panelBinding != null){
panel.selectedProperty().bindBidirectional(panelBinding);
}
}
我想要的是允许双向组绑定' pkg'有多个项目。这样当我选择我的包时,会自动选择'面板',或者如果我选择'面板',将选择/取消选择所有'pkg'。我陷入困境:
What I want is to allow bidirectional group bindings when 'pkg' has more than one item. That way when I select my packages, the 'panel' will automatically be selected or if I select 'panel', all the 'pkg' will be selected/deselected. I got stuck at :
panel.selectedProperty()。bind(binder);
panel.selectedProperty().bind(binder);
并得到
JavaFX应用程序线程java.lang.RuntimeException:CheckBox.selected:无法设置绑定值。
"JavaFX Application Thread" java.lang.RuntimeException: CheckBox.selected : A bound value cannot be set.
因为我对'binder'进行了单向绑定。有没有办法可以执行与此相同的操作?:
since I did a one directional binding for 'binder'. Is there a way I can perform something equivalent to this?:
panel.selectedProperty()。bindBidirectional(binder);
panel.selectedProperty().bindBidirectional(binder);
我似乎无法在文档中找到它或者我没有找到正确的位置。谢谢!
I can't seem to find it in the docs or I'm not looking at the right places. Thanks!
推荐答案
条件选中所有复选框只能表示为 BooleanBinding
,而不是 BooleanProperty
。基本上,问题是没有明确定义条件 false
:有很多方法可以做到这一点(即,取消选中所有复选框的任何非空子集)。因此,您不能使用双向绑定:您必须在两个条件中的每一个上使用侦听器。
The condition "all check boxes are selected" can only be expressed as a BooleanBinding
, not as a BooleanProperty
. Basically, the issue is that making that condition false
is not clearly defined: there are many ways to do it (i.e. make any non-empty subset of all the checkboxes unselected). Hence you cannot use bidirectional bindings: you have to use listeners on each of the two conditions.
这是一个实现:
// must keep a reference to the Binding to prevent premature
// garbage collection:
BooleanBinding allSelected ;
private void bindPanelToPackages(CheckBox pane, CheckBox... packages) {
// BooleanBinding that is true if and only if all check boxes in packages are selected:
allSelected = Bindings.createBooleanBinding(() ->
// compute value of binding:
Stream.of(packages).allMatch(CheckBox::isSelected),
// array of thing to observe to recompute binding - this gives the array
// of all the check boxes' selectedProperty()s.
Stream.of(packages).map(CheckBox::selectedProperty).toArray(Observable[]::new));
// update pane's selected property if binding defined above changes
allSelected.addListener((obs, wereAllSelected, areAllNowSelected) ->
pane.setSelected(areAllNowSelected));
// use an action listener to listen for a direct action on pane, and update all checkboxes
// in packages if this happens:
pane.setOnAction(e ->
Stream.of(packages).forEach(box -> box.setSelected(pane.isSelected())));
}
和SSCCE:
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class MultipleCheckBoxSelection extends Application {
private BooleanBinding allSelected ;
@Override
public void start(Stage primaryStage) {
CheckBox selectAll = new CheckBox("Select all");
int numBoxes = 5 ;
CheckBox[] boxes = IntStream
.rangeClosed(1, numBoxes)
.mapToObj(i -> new CheckBox("Item "+i))
.toArray(CheckBox[]::new);
bindPanelToPackages(selectAll, boxes);
VBox root = new VBox(10, selectAll);
root.setStyle("-fx-padding: 15;");
Stream.of(boxes).forEach(box -> box.setStyle("-fx-padding: 0 0 0 10;"));
Stream.of(boxes).forEach(root.getChildren()::add);
Scene scene = new Scene(root, 250, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private void bindPanelToPackages(CheckBox pane, CheckBox... packages) {
// BooleanBinding that is true if and only if all check boxes in packages are selected:
allSelected = Bindings.createBooleanBinding(() ->
// compute value of binding:
Stream.of(packages).allMatch(CheckBox::isSelected),
// array of thing to observe to recompute binding - this gives the array
// of all the check boxes' selectedProperty()s.
Stream.of(packages).map(CheckBox::selectedProperty).toArray(Observable[]::new));
// update pane's selected property if binding defined above changes
allSelected.addListener((obs, wereAllSelected, areAllNowSelected) ->
pane.setSelected(areAllNowSelected));
// use an action listener to listen for a direct action on pane, and update all checkboxes
// in packages if this happens:
pane.setOnAction(e ->
Stream.of(packages).forEach(box -> box.setSelected(pane.isSelected())));
}
public static void main(String[] args) {
launch(args);
}
}
这篇关于JavaFX中的多个布尔绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!