保持带有复选框的ListView与字符串列表同步

时间:2017-05-17 10:32:30

标签: java listview checkbox javafx

我想创建一个简单的ListView,并将其选定的项与列表中包含的字符串同步。我已经想通了我可以使用方法setCellFactory(),我在选择/取消选择项目时更新String列表,但我不知道如何做相反的事情,当字符串列表更改时更新ListView项目选择。

到目前为止,我有:

ListView<String> selectedAttributes = new ListView<>();
String[] toppings = {"Cheese", "Pepperoni", "Black Olives"};
        listViewAttributes.getItems().addAll(toppings);
        listViewAttributes.setCellFactory(CheckBoxListCell.forListView(new Callback<String, ObservableValue<Boolean>>() {
            @Override
            public ObservableValue<Boolean> call(String item) {
                BooleanProperty observable = new SimpleBooleanProperty();
                observable.addListener((obs, wasSelected, isNowSelected) -> {
                    if (isNowSelected) {
                        selectedAttributes.add(item);
                    } else {
                        selectedAttributes.remove(item);
                    }
                    System.out.println(selectedAttributes.size());

                });
                return observable;
            }
        }));

这使得在检查/取消选中ListView项时更新列表selectedAttributes元素,现在我想在更改列表内容时更新ListView项目选项。

我该怎么做?

2 个答案:

答案 0 :(得分:1)

假设selectedAttributesObservableSet,(或ObservableList,您仔细检查,不要多次添加相同的项目)添加

observable.set(selectedAttributes.contains(item));
selectedAttributes.addListener((ListChangeListener.Change<? extends String> c) -> 
    observable.set(selectedAttributes.contains(item)));

以下是采用这种方法的SSCCE:

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.collections.SetChangeListener;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class ListViewWithCheckBoxes extends Application {

    @Override
    public void start(Stage primaryStage) {
        ListView<String> toppingsList = new ListView<>();
        String[] toppings = {"Cheese", "Tomato Sauce", "Pepperoni", "Black Olives"};
        toppingsList.getItems().addAll(toppings);

        ObservableSet<String> selectedToppings = FXCollections.observableSet();

        toppingsList.setCellFactory(CheckBoxListCell.forListView(new Callback<String, ObservableValue<Boolean>>() {
            @Override
            public ObservableValue<Boolean> call(String item) {
                BooleanProperty observable = new SimpleBooleanProperty();
                observable.addListener((obs, wasSelected, isNowSelected) -> {
                    if (isNowSelected) {
                        selectedToppings.add(item);
                    } else {
                        selectedToppings.remove(item);
                    }
                    System.out.println(selectedToppings.size());

                });

                observable.set(selectedToppings.contains(item));
                selectedToppings.addListener((SetChangeListener.Change<? extends String> c) -> 
                    observable.set(selectedToppings.contains(item)));

                return observable;
            }
        }));


        // example of a button that changes what's selected in the list
        // This selects "Cheese" and "Tomato Sauce" and deselects everything else
        Button justCheese = new Button("Just a cheese pizza");
        justCheese.setOnAction(e -> {
            selectedToppings.clear();
            selectedToppings.add("Cheese");
            selectedToppings.add("Tomato Sauce");
        });

        BorderPane root = new BorderPane(toppingsList);
        root.setTop(justCheese);
        BorderPane.setMargin(justCheese, new Insets(5));

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

你做事的方式(用一个代表所选项目的单独列表)有点复杂。此时,为列表中具有可观察属性的项定义合适的模型类可能更容易:

public class Topping {

    private final String name ;

    private final BooleanProperty selected = new SimpleBooleanProperty();

    public Topping(String name) {
        this.name = name ;
    }

    public BooleanProperty selectedProperty() {
        return selected ;
    }

    public final boolean isSelected() {
        return selectedProperty().get();
    }

    public final void setSelected(boolean selected) {
        selectedProperty().set(selected);
    }

    public String getName() {
        return name ;
    }

    @Override
    public String toString() {
        return getName();
    }
}

然后剩下的代码就容易多了:

ListView<Topping> listView = new ListView<>();
List<Topping> toppings = Arrays.asList(
    new Topping("Cheese"), 
    new Topping("Pepperoni") , 
    new Topping("Black Olives"));
listView.getItems().addAll(toppings);

listView.setCellFactory(CheckBoxListCell.forListView(Topping::selectedProperty));

现在,您只需通过调用,例如

,即可在UI的复选框外部选择项目
for (Topping topping : toppings) {
    topping.setSelected(true);
}

以下是采用这种方法的SSCCE:

import java.util.Arrays;
import java.util.List;

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class ListViewWithCheckBoxes extends Application {

    @Override
    public void start(Stage primaryStage) {
        ListView<Topping> toppingsList = new ListView<>();
        Topping cheese = new Topping("Cheese");
        Topping tomSauce = new Topping("Tomato Sauce");
        Topping pepperoni = new Topping("Pepperoni");
        Topping blackOlives = new Topping("Black Olives");

        toppingsList.getItems().addAll(cheese, tomSauce, pepperoni, blackOlives);


        toppingsList.setCellFactory(CheckBoxListCell.forListView(Topping::selectedProperty));

        // example of a button that changes what's selected in the list
        // This selects "Cheese" and "Tomato Sauce" and deselects everything else

        Button justCheese = new Button("Just a cheese pizza");
        List<Topping> cheesePizzaToppings = Arrays.asList(cheese, tomSauce);

        justCheese.setOnAction(e -> toppingsList.getItems().forEach(
                topping -> topping.setSelected(cheesePizzaToppings.contains(topping))));

        BorderPane root = new BorderPane(toppingsList);
        root.setTop(justCheese);
        BorderPane.setMargin(justCheese, new Insets(5));

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static class Topping {

        private final String name ;

        private final BooleanProperty selected = new SimpleBooleanProperty();

        public Topping(String name) {
            this.name = name ;
        }

        public BooleanProperty selectedProperty() {
            return selected ;
        }

        public final boolean isSelected() {
            return selectedProperty().get();
        }

        public final void setSelected(boolean selected) {
            selectedProperty().set(selected);
        }

        public String getName() {
            return name ;
        }

        @Override
        public String toString() {
            return getName();
        }
    }


    public static void main(String[] args) {
        launch(args);
    }
}

答案 1 :(得分:1)

使用for循环将String项目与equals()方法列表进行比较,如果item相等,则使用下面的代码设置observable true。

ListView<String> listViewAttributes = new ListView<>();

        List<String> selectedAttributes = new ArrayList<>();
        selectedAttributes.add("Pepperoni");

        String[] toppings = { "Cheese", "Pepperoni", "Black Olives" };
        listViewAttributes.getItems().addAll(toppings);
        listViewAttributes
                .setCellFactory(CheckBoxListCell.forListView(new Callback<String, ObservableValue<Boolean>>() {
                    @Override
                    public ObservableValue<Boolean> call(String item) {
                        BooleanProperty observable = new SimpleBooleanProperty();
                        for (int i = 0; i < selectedAttributes.size(); i++) {
                            if (item.equals(selectedAttributes.get(i))) {
                                observable.set(true);
                            }
                        }
                        observable.addListener((obs, wasSelected, isNowSelected) -> {
                            if (isNowSelected) {
                                selectedAttributes.add(item);
                            } else {
                                selectedAttributes.remove(item);
                            }
                            System.out.println(selectedAttributes.size());

                        });
                        return observable;
                    }
                }));