How to add a listener to a checkbox inside a list using CheckBoxListCell

I have a listview that uses a CheckBoxListCell to display a list with checkboxes next to items. How to add a listener to this checkbox to find out when an item was selected or not selected? enter image description here

+5
source share
2 answers

Decision

You do not add a listener to this flag. You add a listener to the observed property of the object associated with the checkbox with CheckBoxListCell.forListView .

Communication setup:

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

Adding a listener for all elements:

 tasks.forEach(task -> task.selectedProperty().addListener((observable, wasSelected, isSelected) -> { if (isSelected) { // . . . } else { // . . . } })); 

Documentation

The process is described in CheckBoxListCell.forListView javadoc, for example:

getSelectedProperty - A callback that, given an object of type T (which is a value taken from the ListView.items), will return an ObservableValue that represents whether this item is selected or not. This ObservableValue will be bound bidirectionally (this means that the CheckBox in the cell will set / disable this property based on user interactions, and the CheckBox will reflect the ObservableValue state if it changes externally).

Program example

An example program that demonstrated some patterns that could be used with 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"); } } 

Example output after selecting the first item once and the third item three times.

piggy

+11
source

Here is an alternative if the element does not yet have a property that indicates whether it was selected or not:

 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; } } 

Then, to use it, simply do:

 CheckedListViewCheckObserver observer = new CheckedListViewCheckObserver<>(); checklist.setCellFactory(CheckBoxListCell.forListView(observer::getObserverForObject)); 

Now you can configure the listener to listen to any changes:

 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()); } }); 

The advantage of this method is that it does not depend on the objects used; Instead, since it is generic, you can simply attach it to an existing list and start working with the bat.

Hope this helps someone.

0
source

Source: https://habr.com/ru/post/1200515/


All Articles