JavaFX 8, ListView avec cases à cocher

Je veux créer un simple ListView. J’ai compris que je pouvais utiliser la méthode setCellFactory () mais je ne comprenais pas comment les utiliser correctement. Jusqu’à présent j’ai:

myListView.setCellFactory(CheckBoxListCell.forListView(property)); 

Avec “propriété” étant ce qu’on appelle un rappel – je pense que le rappel a quelque chose à voir avec la limite bidirectionnelle. Alors j’ai créé un

 property = new CallBack<String, ObservableValue>(); 

Mon compilateur me dit que si je crée un nouveau rappel, je dois écraser l’appel de méthode.

Et me voilà coincé. Que fais-je avec cet appel de méthode? Je peux l’implémenter, mais que dois-je retourner ou utiliser? Je veux cliquer sur ma case à cocher sur un listItem et l’afficher “bonjour” dans la console.

Si vous avez un ListView , chaque élément du ListView est un Ssortingng et la méthode CheckBoxListCell.forListView(...) attend un Callback> .

Dans le mode de pensée antérieur à Java 8, un Callback> est une interface qui définit une seule méthode,

 public ObservableValue call(Ssortingng s) ; 

Vous avez donc besoin de quelque chose qui implémente cette interface et vous transmettez un object de ce type.

La documentation vous indique également comment ce rappel est utilisé:

Un rappel qui, étant donné un object de type T (qui est une valeur extraite de la liste ListView.items), retournera une valeur ObservableValue indiquant si l’élément donné est sélectionné ou non. Cette ObservableValue sera liée de manière bidirectionnelle (ce qui signifie que la case à cocher de la cellule va définir / annuler la définition de cette propriété en fonction des interactions de l’utilisateur, et que la case à cocher reflétera l’état de la valeur ObservableValue, si elle change en externe).

(Puisque vous avez une ListView , T est une Ssortingng .) Ainsi, pour chaque élément de la vue liste (chaque élément est une Ssortingng ), le rappel est utilisé pour déterminer une ObservableValue qui est liée de manière bidirectionnelle à la état de la case à cocher. En d’autres termes, si la case à cocher est cochée, cette propriété est définie sur true et, si elle n’est pas cochée, elle est définie sur false . Inversement, si la propriété est définie sur true (ou false ) par programme, la case à cocher est cochée (ou décochée).

Le cas d’utilisation typique ici est que le type d’élément dans ListView aurait un BooleanProperty dans le cadre de son état. Donc, vous utiliseriez généralement ceci avec une sorte de classe personnalisée représentant vos données, comme suit avec la classe interne Item :

 import javafx.application.Application; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleSsortingngProperty; import javafx.beans.property.SsortingngProperty; import javafx.beans.value.ObservableValue; import javafx.scene.Scene; 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 ListViewWithCheckBox extends Application { @Override public void start(Stage primaryStage) { ListView listView = new ListView<>(); for (int i=1; i<=20; i++) { Item item = new Item("Item "+i, false); // observe item's on property and display message if it changes: item.onProperty().addListener((obs, wasOn, isNowOn) -> { System.out.println(item.getName() + " changed on state from "+wasOn+" to "+isNowOn); }); listView.getItems().add(item); } listView.setCellFactory(CheckBoxListCell.forListView(new Callback>() { @Override public ObservableValue call(Item item) { return item.onProperty(); } })); BorderPane root = new BorderPane(listView); Scene scene = new Scene(root, 250, 400); primaryStage.setScene(scene); primaryStage.show(); } public static class Item { private final SsortingngProperty name = new SimpleSsortingngProperty(); private final BooleanProperty on = new SimpleBooleanProperty(); public Item(Ssortingng name, boolean on) { setName(name); setOn(on); } public final SsortingngProperty nameProperty() { return this.name; } public final Ssortingng getName() { return this.nameProperty().get(); } public final void setName(final Ssortingng name) { this.nameProperty().set(name); } public final BooleanProperty onProperty() { return this.on; } public final boolean isOn() { return this.onProperty().get(); } public final void setOn(final boolean on) { this.onProperty().set(on); } @Override public Ssortingng toSsortingng() { return getName(); } } public static void main(Ssortingng[] args) { launch(args); } } 

Si vous avez réellement un ListView , le fait que vous définissiez la propriété en cliquant sur la case à cocher n’est pas vraiment clair. Mais rien ne vous empêche de créer un appel dans le rappel uniquement dans le but de vous lier à l’état sélectionné de la case à cocher:

 import javafx.application.Application; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ObservableValue; import javafx.scene.Scene; 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 ListViewWithSsortingngAndCheckBox extends Application { @Override public void start(Stage primaryStage) { ListView listView = new ListView<>(); for (int i = 1; i <= 20 ; i++) { String item = "Item "+i ; listView.getItems().add(item); } listView.setCellFactory(CheckBoxListCell.forListView(new Callback>() { @Override public ObservableValue call(Ssortingng item) { BooleanProperty observable = new SimpleBooleanProperty(); observable.addListener((obs, wasSelected, isNowSelected) -> System.out.println("Check box for "+item+" changed from "+wasSelected+" to "+isNowSelected) ); return observable ; } })); BorderPane root = new BorderPane(listView); Scene scene = new Scene(root, 250, 400); primaryStage.setScene(scene); primaryStage.show(); } public static void main(Ssortingng[] args) { launch(args); } } 

Notez que dans ce cas, les BooleanProperty sont potentiellement créées et ignorées fréquemment. Ce n’est probablement pas un problème dans la pratique, mais cela signifie que la première version, avec la classe de modèle dédiée, peut mieux fonctionner.

En Java 8, vous pouvez simplifier le code. Callback donné que l’interface Callback n’a qu’une seule méthode abstraite (en faisant une interface fonctionnelle ), vous pouvez penser à un Callback> tant que fonction prenant un Item et générant une ObservableValue . Ainsi, l’usine de cellules du premier exemple pourrait être écrite avec une expression lambda :

  listView.setCellFactory(CheckBoxListCell.forListView(item -> item.onProperty())); 

ou, encore plus succinctement, en utilisant des références de méthodes :

  listView.setCellFactory(CheckBoxListCell.forListView(Item::onProperty)); 
  listView.setCellFactory(CheckBoxListCell.forListView(new Callback>() { @Override public ObservableValue call(Ssortingng item) { BooleanProperty observable = new SimpleBooleanProperty(); observable.addListener((obs, wasSelected, isNowSelected) -> System.out.println("Check box for "+item+" changed from "+wasSelected+" to "+isNowSelected) ); return observable ; } })); 

Je vous remercie! Cela m’aide à résoudre mon problème.

Merci pour les réponses précédentes. Je manque l’information selon laquelle setCellValueFactory n’est pas nécessaire, mais la valeur atsortingbuée doit également être définie dans setCellFactory. Voici mon approche (beaucoup copiée de la solution précédente).

 public TreeTableColumn treetblcolHide; ... treetblcolHide.setCellFactory(CheckBoxTreeTableCell.forTreeTableColumn(new Callback>() { @Override public ObservableValue call(final Integer param) { final RowContainer rowitem = treetblcolHide.getTreeTableView().getTreeItem(param).getValue(); BooleanProperty observable = new SimpleBooleanProperty(); observable.addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { rowitem.setHideMenuItem(newValue.toSsortingng()); } } ); observable.setValue(Boolean.parseBoolean(rowitem.getHideMenuItem())); return observable ; } }));