IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaFX Discussion :

Ajout d'un bouton dans une colonne d'une TableView


Sujet :

JavaFX

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mai 2010
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Mai 2010
    Messages : 36
    Par défaut Ajout d'un bouton dans une colonne d'une TableView
    Bonjour,

    Je recherche une explication sur le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
     @FXML
        private TableColumn<Type, Boolean> Supp;
     
       @FXML
        public void initialize() {
            tableView2.setEditable(true);
            ..
            Supp.setSortable(false);
            Supp.setCellValueFactory(
                    new Callback<TableColumn.CellDataFeatures<Type, Boolean>, ObservableValue<Boolean>>() {
     
                        @Override
                        public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Type, Boolean> p) {
                            return new SimpleBooleanProperty(p.getValue() != null);
                        }
                    });
            Supp.setCellFactory(
                    new Callback<TableColumn<Type, Boolean>, TableCell<Type, Boolean>>() {
     
                        @Override
                        public TableCell<Type, Boolean> call(TableColumn<Type, Boolean> p) {
                            return new ButtonCell();
                        }
     
                    });
     
        }
     
        //Define the button cell
        private class ButtonCell extends TableCell<Type, Boolean> {
     
            final Button cellButton = new Button("Action");
     
            ButtonCell() {
     
                cellButton.setOnAction(new EventHandler<ActionEvent>() {
     
                    @Override
                    public void handle(ActionEvent t) {
                        // do something when button clicked
                        //...
                    }
                });
            }
     
            //Display button if the row is not empty
            @Override
            protected void updateItem(Boolean t, boolean empty) {
                super.updateItem(t, empty);
                if(!empty){
                    setGraphic(cellButton);
                }
            }
        }
    c'est pour l'attribut supp qui doit être un bouton.
    Il est ajouté dans une table view mais j'aimerais avoir une explication sur les instructions setCellValueFactory et setCellFactory.

    A quoi servent -elles?

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    C'est vrai que le nom n'est pas très parlant car se ressemblant fortement, je vais donc citer une partie de l'article sur l'API Cell que j'ai en cours de rédaction :

    Citation Envoyé par moi
    • cellFactory - de type Callback<TableColumn<V, T>, TableCell<V, T>> : une fabrique à cellules qui est utilisée pour afficher chaque valeur T de la colonne associé à chaque valeur V de la table.
    • cellValueFactory - très importante et à ne pas confondre avec la précédente : une fabrique qui, pour chaque valeur V de la table retourne une ObservableValue<T> pour cette colonne. Cette fabrique sert donc à peupler les valeurs de la colonne à partir de celles de la table.


    [...]

    La propriété cellValueFactory est donc quelque chose de très important pour la colonne : c'est via cette fabrique que l'on peut extraire les objets de types T qui peuplent dans la colonne à partir des objets de type V qui sont présents dans la table.
    Reprenons, ta table est en faite une liste de valeurs de type V ; oui en JavaFX, le modèle d'une table c'est une liste, d’où le TableView<V> et le TreeTableView<V>.
    Mais tu dispose de colonnes qui affichent des valeurs de type T, d’où les classes TableColumn<V, T> et TreeTableColumn<V, T>.

    Par exemple dans une TableView<Voiture> contient une liste d'instances de Voitures.

    Mais je vais avoir des colonnes avec des types plus variés :
    1. colonne 1 - TableColumn<Voiture, String> - pour le nom, cette colonne contient des instances de String.
    2. colonne 2 - TableColumn<Voiture, Marque> - pour la marque, cette colonne contient des instances de Marque.
    3. colonne 3 - TableColumn<Voiture, Color> - pour la couleur, cette colonne contient des instances de Color.
    4. colonne 4 - TableColumn<Voiture, Integer> - pour le nombre de porte, cette colonne contient des instances de Integer.
    5. etc.


    Sur chaque colonne, je vais donc avoir une fabrique cellValueFactory qui permet :
    1. colonne 1 - À partir d'une instance de Voiture de trouver son nom sous forme de String.
    2. colonne 2 - À partir d'une instance de Voiture de trouver sa Marque.
    3. colonne 3 - À partir d'une instance de Voiture de trouver sa couleur sous forme de Color.
    4. colonne 4 - À partir d'une instance de Voiture de trouver son nombre de porte sous forme d'Integer.
    5. etc.


    La c'est ok on a les bonnes valeur mais, bon, tout est affiché en mode texte.
    Donc désormais il nous faut créer les bonnes cellules pour afficher chaque classe :
    C'est là ou la fabrique cellFactory entre en course:
    1. colonne 1 - on prend une String et on affiche le nom de la voiture avec une photo de la voiture.
    2. colonne 2 - on prend une Marque et on affiche le logo + lien hypertexte vers le site du constructeur.
    3. colonne 3 - on prend une Color et on affiche un carre de couleur au lieu de la valeur textuelle.
    4. colonne 4 - on prend un Integer, on crée une String a partir de ce dernier mais on va aligner le texte sur la droite au lieu de la gauche et on avoir une irone montrant si la voiture est 3 ou 5 portes.
    5. etc.




    Donc dans ton code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TableColumn<Type, Boolean> Supp;
    Tu as des objets de type Type dans ta table, mais ta colonne affiche un booléen.

    -> il te faut un cellValueFactory qui a partir d'une instance de Type renvoie une ObservableValue<Boolean>.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Supp.setCellValueFactory(
                    new Callback<TableColumn.CellDataFeatures<Type, Boolean>, ObservableValue<Boolean>>() {
     
                        @Override
                        public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Type, Boolean> p) {
                            return new SimpleBooleanProperty(p.getValue() != null);
                        }
                    });
    C'est très bien si Type ne contient pas une propriétés JavaFX.
    Si au contraire value est une propriété JavaFX, on peut faire a la place :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Supp.setCellValueFactory(new PropertyValueFactory<>("value"));
    ce qui est beaucoup plus simple avouons le.

    Désormais tu veux afficher correctement ton booléen (par défaut, il y a juste le texte true ou false qui s'affiche), voir même rendre la cellule interactive.

    -> tu as donc une cellFactory qui a partir d'une valeur booléenne affiche... un bouton :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Supp.setCellFactory(
                    new Callback<TableColumn<Type, Boolean>, TableCell<Type, Boolean>>() {
     
                        @Override
                        public TableCell<Type, Boolean> call(TableColumn<Type, Boolean> p) {
                            return new ButtonCell();
                        }
     
                    });
    Par contre ici rien ne devrait s'afficher sur le bouton, il est vierge de texte et la valeur du booléen n'a aucune influence dessus vu qu'il manque la surchage de updateItem() dans le ButtonCell pour configurer ce bouton.

    Pourquoi pas... moi j'aurai plutôt utilise ça histoire d'avoir des cases a cocher :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Supp.setCellFactory(CheckBoxTableCell.forTableColumn(Supp));
    Pour le moment, la cellule est non-interactive, a voir après si tu veux rendre la colonne éditable (il y aura un peu plus de code a mettre si la propriété value de la classe Type n'est pas une propriété JavaFX).
    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

  3. #3
    Membre averti
    Inscrit en
    Mai 2010
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Mai 2010
    Messages : 36
    Par défaut
    C'est limpide Bouye merci.

    Le but ici est d'avoir un bouton Suppression sur chaque enregistrement de ma tableview (instance de la classe Type si je comprend bien) afin de permettre de supprimer l'enreg.

    J'ai bien ajouté la méthode updateItem et mon bouton s'affiche.

    Lorsque j'appuie sur le bouton, j'appel la méthode handle en me transmettant le paramètre ActionEvent.

    J'ai maintenant un problème pour récupérer mon instance de Type.

    La ligne de ma tableview est bien une instance de mon bean Type mais la colonne du bouton sup n'est pas mappé. Comment récupérer les valeurs de mon instance de mon Bean?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
        /**
         * Initializes the controller class.
         */
        @FXML
        public void initialize() {
            tableView2.setEditable(true);
            Index.setCellValueFactory(new PropertyValueFactory<Type, Integer>("Index"));
            Type.setCellValueFactory(new PropertyValueFactory<Type, String>("Type"));
            Type.setCellFactory(TextFieldTableCell.<Type>forTableColumn());
            Categorie.setCellValueFactory(new PropertyValueFactory<Type, String>("Categorie"));
            Categorie.setCellFactory(TextFieldTableCell.<Type>forTableColumn());
            Nom.setCellValueFactory(new PropertyValueFactory<Type, String>("Nom"));
            Nom.setCellFactory(TextFieldTableCell.<Type>forTableColumn());
            Supp.setSortable(false);
            Supp.setCellValueFactory(
                    new Callback<TableColumn.CellDataFeatures<Type, Boolean>, ObservableValue<Boolean>>() {
     
                        @Override
                        public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Type, Boolean> p) {
                            return new SimpleBooleanProperty(p.getValue() != null);
                        }
                    });
            Supp.setCellFactory(
                    new Callback<TableColumn<Type, Boolean>, TableCell<Type, Boolean>>() {
     
                        @Override
                        public TableCell<Type, Boolean> call(TableColumn<Type, Boolean> p) {
                            return new ButtonCell();
                        }
     
                    });
     
        }
     
        //Define the button cell
        private class ButtonCell extends TableCell<Type, Boolean> {
     
            final Button cellButton = new Button("Action");
     
            ButtonCell() {
     
                cellButton.setOnAction(new EventHandler<ActionEvent>() {
     
     
                    @Override
                    public void handle(ActionEvent t) {
                        // do something when button clicked
                        System.out.println("action");
     
                    }
                });
            }
     
            //Display button if the row is not empty
            @Override
            protected void updateItem(Boolean t, boolean empty) {
                super.updateItem(t, empty);
                if (!empty) {
                    setGraphic(cellButton);
                }
            }
        }

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Alors, il y a deux question distinctes :
    1. Récupérer une propriété non-JavaFX et non Java Bean (elle n'est pas observable via un PropertyChangeListener c'est donc un simple couple getter/setter au lieu d'une vraie propriété Java Bean).
    2. Avoir un bouton pour supprimer une ligne donnée.


    1. La propriété n'est pas observable donc pas de miracle. Je vais re-citer un passage de l'article en question (ça m’évitera de retaper grosso-modo la même chose).
      Ici :
      • "Propriétés JavaBeans observables" = getter + setter + possibilité d'enregistrer un PropertyChangeListener sur la propriété en question.
      • "Autre" = getter + setter simple, méthode custom ou accès direct.


      Citation Envoyé par moi

      La propriété cellValueFactory est donc quelque chose de très important pour la colonne : c'est via cette fabrique que l'on peut extraire les objets de types T qui peuplent dans la colonne à partir des objets de type V qui sont présents dans la table.

      Prenons par exemple la classe Truc suivante :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      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
      public class Truc { 
          //////////////////////////////////////////////////////////////////////////// 
          // Propriétés JavaFX. 
          private final BooleanProperty visible = new SimpleBooleanProperty(); 
       
          public final boolean isVisible() { 
              return visible.get(); 
          } 
       
          public final void setVisible(boolean value) { 
              visible.set(value); 
          } 
       
          public final BooleanProperty visibleProperty() { 
              return visible; 
          } 
       
           private final StringProperty name = new SimpleStringProperty(); 
       
           public final String getName() { 
               return name.get(); 
           } 
       
           public final void setName(String value) { 
               name.set(value); 
           } 
       
           public final StringProperty nameProperty() { 
               return name; 
           } 
       
           //////////////////////////////////////////////////////////////////////////// 
           // Propriétés JavaBeans observables. 
           private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); 
       
           public final void addPropertyChangeListener(String property, PropertyChangeListener listener) { 
               propertyChangeSupport.addPropertyChangeListener(property, listener); 
           } 
       
           public final void removePropertyChangeListener(String property, PropertyChangeListener listener) { 
               propertyChangeSupport.removePropertyChangeListener(property, listener); 
           } 
       
           private final void firePropertyChange(String property, Object oldValue, Object newValue) { 
               propertyChangeSupport.firePropertyChange(property, oldValue, newValue); 
           } 
       
           private boolean opaque = false; 
       
           public boolean isOpaque() { 
               return opaque; 
           } 
       
           public void setOpaque(boolean value) { 
               final boolean oldValue = opaque; 
               opaque = value; 
               firePropertyChange("opaque", oldValue, opaque); 
           } 
       
           private String comment; 
       
           public String getComment() { 
               return comment; 
           } 
       
           public void setComment(String value) { 
               final String oldValue = comment; 
               comment = value; 
               firePropertyChange("comment", oldValue, comment); 
           } 
       
           //////////////////////////////////////////////////////////////////////////// 
           // Autres 
       
           public boolean administrator; 
           public String email; 
      }
      Cette classe dispose de 3 ensembles bien distincts de propriétés :
      • Des propriétés JavaFX :
        • visible - un booléen.
        • name - une chaine de texte.
      • Des propriétés JavaBeans observables - c'est-à-dire que ces propriétés Java standard qui lèvent des évènements de type PropertyChangeEvent lorsqu'elles sont modifiées. Il est de plus possible d'enregistrer des écouteurs de type PropertyChangeListener sur notre objet de type Truc pour recevoir ces évènements.
        • opaque - un booléen.
        • comment - une chaine de texte.
      • Des membres en accès direct - on aurait aussi pu mettre des getters couplés à des setters simples qui ne lèvent pas de PropertyChangeEvent en cas de modification.
        • administrator - un booléen.
        • email - une chaine de texte.


      Nous allons maintenant essayer d'afficher ces différentes propriétés dans une TableView<Truc>. Compte tenu de la nature de nos différentes propriétés, nous aurons des colonnes de type TableColumn<Truc, Boolean> et TableColumn<Truc, String>.

      [...]

      Il nous faut aussi bien sur rajouter les colonnes appropriées :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      // Construction de la table. 
      final TableColumn<Truc, Boolean> visibleColumn = new TableColumn<>("Visible"); 
      final TableColumn<Truc, String> nameColumn = new TableColumn<>("Nom"); 
      final TableColumn<Truc, Boolean> opaqueColumn = new TableColumn<>("Opaque"); 
      final TableColumn<Truc, String> commentColumn = new TableColumn<>("Commentaires"); 
      final TableColumn<Truc, Boolean> administratorColumn = new TableColumn<>("Administrateur"); 
      final TableColumn<Truc, String> emailColumn = new TableColumn<>("Mél"); 
      tableView.getColumns().setAll(visibleColumn, nameColumn, opaqueColumn, commentColumn, administratorColumn, emailColumn);


      [...]

      Propriétés JavaFX
      Quand on utilise des propriétés JavaFX, c'est bien simple : il n'y a pas grand-chose à faire ! Nous pouvons utiliser la classe javafx.scene.control.cell.PropertyValueFactory<V, T> pour créer une fabrique de propriété utilisant la réflexion. Et tout fonctionne directement !

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      // Propriété visible. 
      visibleColumn.setCellValueFactory(new PropertyValueFactory<>("visible")); 
      // Propriété name. 
      nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));


      Si les propriétés visible et name sont modifiées ailleurs que dans la table, alors cette dernière se met à jour automatiquement avec les nouvelles valeurs.

      Propriétés JavaBeans observables
      Au premier abord on peut penser qu'il suffit d'utiliser la classe PropertyValueFactory sur les propriétés opaque et comment et si on essaie on verra que les valeurs correctes s'affichent. Mais en fait cela est trompeur : les valeurs initiales sont bien affichées ; cependant, en cas de modification hors de la table, cette dernière ne se met pas à jour ! Cela peut être gênant…

      Nous allons devoir spécifier nos propres fabriques de valeurs pour ces deux propriétés et nous allons utiliser les builders présents dans l'API JavaFX qui permettent de créer un adaptateur entre les propriétés JavaBeans observables et les propriétés JavaFX :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      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
      // Propriété opaque. 
      opaqueColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Truc, Boolean>, ObservableValue<Boolean>>() { 
          @Override 
          public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Truc, Boolean> p) { 
              final Truc t = p.getValue(); 
              try { 
                  return JavaBeanBooleanPropertyBuilder.create().bean(t).name("opaque").build(); 
              } catch (NoSuchMethodException ex) { 
                  Logger.getLogger(MainFX4.class.getName()).log(Level.SEVERE, null, ex); 
                  return null; 
              } 
           } 
      }); 
      // Propriété comment. 
      commentColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Truc, String>, ObservableValue<String>>() { 
          @Override 
          public ObservableValue<String> call(TableColumn.CellDataFeatures<Truc, String> p) { 
              final Truc t = p.getValue(); 
              try { 
                  return JavaBeanStringPropertyBuilder.create().bean(t).name("comment").build(); 
              } catch (NoSuchMethodException ex) { 
                  Logger.getLogger(MainFX4.class.getName()).log(Level.SEVERE, null, ex); 
                  return null; 
              } 
          } 
      });
      En utilisant cet adaptateur, la table est prévenue de toutes modifications extérieures des propriétés opaque et comment et le contenu des cellules de la ligne change en conséquence.



      Autres
      Nous allons créer des propriétés pour mettre en place une Fr Façade destinée à convertir la valeur en provenance de l’objet vers une propriété JavaFX mais, ici il n’y a pas de secrets : ces membres ou propriétés ne sont pas observables ; il est totalement impossible d’être tenu au courant d’une modification externe. De la meme manière, si la table est éditable, une modification apportée sur la colonne n’est pas reportée sur l’objet.

      Si on a à faire à des getters, on peut tenter l’utilisation de la classe PropertyValueFactory. Sinon, il va falloir procéder a mano :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      // Propriété administrator.         
      administratorColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Truc, Boolean>, ObservableValue<Boolean>>() { 
          @Override 
          public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Truc, Boolean> p) { 
              final Truc t = p.getValue(); 
              return new SimpleBooleanProperty(t.administrator); 
          } 
      }); 
      // Propriété email.         
      emailColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Truc, String>, ObservableValue<String>>() { 
          @Override 
          public ObservableValue<String> call(TableColumn.CellDataFeatures<Truc, String> p) { 
              final Truc t = p.getValue(); 
              return new SimpleStringProperty(t.email); 
          } 
      });
      Nous avons enfin l'affichage complet de nos colonnes :



      [...]

      Booléens

      L'API JavaFX propose la classe prête à l'emploi javafx.scene.control.cell.CheckBoxTableCell qui peut être utilisée pour représenter des valeurs booléennes sous forme de case à cocher. De plus, ici, nous n'aurons même pas besoin d'écrire une nouvelle classe ou un nouveau callback puisque CheckBoxTableCell propose directement une fabrique statique. L'appel à la méthode forTableColumn() permet de générer le callback qui sera chargé de créer les cellules de ces colonnes. Il nous suffit donc d'insérer dans notre code :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      visibleColumn.setCellFactory(CheckBoxTableCell.forTableColumn(visibleColumn));
      opaqueColumn.setCellFactory(CheckBoxTableCell.forTableColumn(opaqueColumn));
      administratorColumn.setCellFactory(CheckBoxTableCell.forTableColumn(administratorColumn));
      Pour que notre affichage se dote de case à cocher dans les colonnes contenant des valeurs booléennes :



      Édition

      [...]

      Pour qu’une valeur soit éditable dans la table, il faut que la table soit marquée comme éditable bien sur, mais aussi que la colonne le soit. Commençons donc par insérer les lignes suivantes dans notre code :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      visibleColumn.setEditable(true);
      nameColumn.setEditable(true);
      opaqueColumn.setEditable(true);
      commentColumn.setEditable(true);
      administratorColumn.setEditable(true);
      emailColumn.setEditable(true);
      tableView.setEditable(true);
      Et… et c’est tout en ce qui concerne les propriétés visible et opaque ! Il est en effet possible, dans la table, de cocher et décocher les cases [...]

      Ce qui démontre que notre objet t reçoit bien les nouvelles valeurs booléennes qui ont été éditées dans la table.
      Par contre, les colonnes contenant les valeurs des propriétés name, comment et email ne semblent pas vouloir être éditées : si on essaie de cliquer ou de double-cliquer sur le contenu de la cellule, rien ne se passe. Le problème se situe en fait au niveau de la cellule par défaut qui est produite : elle ne supporte pas l’édition. Ici aussi, l’API JavaFX vient à notre rescousse, nous allons utiliser la classe prête à l’emploi javafx.scene.control.cell.TextFieldTableCell. Cette classe permet d’utiliser un champ de saisie texte lors du passage en mode édition. Comme précédemment, il suffit d’appeler la méthode statique forTableColumn() pour disposer d’un callback prêt a l’emploi qui servira de fabrique de cellules. Insérons les lignes suivantes dans notre code :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      nameColumn.setCellFactory(TextFieldTableCell.<String>forTableColumn()); 
      commentColumn.setCellFactory(TextFieldTableCell.<String>forTableColumn()); 
      emailColumn.setCellFactory(TextFieldTableCell.<String>forTableColumn());
      Au lancement, aucun changement n'est discernable, la table est totalement identique à ce que nous avions précédemment.



      Cependant si on double clique sur une des colonnes contenant du texte, désormais, la cellule va basculer en mode édition.



      Les valeurs éditées dans les colonnes contenant les propriétés name et comment sont immédiatement reportées vers l'objet t une fois la validation effectuée [...]

      Les propriétés administrator et email vont demander un peu plus de travail ! Bien qu'il soit possible d'éditer le contenu de la table, les modifications ne sont pas reportées vers l'objet t.

      En ce qui concerne la propriété email, nous allons utiliser un callback sur la colonne. En effet, il nous suffit de placer un callback sur la propriété onEditCommit de la colonne : cette propriété est appelée lorsque l'utilisateur valide son édition. Nous pouvons donc récupérer la nouvelle valeur et la stocker dans notre objet t :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      emailColumn.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Truc, String>>() { 
          @Override 
          public void handle(TableColumn.CellEditEvent<Truc, String> event) { 
              System.out.printf("Mél %s -> %s", event.getOldValue(), event.getNewValue()).println(); 
              final Truc t = event.getRowValue(); 
              t.email = event.getNewValue(); 
          } 
      });
      Désormais, la propriété email est correctement mise à jour en cas d'édition !

      On serait tenté de faire quelques choses de similaire avec la propriété administrator. Cependant, si on le faisait, on se rendrait compte que le callback n'est jamais appelé. Le concepteur de CheckBoxTableCell a en effet estimé qu'il n'était pas utile que ce composant passe en mode édition lors de son activation. Après tout lors d'un clic, le changement de valeur est immédiatement reporté vers la propriété source dans la colonne.

      Nous allons donc pallier à ce problème en établissant un écouteur dans le code qui retourne une valeur observable à partir de notre objet t.

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      // Propriété administrator.         
      administratorColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Truc, Boolean>, ObservableValue<Boolean>>() {	 
          @Override 
          public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Truc, Boolean> p) { 
             final Truc t = p.getValue(); 
             final BooleanProperty result = new SimpleBooleanProperty(t.administrator); 
             result.addListener(new ChangeListener<Boolean>() { 
                 @Override 
                 public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue, Boolean newValue) { 
                     t.administrator = newValue; 
                 } 
             }); 
             return result; 
         } 
      });
      Désormais, en cas de modification de cette valeur dans la table, le membre correspondant dans l'objet est également correctement modifié !
    2. En ce qui concerne le bouton permettant de supprimer la valeur d'une ligne, je serai tente de faire la chose suivante.

      Tout d'abord, ici, un objet Type pour le test. Ici j'utilise des propriétés JavaFX mais on peut utiliser d'autres propriétés comme indiquées plus haut.

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      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
      public class Type {
       
          private final BooleanProperty visible = new SimpleBooleanProperty();
       
          public final boolean isVisible() {
              return visible.get();
          }
       
          public final void setVisible(boolean value) {
              visible.set(value);
          }
       
          public final BooleanProperty visibleProperty() {
              return visible;
          }
          private final StringProperty name = new SimpleStringProperty();
       
          public final String getName() {
              return name.get();
          }
       
          public final void setName(String value) {
              name.set(value);
          }
       
          public final StringProperty nameProperty() {
              return name;
          }
      }
      Et le programme qui affiche la table. Etant donne que tu n'as pas fourni le code de la classe ButtonCell, j'en ai crée une nouvelle sous forme de classe anonyme.

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      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
      public class Main extends Application {
       
          @Override
          public void start(Stage primaryStage) {
              final TableColumn<Type, String> nameColumn = new TableColumn<>("Nom");
              nameColumn.setCellValueFactory(new PropertyValueFactory("name"));
              nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
              final TableColumn<Type, Boolean> visibleColumn = new TableColumn<>("Visible");
              visibleColumn.setCellValueFactory(new PropertyValueFactory("visible"));
              visibleColumn.setCellFactory(CheckBoxTableCell.forTableColumn(visibleColumn));
              final TableColumn<Type, Void> deleteColumn = new TableColumn<>("Supprimer");
              deleteColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Type, Void>, ObservableValue<Void>>() {
       
                  @Override
                  public ObservableValue<Void> call(TableColumn.CellDataFeatures<Type, Void> p) {
                      return null;
                  }
              });
              deleteColumn.setCellFactory(new Callback<TableColumn<Type, Void>, TableCell<Type, Void>>() {
       
                  @Override
                  public TableCell<Type, Void> call(TableColumn<Type, Void> p) {
                      return new TableCell<Type, Void>() {
                          private Button button = new Button("Supprimer");
       
                          {
                              button.setMaxWidth(Double.MAX_VALUE);
                              button.setOnAction(new EventHandler<ActionEvent>() {
       
                                  @Override
                                  public void handle(ActionEvent t) {
                                      final Type item = (Type) getTableRow().getItem();
                                      System.out.println(item.getName());
                                      getTableView().getItems().remove(item);
                                  }
                              });
                          }
       
                          @Override
                          protected void updateItem(Void value, boolean empty) {
                              super.updateItem(value, empty);
                              final String text = null;
                              setText(null);
                              final Node graphic = (empty) ? null : button;
                              setGraphic(graphic);
                          }
                      };
                  }
              });
              final TableView<Type> tableView = new TableView<>();
              tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
              tableView.getColumns().setAll(nameColumn, visibleColumn, deleteColumn);
              final Type type1 = new Type();
              type1.setName("Foo");
              type1.setVisible(true);
              final Type type2 = new Type();
              type2.setName("Fuu");
              type2.setVisible(false);
              tableView.getItems().setAll(type1, type2);
              final StackPane root = new StackPane();
              root.getChildren().add(tableView);
              final Scene scene = new Scene(root, 300, 250);
              primaryStage.setTitle("Test bouton suppression");
              primaryStage.setScene(scene);
              primaryStage.show();
          }
       
          /**
           * @param args the command line arguments
           */
          public static void main(String[] args) {
              launch(args);
          }
      }
      Note : j'ai tape le code sous JDK8, meme si je n'ai pas utilise de lambda. Pour le JDK7, il faudra rajouter des <> ici et la pour retirer des erreurs liees au generics que le compilateur produit dans l'IDE. Par exemple :

      Code Java8 : Sélectionner tout - Visualiser dans une fenêtre à part
      nameColumn.setCellValueFactory(new PropertyValueFactory("name"));

      Si je n'abuse, pour compiler sous le JDK7, il faut écrire :

      Code Java7 : Sélectionner tout - Visualiser dans une fenêtre à part
      nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
    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

  5. #5
    Membre averti
    Inscrit en
    Mai 2010
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Mai 2010
    Messages : 36
    Par défaut
    Ok merci Bouye, mais ma question n'était pas assez précise.

    Si j'ai bien compris dans ton exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // Propriété administrator.         
    administratorColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Truc, Boolean>, ObservableValue<Boolean>>() {	 
        @Override 
        public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Truc, Boolean> p) { 
           final Truc t = p.getValue(); 
           final BooleanProperty result = new SimpleBooleanProperty(t.administrator); 
           result.addListener(new ChangeListener<Boolean>() { 
               @Override 
               public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue, Boolean newValue) { 
                   t.administrator = newValue; 
               } 
           }); 
           return result; 
       } 
    });
    L'instance t va ramener un boolean donc true ou false.

    Ma question était plutôt celle-ci : dans le cas ou ta tableView comporte plusieurs enregistrements il faut bien que je récupère mon enregistrement pour le delete.
    Ici dans ton exemple, il faut que je récupère par exemple la valeur de ma colonne nom pour faire un update de ma base de données et passer le nom "foo" comme administrateur.

    Comment relier ma checkbox à mon enregistrement?

    Par exemple, lorsque dans une colonne "éditable", je faisais un setOnEditCommit(TableColumn.CellEditEvent cellEditEvent). Ainsi je pouvais récupérer mon enregistrement et mettre à jour ma base de données de la manière suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     // Récupération de l'ancien enreg
            Type type = (Type) cellEditEvent.getRowValue();
     
            // Récupération de la nouvelle valeur
            String tipe = (String) cellEditEvent.getNewValue();
     
            type.setType(tipe);
     
            // DAO...

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    Reprenons :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public class Type {
        public String name;
        public boolean visible;
    }
    Le cellDataFeature passé en argument de la factory te permet également de récupérer la colonne et la table ainsi que l'objet. A partir de là tu peux récupérer la la valeur soit en manipulant l'ojbet source lui-même soit en pointant sur la bonne colonne et en retirant son contenu.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    public class Main extends Application {
     
        @Override
        public void start(Stage primaryStage) {
            final TableColumn<Type, String> nameColumn = new TableColumn<>("Nom");
            nameColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Type, String>, ObservableValue<String>>() {
     
                @Override
                public ObservableValue<String> call(TableColumn.CellDataFeatures<Type, String> cellDataFeature) {
                    final Type type = cellDataFeature.getValue();
                    return type == null ? null : new SimpleStringProperty(type.name);
                }
            });
            nameColumn.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Type, String>>() {
     
                @Override
                public void handle(TableColumn.CellEditEvent<Type, String> cellEditEvent) {
                    final Type type = cellEditEvent.getRowValue();
                    type.name = cellEditEvent.getNewValue();
                }
            });
            nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
            nameColumn.setEditable(true);
            final TableColumn<Type, Boolean> visibleColumn = new TableColumn<>("Visible");
            visibleColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Type, Boolean>, ObservableValue<Boolean>>() {
     
                @Override
                public ObservableValue<Boolean> call(final TableColumn.CellDataFeatures<Type, Boolean> cellDataFeature) {
                    final Type type = cellDataFeature.getValue();
                    ObservableValue<Boolean> result = null;
                    if (type != null) {
                        result = new SimpleBooleanProperty(type.visible);
                        result.addListener(new ChangeListener<Boolean>() {
     
                            @Override
                            public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue, Boolean newValue) {
                                final String name1 = type.name;
                                System.out.println(name1);
                                final TableColumn<Type, Boolean> tableColumn = cellDataFeature.getTableColumn();
                                final TableView<Type> tableView = cellDataFeature.getTableView();
                                final int index = tableView.getItems().indexOf(type);
                                final String name2 = (String)(tableView.getColumns().get(0).getCellData(index));
                                System.out.println(name2);
                                // [...]
                            }
                        });
                    }
                    return result;
                }
            });
            visibleColumn.setCellFactory(CheckBoxTableCell.forTableColumn(visibleColumn));
            visibleColumn.setEditable(true);
            final TableView<Type> tableView = new TableView<>();
            tableView.setEditable(true);
            tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
            tableView.getColumns().setAll(nameColumn, visibleColumn);
            final Type type1 = new Type();
            type1.name = "Foo";
            type1.visible = true;
            final Type type2 = new Type();
            type2.name = "Fuu";
            type2.visible = true;
            tableView.getItems().setAll(type1, type2);
            final StackPane root = new StackPane();
            root.getChildren().add(tableView);
            final Scene scene = new Scene(root, 300, 250);
            primaryStage.setTitle("Test bouton suppression");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
     
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            launch(args);
        }
    }
    Dans le cas où tu préfère conserver un bouton, tu peux faire aussi exactement la même chose dans le code de ton action.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    //        visibleColumn.setCellFactory(CheckBoxTableCell.forTableColumn(visibleColumn));
            visibleColumn.setCellFactory(new Callback<TableColumn<Type, Boolean>, TableCell<Type, Boolean>>() {
     
                @Override
                public TableCell<Type, Boolean> call(TableColumn<Type, Boolean> p) {
                    return new TableCell<Type, Boolean>() {
                        private Button button = new Button("Supprimer");
     
                        {
                            button.setMaxWidth(Double.MAX_VALUE);
                            button.setOnAction(new EventHandler<ActionEvent>() {
     
                                @Override
                                public void handle(ActionEvent t) {
                                    final Type item = (Type) getTableRow().getItem();
                                    final String name1 = item.name;
                                    System.out.println(name1);
                                    final String name2 = (String) (getTableView().getColumns().get(0).getCellData(getIndex()));
                                    System.out.println(name2);
                                    // [...]
                                }
                            });
                        }
     
                        @Override
                        protected void updateItem(Boolean value, boolean empty) {
                            super.updateItem(value, empty);
                            final String text = null;
                            setText(null);
                            final Node graphic = (empty) ? null : button;
                            setGraphic(graphic);
                        }
                    };
                }
            });
    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

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [WD18] Metre une colonne d'une Table sur une ligne d'une autre Table
    Par Totophe2 dans le forum WinDev
    Réponses: 2
    Dernier message: 22/11/2013, 12h58
  2. Réponses: 2
    Dernier message: 18/11/2012, 11h25
  3. Réponses: 7
    Dernier message: 25/03/2011, 10h52
  4. Réponses: 4
    Dernier message: 31/10/2007, 20h27
  5. [2.0] Mettre une Checkbox dans le header d'une colonne d'une DatagridView
    Par aurelien.tournier dans le forum Windows Forms
    Réponses: 5
    Dernier message: 23/01/2007, 10h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo