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 :

Problème de binding - tableau dynamique


Sujet :

JavaFX

  1. #1
    Membre du Club
    Homme Profil pro
    Ingénieur projet
    Inscrit en
    Juin 2014
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur projet
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2014
    Messages : 46
    Points : 43
    Points
    43
    Par défaut Problème de binding - tableau dynamique
    Bonjour,

    Je rencontre actuellement un problème pour une application que je développe. J'utilise une classe 'Compose' qui entre autre me permet de stoker le nom d'un composé ainsi que l'évolution de sa concentration sous forme d'une liste Observable ('concentrationComposeList '). Mon but est de lister de manière dynamique dans un tableau les valeurs contenues dans la liste 'concentrationComposeList' pour chaque composé généré par l'utilisateur.

    Chaque colonne de mon tableau 'table' correspond donc à un composé. Les différentes lignes du tableau listent les valeurs contenues dans concentrationComposeList.
    La seul façon que j'ai trouvé pour faire ça c'est de générer une liste 'data' de listes et de l'afficher dans le tableau.

    Voici la méthode suivie:
    A partir de la liste 'composeList' contenant l'ensemble des composés générés, je génère des sous listes 'row'
    Chaque sous liste 'row' correspond à une ligne du tableau et est formée par les différentes concentrations des différents composés pour un même index.

    La liste 'data' généré en compilant toutes ces sous listes 'row' est affichée dans le tableau.
    Cela fonction puisque je visualise bien les valeurs.

    Mon problème en procédant de cette manière est que les valeurs contenues dans le tableau et donc contenues dans 'data' ne sont pas liées aux valeurs contenues dans ComposeList. Pour s'en assurer, j'ai fait un petit test modifiant une valeur, dans l'un des composés listés dans ComposeList, la modifications n'est pas reportée dans le tableau...

    Je souhaite ajouter des fonctionnalités d'édition des cellules du tableau, et de copier / coller de leur contenu. Il est donc indispensable pour moi que les valeurs contenues dans ComposeList soient correctement liées au contenu du tableau.
    J'ai donc besoin de votre aide pour faire ça de manière plus élégante, et surtout pour faire en sorte que les valeurs listées dans le tableau soient liés aux composés générés par l'utilisateur...

    Merci d'avance pour votre aide...


    Voici le code de la classe Compose utilisée pour stocker les différentes données :
    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
     
    package application;
     
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.property.StringProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
     
    /**
     * Création d'une classe Compose qui permet de stocker à la fois 
     * le nom d'un composé ainsi que l'évolution de sa concentration au cours du temps
     */
    public class Compose{
    	// Nom du composé
    	private final StringProperty  nomCompose; 
     
    	// Liste permettant de stocker la concentration au cours du temps du composé
    	private ObservableList<DoubleProperty> concentrationComposeList = FXCollections.observableArrayList();
     
    	public Compose(String nom){
    		this.nomCompose = new SimpleStringProperty(nom);
     
    		// Pour cet exemple, la liste est générée aléatoirement
    		for (int i=0; i< Math.round(Math.random()*10+5); i++){
    			concentrationComposeList.add(new SimpleDoubleProperty(Math.round(Math.random()*10)));
    		}
    	}
     
    	public String getNomCompose() {
    		return nomCompose.get();
    	}
     
    	public void setNomCompose(String nomCompose) {
    		this.nomCompose.set(nomCompose);
    	}
     
    	 public StringProperty nomComposeProperty() {
    	        return nomCompose;
    	    }
     
     
     
    	public ObservableList<DoubleProperty> getConcentrationComposeList() {
    		return concentrationComposeList;
    	}
     
    	public void setConcentrationComposeList(ObservableList<DoubleProperty> concentrationComposeList) {
    		this.concentrationComposeList = concentrationComposeList;
    	}
    }
    Voici le code de ma classe principale
    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
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
     
    package application;
     
    import java.text.NumberFormat;
    import javafx.application.Application;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.value.ObservableValue;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.scene.Scene;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableColumn.CellDataFeatures;
    import javafx.scene.control.TableView;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.text.Text;
    import javafx.stage.Stage;
    import javafx.util.Callback;
     
    public class TableCopyPasteCellsTest extends Application {
     
    	private final static ObservableList<Compose> composeList = FXCollections.observableArrayList();
     
    	@SuppressWarnings("rawtypes")
    	private static ObservableList<ObservableList> data;
     
    	public static void main(String[] args) {
    		launch(args);
    	}
     
    	static int minNumberValue; // Variable permettant de connaître le nombre de valeurs de la plus petite série de données affichée dans le tableau
    	static int maxNumberValue; // Variable permettant de connaître le nombre de valeurs de la plus grande série de données affichée dans le tableau
     
     
    	private static NumberFormat numberFormatter = NumberFormat.getNumberInstance();
     
    	@SuppressWarnings({ "unchecked", "rawtypes" })
    	public void start(Stage stage) {
     
    		// Ajout de nouveaux composés tests à la liste data.
    		composeList.add(new Compose("A"));
    		composeList.add(new Compose("B"));
     
    		// Création du tableau
    		TableView table = new TableView<>();
    		table.setPlaceholder(new Text("No content in table"));
     
    		data = FXCollections.observableArrayList();
     
     
    		// création des différentes colonnes.
    		int i=0;
    		for (Compose p: composeList){
    			final int j=i;
    			TableColumn col = new TableColumn(p.getNomCompose());
    			col.setMinWidth(100);
     
    			col.setEditable(true);
    			col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
    				public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
    					// On vérifie que l'élément param.getValue().get(j) contient bien une valeur.
    					// Cela évite les erreurs de type "java.lang.Null Point Exception" dans le cas où les listes n'ont pas les mêmes longueur.
    					if (param.getValue().get(j) != null){
    						return new SimpleStringProperty(param.getValue().get(j).toString());   
    					}else {
    						return new SimpleStringProperty("");
    					}
    				}                   
    			});
     
    			i++;
     
    			table.getColumns().addAll(col);			
    			table.setEditable(true);
    		}
     
     
    		// Calcul du nombre de valeurs min et max contenues dans les séries de données de l'ensemble des composés
    		minNumberValue = composeList.get(0).getConcentrationComposeList().size();
    		maxNumberValue = composeList.get(0).getConcentrationComposeList().size();
    		for (Compose p: composeList){
    			if (p.getConcentrationComposeList().size()<minNumberValue){
    				minNumberValue = p.getConcentrationComposeList().size();
    			}
     
    			if (p.getConcentrationComposeList().size()>minNumberValue){
    				maxNumberValue = p.getConcentrationComposeList().size();
    			}
    		}
    		displayComposeList();
     
     
    		// Ajout des données à la liste ObservableList data
    		for (int j=0; j<maxNumberValue+1; j++){
    			ObservableList<String> row = FXCollections.observableArrayList();
    			row.clear();
    			for (Compose p: composeList){
    				if (p.getConcentrationComposeList().size() > j){
    					row.add(String.valueOf(p.getConcentrationComposeList().get(j).get()));
    				}else {
    					row.add(null);
    				}
     
    			}
    			data.add(row);
    		}
     
    		table.setItems(data);
     
    		// test permettant de vérifier si les listes composeList et data sont liées ou non
    		System.out.println(composeList.get(0).getConcentrationComposeList().get(0));
    		System.out.println("Modification de la première valeur du tableau dans la liste des composés");
    		composeList.get(0).getConcentrationComposeList().get(0).set(0);
    		System.out.println(composeList.get(0).getConcentrationComposeList().get(0));
    		System.out.println(data);
     
    		BorderPane borderPane= new BorderPane();
    		borderPane.setCenter(table);
     
     
    		Scene scene = new Scene(borderPane);
     
    		stage.setScene(scene);
    		stage.show();
     
    	}
     
    	private void displayComposeList(){
     
    		System.out.println("ComposeList : ");
    		for (int j=0; j<maxNumberValue; j++){
    			for (Compose p: composeList){
    				if (p.getConcentrationComposeList().size() > j){
    					System.out.print(p.getConcentrationComposeList().get(j).get()+"\t");
    				}else {
    					System.out.print("null"+"\t");
    				}	
    			}
    			System.out.println("");
    		}
    	}
    }

  2. #2
    Rédacteur/Modérateur

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

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

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Hum, j'ai mal ai crane (comme toujours des que je touche aux JTable ou a TableView).

    Ton problème vient je pense de ta fabrique a valeurs de cellule (c'est tellement plus facile a lire avec des lambda ) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
        public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
                // On vérifie que l'élément param.getValue().get(j) contient bien une valeur.
                // Cela évite les erreurs de type "java.lang.Null Point Exception" dans le cas où les listes n'ont pas les mêmes longueur.
                if (param.getValue().get(j) != null){
                        return new SimpleStringProperty(param.getValue().get(j).toString());   
                }else {
                        return new SimpleStringProperty("");
                }
        }                   
    });
    Tu crée certes une propriété qui empaquète la valeur provenant de ton compose mais c'est tout. Je m'explique : en cas de changement de valeur de la propriété après l’édition ce la cellule, ce changement de valeur n'est pas reporté vers le compose. La valeur qui sort de la composante n'est pas une propriété FX (ou bean), elle ne sait pas du tout quand la propriété qui a été créée à partir d'elle a été modifiée. En effet, il te manque un écouteur pour faire le cheminement inverse.

    Il te faudrait, je pense, modifier le code pour mettre un truc du genre (à tester) :

    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
    new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
        public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
                // On vérifie que l'élément param.getValue().get(j) contient bien une valeur.
                // Cela évite les erreurs de type "java.lang.Null Point Exception" dans le cas où les listes n'ont pas les mêmes longueur.
                if (param.getValue().get(j) != null){
    //                return new SimpleStringProperty(param.getValue().get(j).toString());
                    StringProperty property = new SimpleStringProperty(param.getValue().get(j).toString());
                    property.addListener(new ChangeListener<String>() {
     
                        @Override
                        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                            param.getValue().set(j, newValue);
                        }
                    });
                    return property;
                }else {
                        return new SimpleStringProperty("");
                }
        }                   
    });
    Bon, par contre pour le coup je ne pige pas pourquoi tu fais une TableView<ObservableList<String>> (en extrapolant de ton code) et pourquoi tu ne fais pas directement une TableView<Compose> en fait
    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 du Club
    Homme Profil pro
    Ingénieur projet
    Inscrit en
    Juin 2014
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur projet
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2014
    Messages : 46
    Points : 43
    Points
    43
    Par défaut
    Merci pour cette piste de réponse, le contenu du tableau est effectivement désormais bien lié au contenu de la liste 'data' avec cette nouvelle méthode, mais le contenu de data et de composeList ne le sont pas. Je vais essayer d'adapter cela à mon code et de lier le contenu de data avec celui des éléments contenus dans composeList.

    je suis passé par un 'TableView<ObservableList<String>>' parceque je ne suis pas parvenu à utiliser directement un 'TableView<Compose>'. Je pense aussi que ce serait préférable, mais à défaut d'arriver à faire mieux, j'ai du contourner ce problème.

    J'aurai aimé travailler directement avec la liste 'composeList' pour alimenter le tableau, mais je n'arrive pas à générer le tableau colonne par colonne. Du coup j'ai généré une nouvelle liste contenant chaque ligne du tableau sous forme de liste ... Je pense qu'il y a très certainement mieux comme façon de faire, mais là, je ne trouve pas d'autre solution ...

    Si vous avez d'autres pistes, elles sont bien entendu les bienvenues.
    En tous cas, merci pour l'aide apportée.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    876
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2005
    Messages : 876
    Points : 491
    Points
    491
    Par défaut
    Citation Envoyé par bouye Voir le message
    Hum, j'ai mal ai crane (comme toujours des que je touche aux JTable ou a TableView).

    Bonjour,

    Que suggère tu d'utiliser en lieu et place de TableView ?

    j'ai lu avec attention ton article:
    http://www.developpez.net/forums/d14...fabrice-bouye/

    Et je n'y avait pas détecté ton aversion pour les TableView.
    Je m'en vais d'ailleurs te poser une question dans une discussion à suivre.

  5. #5
    Rédacteur/Modérateur

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

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

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Ça c’était avant.

    Désormais, étant pas mal habitué aux interfaces mobiles, tablettes ou autre bootstrap, souvent une ListView fait aussi bien le travail qu'une TableView surtout quand il s'agit de montrer des données complexes en lecture seule et ce sans avoir besoin de créer 45.000 classes pour chaque colonne.

    Sur la demande de notre responsable de section Java, je viens de mater une des présentations JavaFX de la JavaOne 2015 et on y montre un ListView utilisé comme un... éditeur de code avec saisie, colorisation syntaxique et détecteur d'erreur et suggestions d'auto-completion (vivi exactement comme la partie édition de code dans votre Eclipse, NetBeans, IDEA). En fait c'est vachement puissant ListView.
    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

Discussions similaires

  1. [CS3] Problème sur un tableau dynamique
    Par Yep_yep dans le forum Dreamweaver
    Réponses: 0
    Dernier message: 16/09/2009, 13h08
  2. [phpToPDF] Affichage tableau dynamique
    Par fat dans le forum Bibliothèques et frameworks
    Réponses: 17
    Dernier message: 23/05/2007, 16h19
  3. problème sur un tableau dynamique
    Par boss_gama dans le forum ASP
    Réponses: 9
    Dernier message: 24/08/2006, 17h27
  4. Problème avec PtInRegion et un tableau dynamique
    Par mduse dans le forum Langage
    Réponses: 2
    Dernier message: 06/12/2005, 09h29

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