+ Répondre à la discussion
Affichage des résultats 1 à 4 sur 4
  1. #1
    Invité régulier
    Inscrit en
    mars 2003
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : mars 2003
    Messages : 9
    Points : 5
    Points
    5

    Par défaut Binding entre une TableView et deux TextField (JavaFX 2.0)

    Bonjour à vous

    Depuis plusieurs jours, je cherche une solution pour faire la liaison entre ma TableView et mes TextField (qui servent à éditer ma TableView)

    Le principe :
    Les données (Personne) sont lues en JPA depuis une DB (PersonneDAO). Ce sont des simples POJO. Ces données sont affichées dans une TableView.
    Je voudrais que lorsqu'on sélectionne une ligne dans la TableView, les TextField se remplissent avec les données de la TableView et lorsque l'on modifier le contenu des TextField, la ligne sélectionnée de la TableView soit modifiée directement.

    J'ai chercher des exemples via google afin de mieux comprendre le mécanisme du binding mais rien ne m'a permis de trouver une solution. J'ai tenté de me baser sur le site http://ugate.wordpress.com/2012/07/3...ings-part-iii/ mais rien à faire.

    Voici mes sources :

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.event.EventHandler;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.input.MouseButton;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.HBox;
    import javafx.stage.Stage;
    import jfxtras.labs.scene.control.BeanPathAdapter;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public class TestAppl extends Application {
     
      private TableView<Personne> tv;
      private TextField tfNom;
      private TextField tfPrenom;
      private ObservableList<Personne> personnes;
     
      private Personne p = new Personne();
      private BeanPathAdapter<Personne> personPA = new BeanPathAdapter<>(p);
     
      @Override
      public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Test de TableView");
     
        Scene scene = new Scene(new BorderPane(), 800, 500);
        primaryStage.setScene(scene);
     
        PersonneDAO personneDAO = new PersonneDAO();
     
        HBox pan = new HBox();
        pan.setPadding(new Insets(10, 10, 10, 10));
        pan.setSpacing(5);
        tfNom = new TextField();
        tfPrenom = new TextField();
     
        pan.getChildren().addAll(tfNom, tfPrenom);
        ((BorderPane) scene.getRoot()).setTop(pan);
     
        tv = new TableView<>();
     
        TableColumn<Personne, String> nomCol = new TableColumn("Nom");
        nomCol.setCellValueFactory(new PropertyValueFactory("nom"));
     
        TableColumn<Personne, String> prenomCol = new TableColumn("Prénom");
        prenomCol.setCellValueFactory(new PropertyValueFactory("prenom"));
     
        tv.getColumns().addAll(nomCol, prenomCol);
     
        personnes = FXCollections.observableArrayList(personneDAO.getPersonnes());
        tv.getItems().addAll(personnes);
     
        tv.setOnMouseClicked(new EventHandler<MouseEvent>() {
          @Override
          public void handle(MouseEvent mouseEvent) {
            if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
              if (mouseEvent.getClickCount() == 1) {
                personPA.setBean(tv.getSelectionModel().getSelectedItem());
                personPA.bindBidirectional("nom", tfNom.textProperty());
                personPA.bindBidirectional("prenom", tfPrenom.textProperty());
              }
            }
          }
        });
     
        ((BorderPane) scene.getRoot()).setCenter(tv);
     
        primaryStage.show();
      }
     
      public static void main(String[] args) {
        Application.launch(args);
      }
    Le bean Personne :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     public class Personne {
        private String nom;
        private String prenom;
     
        public Personne() {
        }
     
        public Personne(String nom, String prenom) {
          this.nom = nom;
          this.prenom = prenom;
        }
     
        public String getNom() {
          return nom;
        }
     
        public void setNom(String nom) {
          this.nom = nom;
        }
     
        public String getPrenom() {
          return prenom;
        }
     
        public void setPrenom(String prenom) {
          this.prenom = prenom;
        }
      }
    Et le futur DAO :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     public class PersonneDAO {
     
        public List<Personne> getPersonnes() {
          List<Personne> pers = new ArrayList<>();
          pers.add(new Personne("Nom1", "prenom1"));
          pers.add(new Personne("Nom2", "prenom2"));
          pers.add(new Personne("Nom3", "prenom3"));
          return pers;
        }
      }
    Je vous remercie de m'avoir lu et si quelqu'un à une idée ...
    Je vous souhaite une bonne journée.

    Neo

  2. #2
    Membre Expert
    Avatar de la.lune
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    décembre 2010
    Messages
    512
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Comores

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : décembre 2010
    Messages : 512
    Points : 1 947
    Points
    1 947

    Par défaut

    Bonjour!
    Ton problème d'abord c'est qu'en JavaFX on ne définit pas les beans comme tu l'a défini, il y a une manière très précise pour définir les beans, comme j'ai fais avec la classe Personne.

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    package testappl;
     
    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.property.StringProperty;
     
     
    public class Personne {
     
        private StringProperty nom;
        private StringProperty prenom;
     
     
     public Personne(String nom, String prenom){
     this.nom=new SimpleStringProperty(nom);
     this.prenom=new SimpleStringProperty(prenom);
     }
        public final String getNom() {
          return nom.get();
        }
     
        public final void setNom(String nom) {
          this.nom.set(nom);
        }
        public StringProperty nomProperty(){
            return nom;
     
        }
     
        public final String getPrenom() {
          return prenom.get();
        }
     
        public final void setPrenom(String prenom) {
          this.prenom.set(prenom);
        }
       public StringProperty prenomProperty(){
       return prenom;}
      }
    Il ne faut pas oublier pour les méthodes nonProperty() et prenomProperty() : non et prenom doivent être en minuscule comme ils sont déclarés, et tu garde la même forme comme sur les nom des colones sur le Tableview comme tu as déjà fait.

    Après j'ai enlevé la librairie jfxtras que tu as utilisé, on a pas besoin du BeanPathAdapter, l’implémentation de l'API javafx suffit.

    Donc l'astuce c'est qu'à chaque sélection d'une ligne on bind bidirectionnellement les textFields avec les propriétés du bean Personne contenu sur la ligne sélectionné, mais il ne faut pas oublier d'unbinder avant ce qui a été précédemment bindé. D'où la nécessite d'avoir un bean Personne en cours qui va pointer sur la personne sélectionné. Et quand tu ajoutes la liste Personne au tableview, lui il binde ces cellules aux propriétés du bean, à condition que ce dernier respecte les normes des beans en Javafx. J'ai illustré dans l'image suivant les binding, les flèches à sens uniques explicitent les bindings à sens unique et le double flèche c'est pour les bindings bidirectionels.

    Voici le code:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
     
    /*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package testappl;
     
     
    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.event.EventHandler;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.input.MouseButton;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.HBox;
    import javafx.stage.Stage;
     
     
     
    public class TestAppl extends Application {
     
      private TableView<Personne> tv;
      private TextField tfNom;
      private TextField tfPrenom;
      private ObservableList<Personne> personnes;
      //La personne sléctioné
      private Personne pEnCours;
     
      @Override
      public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Test de TableView");
     
        Scene scene = new Scene(new BorderPane(), 800, 500);
        primaryStage.setScene(scene);
     
        PersonneDAO personneDAO = new PersonneDAO();
     
        HBox pan = new HBox();
        pan.setPadding(new Insets(10, 10, 10, 10));
        pan.setSpacing(5);
        tfNom = new TextField();
        tfPrenom = new TextField();
     
        pan.getChildren().addAll(tfNom, tfPrenom);
        ((BorderPane) scene.getRoot()).setTop(pan);
     
        tv = new TableView<>();
     
        TableColumn nomCol = new TableColumn("Nom");
        nomCol.setCellValueFactory(new PropertyValueFactory("nom"));
     
        TableColumn prenomCol = new TableColumn("Prénom");
        prenomCol.setCellValueFactory(new PropertyValueFactory("prenom"));
     
        tv.getColumns().addAll(nomCol, prenomCol);
     
        personnes = FXCollections.observableArrayList(personneDAO.getPersonnes());
        tv.getItems().addAll(personnes);
        tv.setOnMouseClicked(new EventHandler<MouseEvent>() {
          @Override
            public void handle(MouseEvent mouseEvent) {
              if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
                if (mouseEvent.getClickCount() == 1) {
     
                   if(pEnCours!=null){  
                    tfNom.textProperty().unbindBidirectional(pEnCours.nomProperty());
                    tfPrenom.textProperty().unbindBidirectional(pEnCours.prenomProperty());
                    }
                    pEnCours=tv.getSelectionModel().getSelectedItem();
                    //Attribuer de nouveaux liens 
                    tfNom.textProperty().bindBidirectional(pEnCours.nomProperty());
                    tfPrenom.textProperty().bindBidirectional(pEnCours.prenomProperty());
     
              }
            }
          }
        });
     
        ((BorderPane) scene.getRoot()).setCenter(tv);
     
        primaryStage.show();
      }
     
      public static void main(String[] args) {
        Application.launch(args);
      }
    }
    Pour la classe PersonneDAO je ne l'ai pas touché, car tu aura juste a remplir ta liste avec les données de la base de données.
    Il y a une possibilité d'écouter les changement à chaque personne dont les propriétés sont modifiés ou au moins savoir que les valeurs ne sont pas les mêmes avec les ChangeListener ou les InvalidationListerner qu'on peut ajouter au prorprietés de bean personne.

    En tout cas personnellement je n'ai pas cherché à comprendre le contenu de l'article que tu as publié, il reste qu'il y a encore d'autres choses concernant les POJOs je n'ai rien touché, alors bonne continuation.

  3. #3
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Développeur Java
    Inscrit en
    août 2005
    Messages
    4 572
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : août 2005
    Messages : 4 572
    Points : 13 255
    Points
    13 255
    Billets dans le blog
    1

    Par défaut

    Hum, il y a une ou plusieurs classes adaptateur quelques part dans l'API qui permettent de connecter une propriété d'un java bean comme une propriété JavaFX il me semble (j'oublie a chaque fois son nom).

    Grosso-modo ce qu'elles font c'est placer les PropertyChangeListener (les event Java bean) qui vont bien sur les propriétés du bean et forwarder les ChangeListener (les events FX) au moment approprie et packager le tout sous une ObservableValue. Rien qui ne puisse être fait a mano assez rapidement.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  4. #4
    Invité régulier
    Inscrit en
    mars 2003
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : mars 2003
    Messages : 9
    Points : 5
    Points
    5

    Par défaut

    Merci à vous pour vos réponses.

    J'ai été un peu long à répondre car j'ai du avancer sur mon projet et j'avais réussi à trouver une solution un peu 'pourrie' car j'avais des délais à respecter.

    Merci la.lune pour toute ton explication. Je vais l'étudier ce weekend afin de mieux comprendre les properties et le binding. J'ai l'impression qu'il me faudra faire pour chaque bean JPA un convertisseur vers des beans FX (avec des properties). Ce qui ne m'enchante pas vraiment car j'ai près de 500 beans JPA qui ne sont pas toujours des plus simples.

    bouye, les adaptateurs dont tu parles, ce ne serait pas justement les BeanPathAdapter ? C'est ce que j'avais tenté de mettre en place mais je n'y étais pas arrivé.

    La solution que j'avais trouvé était de me passer du binding et de placer un bouton de validation pour l'édition. Lorsque l'on valide les champs édités, je fais :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    Personne selectedPersonne = (Personne)tableView.getSelectionModel().getSelectedItem();
    int index = tableView.getItems().indexOf(selectedPersonne );
    if (index != -1) {
              tableView.getItems().remove(index);
              tableView.layout();
              tableView.getItems().add(index, selectedPersonne );
              tableView.getSelectionModel().select(index);
    }
    Cette solution ne me plaisait pas du tout mais elle m'a dépanné.

    Dès que j'aurai un peu de temps, je reviendrai sur ce bout de code afin de tenter de mettre en place une de vos propositions car, venant du Swing, j'ai des lacunes avec ces concepts.

    En tout cas, je vous remercie tous les deux.
    Neo

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •