Java 如何将侦听器添加到使用CheckBoxListCell的listview中的复选框

Java 如何将侦听器添加到使用CheckBoxListCell的listview中的复选框,java,listview,javafx,Java,Listview,Javafx,我有一个listview,它使用一个复选框ListCell来显示项目旁边带有复选框的列表。如何将侦听器添加到此复选框以了解何时选择或取消选择了某个项目? 解决方案 您不会将侦听器添加到复选框中。将侦听器添加到由例程与复选框关联的对象的observable属性中 成立协会: ListView<Task> checklist = new ListView<>(tasks); checklist.setCellFactory(CheckBoxListCell.forListVi

我有一个listview,它使用一个
复选框ListCell
来显示项目旁边带有复选框的列表。如何将侦听器添加到此复选框以了解何时选择或取消选择了某个项目?
解决方案

您不会将侦听器添加到复选框中。将侦听器添加到由例程与复选框关联的对象的observable属性中

成立协会:

ListView<Task> checklist = new ListView<>(tasks);
checklist.setCellFactory(CheckBoxListCell.forListView(Task::selectedProperty));
文档

javadoc中描述了该过程,如下所示:

getSelectedProperty
-一个回调函数,给定类型为T的对象 (这是从ListView.items列表中获取的值),将 返回一个ObservalEvalue,该值表示给定的 项目是否已选择。此可观察值将被绑定 双向(意味着单元格中的复选框将设置/取消设置 此属性基于用户交互,复选框将 反映ObservalEvalue的状态(如果外部发生更改)

示例程序

示例程序演示了可与CheckBoxListCell一起使用的一些模式:

import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;

import java.util.*;
import java.util.stream.Collectors;

public class CheckList extends Application {
    @Override
    public void start(Stage stage) throws Exception{
        ObservableList<Task> tasks = FXCollections.observableArrayList(
                Arrays.stream(taskNames).map(Task::new).collect(Collectors.toList())
        );

        ListView<String> reactionLog = new ListView<>();
        tasks.forEach(task -> task.selectedProperty().addListener((observable, wasSelected, isSelected) -> {
            if (isSelected) {
                reactionLog.getItems().add(reactionStrings.get(task.getName()));
                reactionLog.scrollTo(reactionLog.getItems().size() - 1);
            }
        }));

        ListView<Task> checklist = new ListView<>(tasks);
        checklist.setCellFactory(CheckBoxListCell.forListView(Task::selectedProperty, new StringConverter<Task>() {
            @Override
            public String toString(Task object) {
                return object.getName();
            }

            @Override
            public Task fromString(String string) {
                return null;
            }
        }));

        HBox layout = new HBox(10, checklist, reactionLog);
        layout.setPrefSize(350, 150);
        layout.setPadding(new Insets(10));
        Scene scene = new Scene(layout);
        stage.setScene(scene);
        stage.show();
    }

    public static class Task {
        private ReadOnlyStringWrapper name = new ReadOnlyStringWrapper();
        private BooleanProperty selected = new SimpleBooleanProperty(false);

        public Task(String name) {
            this.name.set(name);
        }

        public String getName() {
            return name.get();
        }
        public ReadOnlyStringProperty nameProperty() {
            return name.getReadOnlyProperty();
        }

        public BooleanProperty selectedProperty() {
            return selected;
        }
        public boolean isSelected() {
            return selected.get();
        }
        public void setSelected(boolean selected) {
            this.selected.set(selected);
        }
    }

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

    private static final String[] taskNames = {
            "Walk the dog",
            "Skin the cat",
            "Feed the pig"
    };

    private static final Map<String, String> reactionStrings = new HashMap<>();
    static {
        reactionStrings.put("Walk the dog", "The dog thanks you");
        reactionStrings.put("Skin the cat", "The cat hates you");
        reactionStrings.put("Feed the pig", "The pig wants more");
    }
}
导入javafx.application.application;
导入javafx.beans.property.*;
导入javafx.collections.*;
导入javafx.geometry.Insets;
导入javafx.scene.scene;
导入javafx.scene.control.ListView;
导入javafx.scene.control.cell.CheckBoxListCell;
导入javafx.scene.layout.HBox;
导入javafx.stage.stage;
导入javafx.util.StringConverter;
导入java.util.*;
导入java.util.stream.collector;
公共类清单扩展应用程序{
@凌驾
public void start(Stage)引发异常{
ObservableList tasks=FXCollections.observableArrayList(
Arrays.stream(taskNames).map(Task::new).collect(Collectors.toList())
);
ListView反应日志=新建ListView();
tasks.forEach(task->task.selectedProperty().addListener((可观察、已选择、已选择)->{
如果(当选){
添加(reactionString.get(task.getName());
scrollTo(reactionLog.getItems().size()-1);
}
}));
ListView检查表=新的ListView(任务);
checklist.setCellFactory(CheckBoxListCell.forListView(任务::selectedProperty,new StringConverter()){
@凌驾
公共字符串toString(任务对象){
返回object.getName();
}
@凌驾
公共任务fromString(String){
返回null;
}
}));
HBox布局=新HBox(10,检查表,反应日志);
布局。设置尺寸(350150);
布局。设置填充(新插图(10));
场景=新场景(布局);
舞台场景;
stage.show();
}
公共静态类任务{
private ReadOnlyStringWrapper name=new ReadOnlyStringWrapper();
选定的私有布尔属性=新的SimpleBoleanProperty(false);
公共任务(字符串名称){
this.name.set(name);
}
公共字符串getName(){
返回name.get();
}
public ReadOnlyStringProperty nameProperty(){
返回name.getReadOnlyProperty();
}
公共布尔属性selectedProperty(){
返回选中的;
}
公选{
返回选中的。get();
}
已选择公共无效设置(已选择布尔值){
本.已选.集(已选);
}
}
公共静态void main(字符串[]args){
发射(args);
}
私有静态最终字符串[]任务名={
“遛狗”,
“剥猫皮”,
“喂猪”
};
私有静态最终映射reactionStrings=newhashmap();
静止的{
反应字符串。放置(“遛狗”,“狗谢谢你”);
反应字符串。放置(“剥猫皮”,“猫恨你”);
反应字符串。放置(“喂猪”,“猪想要更多”);
}
}
第一项选择一次,第三项选择三次后的样本输出


如果项目尚未具有指示其是否已被选中的属性,则可以选择以下选项:

public class CheckedListViewCheckObserver<T> extends SimpleObjectProperty<Pair<T, Boolean>> {

    BooleanProperty getObserverForObject(T object) {
        BooleanProperty value = new SimpleBooleanProperty(false);
        value.addListener((observable, oldValue, newValue) -> {
            CheckedListViewCheckObserver.this.set(new Pair<>(object, newValue));
        });
        return value;
    }
}
这种方法的优点是它不依赖于所使用的对象;相反,由于它是通用的,您只需将它附加到现有的listview,它就可以开始工作了


希望这对某人有所帮助。

非常感谢@jewelsea
public class CheckedListViewCheckObserver<T> extends SimpleObjectProperty<Pair<T, Boolean>> {

    BooleanProperty getObserverForObject(T object) {
        BooleanProperty value = new SimpleBooleanProperty(false);
        value.addListener((observable, oldValue, newValue) -> {
            CheckedListViewCheckObserver.this.set(new Pair<>(object, newValue));
        });
        return value;
    }
}
CheckedListViewCheckObserver observer = new CheckedListViewCheckObserver<>();
checklist.setCellFactory(CheckBoxListCell.forListView(observer::getObserverForObject));
observer.addListener((obs, old, curr) -> {
    if (curr.getValue()) {
        System.out.println("You have checked " + curr.getKey());
    } else {
        System.out.println("You have unchecked " + curr.getKey());
    }
});