Je souhaite stocker des objets dans un ChoiceBox pour mettre en miroir une table de recherche avec des champs (id, name) afin de pouvoir récupérer facilement l'ID lors de la sauvegarde ultérieure de l'enregistrement choix affiche le texte. Par exemple, si j'ai un ChoiceBox avec des objets Catégorie, lorsque l'utilisateur sélectionne une catégorie dans la liste déroulante, le texte affichera le nom de cette catégorie - l'affichage et la sélection correspondront. Éventuellement, lorsque le modèle enregistre les données, il extrait le champ id de l'objet Category en tant que paramètre dans la requête SQL.Définition de la valeur affichée de ChoiceBox lors de l'appel de setValue()
Mon code au bas de cet article montre mes tentatives pour comprendre ce qui se passe. Le défi est que la partie texte du Choix n'est pas nécessairement mise à jour lorsque la valeur change, soit avec un appel explicite setValue(), soit avec un appel indirect lorsque je lie le Choix à une ObjectProperty.
Je crois comprendre pourquoi. Si j'appelle setValue() avec un objet Category identique à un dans ObservableList du choix (le même objet, pas une autre instance avec les mêmes valeurs de champ), la portion de texte affiche la valeur correcte. Cependant, si j'appelle setValue() avec une autre instance, cela ne fonctionne pas, même si les valeurs des champs sont les mêmes. J'ai fait un Override sur l'égalité() de la classe que j'utilise, mais cela n'a pas aidé. Existe-t-il une autre méthode que ChoiceBox utilise pour comparer des objets?
Avez-vous des suggestions pour contourner ce problème? Je veux éviter de coder d'autres écouteurs, ou rechercher des fonctions chaque fois que j'implémente ce cas d'utilisation. Peut-être un moyen simple serait d'utiliser l'id de la base de données pour obtenir l'un des objets dans la liste de sélection utilisée pour construire le combo et définir cela comme la valeur de la propriété de mon modèle. Par exemple, si l'ID est 1, le champ category de mon modèle sera défini sur = picklist [1] (un objet Category). Puisque le champ ObservableList du choix serait initialisé avec la même liste de sélection, les objets seraient identiques et le problème serait résolu. (Comme dans le troisième scénario dans mon code.)
/*
* If I set the value of a ChoiceBox to exact copy of an object
* in the ObservableList, the text portion is updated accordingly
*
* If is set the value with another instance of the same class
* with the same values, but not the same exact object,
* the text portion is not updated.
*
*/
package javafxapplication1;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class JavaFXApplication1 extends Application {
class TestClass {
// public to simplify demo - normally private
public int id;
public String name;
public TestClass(int id, String name) {
this.id = id;
this.name = name;
}
public boolean equals(TestClass other) {
// not called ...
System.out.println("TestClass.equals() was called");
return this.id == other.id && this.name.equals(other.name);
}
@Override
public String toString() {
return "[id = " + id + " name = " + name + "]";
}
}
@Override
public void start(Stage primaryStage) {
ChoiceBox<String> cbS = new ChoiceBox<>();
ObservableList<String> valuesS = FXCollections.observableArrayList();
valuesS.addAll("A", "B", "C");
cbS.setItems(valuesS);
// a text converter would make the choice display only text
// no the toString() of the class
/*
* SET INITIAL VALUE BEFORE SHOWING VIEW
* no issues with String choice
*/
cbS.setValue("A");
System.out.println("Initial String value: " + cbS.getSelectionModel().getSelectedItem());
Button btn = new Button();
btn.setText("Change String Value");
btn.setOnAction((ActionEvent event) -> {
cbS.setValue("C");
System.out.println("setValue(\"C\") was called");
System.out.println("New String value is " + cbS.getSelectionModel().getSelectedItem());
});
ChoiceBox<TestClass> cbO = new ChoiceBox<>();
ObservableList<TestClass> valuesO = FXCollections.observableArrayList();
TestClass specificInstance = new TestClass(3, "Exact instance");
valuesO.addAll(new TestClass(1, "Aba"), new TestClass(2, "Ubu"), specificInstance);
cbO.setItems(valuesO);
cbO.setValue(new TestClass(1, "Aba"));
System.out.println("Initial Object value: " + cbO.getSelectionModel().getSelectedItem());
Button btnO = new Button();
btnO.setText("Change Object Value");
/*
* SET VALUE TO OTHER INSTANCE WITH SAME FIELD VALUES
*/
btnO.setOnAction((ActionEvent event) -> {
cbO.setValue(new TestClass(2, "Ubu"));
System.out.println("setValue(same-values-object)");
System.out.println("New Object value is " + cbO.getSelectionModel().getSelectedItem());
});
/*
* SET VALUE TO ONE OF THE OBJECTS IN THE CHOICE
*/
Button btnO2 = new Button();
btnO2.setText("Change Object Value");
btnO2.setOnAction((ActionEvent event) -> {
cbO.setValue(specificInstance);
System.out.println("setValue(exact-instance-of-object) was called");
System.out.println("New Object value is " + cbO.getSelectionModel().getSelectedItem());
});
VBox root = new VBox();
root.getChildren().addAll(cbS, btn, cbO, btnO, btnO2);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Test setValue()");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Utilisez toujours le '@ annotation Override' lorsque vous substituez les méthodes ... –