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

Composants Java Discussion :

Ajout de colonnes dynamiquement (getColumnClass)


Sujet :

Composants Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 26
    Par défaut Ajout de colonnes dynamiquement (getColumnClass)
    Bonjour à tous,

    Voila, je suis en train de chercher pour pouvoir ajouter des colonnes de façon dynamique dans une JTable. Le problème, c'est que les cellules ont des render différents suivant la cellule.
    Je ne sais donc pas comment modifier la méthode getColumnClass (int colIndex); pour que quelle que soit le nombre de colonne que l'on ajoute, les renders s'appliquent toujours au bonne colonnes.

    Voici le source du getColumnClass :
    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
    public Class getColumnClass (int columnIndex) {
    		switch (columnIndex) {
    			case 2:
    				return Sexe.class;
    			case 5:
    				return Bourse.class;
    			case 6:
    				return Bac.class;
    			case 7:
    				return Semester.class;
    			case 9:
    				return Semester.class;
    			case 11:
    				return Semester.class;
    			case 13:
    				return Semester.class;
    			case 15:
    				return SemesterPostDut.class;
    			case 17:
    				return SemesterPostDut.class;
    			case 19:
    				return Dut.class;
    			case 20:
    				return PostDUT.class;
    			case 21:
    				return Studies.class;
    			case 23:
    				return Studies.class;
    			case 25:
    				return Studies.class;
    			case 27:
    				return Studies.class;
    			case 29:
    				return Studies.class;
    			case 31:
    				return Studies.class;
    			case 33:
    				return Studies.class;
    			case 35:
    				return Studies.class;
    			case 37:
    				return Studies.class;
    			default:
    				return Object.class;
    		}
    //		return getValueAt(0, columnIndex).getClass();
    	}
    Si par exemple on ajoutait les colonnes en fin de tableau, ce serait assez simple il n'y aurait rien à modifier (puisque les renders des colonnes qu'on ajoute sont de type Object).
    Mais à termes, mon application devra pouvoir ajouter une colonne à n'importe quel endroit de la JTable, d'où mon problème.

    EDIT :
    Sur le site de sun, il utilise ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public Class getColumnClass(int c) {
            return getValueAt(0, c).getClass();
        }
    Malheureusement cela me sort un NullPointerException ...

    Si vous avez des idées, merci d'avance,
    Elhina

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    La question est avant tout de savoir comment tu gères ces colonnes. A quoi ressemble ton TableModel exactement et comment tu comptes rajouter des colonnes...


    a++

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 26
    Par défaut
    Mon model ressemble à ceci :
    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
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    package view;
     
    import javax.swing.table.AbstractTableModel;
     
    import controller.Controller;
    import enumeration.*;
     
    @SuppressWarnings("serial")
    public class TableModel extends AbstractTableModel {
     
    	private Object[][] data;
    	private String[] title;
    	private Controller controller;
     
    	public TableModel (Object[][] data, String[] title, Controller controller) {
    		this.data = data;
    		this.title = title;
    		this.controller = controller;
    	}
     
    	@Override
    	public int getColumnCount () {
    		return this.title.length;
    	}
     
    	@Override
    	public int getRowCount () {
    		return this.data.length;
    	}
     
    	public String getColumnName (int col) {
    		return this.title[col];
    	}
     
    	public boolean isCellEditable (int row, int col) {
    		return true; // Toutes les cellules sont éditables
    	}
     
    	@Override
    	public Object getValueAt (int row, int col) {
    		return this.data[row][col];
    	}
     
    	@Override
    	public void setValueAt (Object aValue, int rowIndex, int columnIndex) {
    		if (aValue != null) {
    			if (aValue instanceof Bac) {
    				data[rowIndex][columnIndex] = (Bac) aValue;
    				controller.modifStudent (aValue.toString (), columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    			else if (aValue instanceof Bourse) {
    				data[rowIndex][columnIndex] = (Bourse) aValue;
    				controller.modifStudent (aValue.toString (), columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    			else if (aValue instanceof Dut) {
    				data[rowIndex][columnIndex] = (Dut) aValue;
    				controller.modifStudent (aValue.toString (), columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    			else if (aValue instanceof PostDUT) {
    				data[rowIndex][columnIndex] = (PostDUT) aValue;
    				controller.modifStudent (aValue.toString (), columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    			else if (aValue instanceof Semester) {
    				data[rowIndex][columnIndex] = (Semester) aValue;
    				controller.modifStudent (aValue.toString (), columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    			else if (aValue instanceof SemesterPostDut) {
    				data[rowIndex][columnIndex] = (SemesterPostDut) aValue;
    				controller.modifStudent (aValue.toString (), columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    			else if (aValue instanceof Sexe) {
    				data[rowIndex][columnIndex] = (Sexe) aValue;
    				controller.modifStudent (aValue.toString (), columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    			else if (aValue instanceof Studies) {
    				data[rowIndex][columnIndex] = (Studies) aValue;
    				controller.modifStudent (aValue.toString (), columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    			else {
    				data[rowIndex][columnIndex] = (String) aValue;
    				controller.modifStudent ((String) aValue, columnIndex, Integer.parseInt ((String) data[rowIndex][controller.getModel ().getCohort ().getIndexID ()]));
    			}
    		}
    	}
     
    	@SuppressWarnings("unchecked")
    	@Override
    	public Class getColumnClass (int columnIndex) {
    		controller.getModel ().getModelPrefProperties ().getClassCol ();
    		switch (controller.getModel ().getModelPrefProperties ().getClassCol ()[columnIndex]) {
    			case 0:
    				return Object.class;
    			case 1:
    				return Sexe.class;
    			case 2:
    				return Bourse.class;
    			case 3:
    				return Bac.class;
    			case 4:
    				return Semester.class;
    			case 5:
    				return SemesterPostDut.class;
    			case 6:
    				return Dut.class;
    			case 7:
    				return PostDUT.class;
    			case 8:
    				return Studies.class;
    			default:
    				return Object.class;
    		}
    	}
     
    	public void addRow (Object[] data) {
    		int indice = 0, nbRow = this.getRowCount (), nbCol = this.getColumnCount ();
     
    		Object temp[][] = this.data;
    		this.data = new Object[nbRow + 1][nbCol];
     
    		for (Object[] value : temp)
    			this.data[indice++] = value;
     
    		this.data[indice] = data;
    		temp = null;
    		//Cette méthode permet d'avertir le tableau que les données ont été modifiées
    		//Ce qui permet une mise à jours complète du tableau
    		this.fireTableDataChanged ();
    	}
     
    	public void removeRow (int position) {
     
    		int indice = 0, indice2 = 0, nbRow = this.getRowCount () - 1, nbCol = this.getColumnCount ();
    		Object temp[][] = new Object[nbRow][nbCol];
     
    		for (Object[] value : this.data) {
    			if (indice != position) {
    				temp[indice2++] = value;
    			}
    			indice++;
    		}
    		this.data = temp;
    		temp = null;
    		// Cette méthode permet d'avertir le tableau que les données ont été modifiées
    		// Ce qui permet une mise à jours complète du tableau
    		this.fireTableDataChanged ();
    	}
     
    	public void changeStructure () {
    		this.fireTableStructureChanged ();
    	}
    }
    J'ai ces colonnes dans une base de données, mais je les ai également dans un fichier properties où chaque ligne correspond à une colonne. Le fichier properties et la BDD doivent donc correspondre.

    Comment je souhaite ajouter une colonne ? Ajouter une colonne modifie la BDD (forcément) et positionne la colonne à la place qu'il faut (par exemple entre la colonne Département et celle du Bac). Ceci est donc au niveau de la BDD. En suite il faut ajouter une colonne dans le fichier properties (avec toutes les nouvelles propriétés. Enfin le programme doit être capable :
    - d'aller chercher dynamiquement toutes les colonnes de la BDD (OK)
    - d'aller chercher dynamiquement toutes les colonnes dans le fichier properties (NOK ce n'est pas encore dynamiquement)
    - d'afficher correctement toutes les colonnes à leur bon emplacement et surtout que leur CellEditor et CellRenderer correspondent bien. (NOK)
    Pour le dernier j'ai donc modifié le getColumnClass pour que ce soit dynamique (je passe par un fichier properties contenant un numéro pour savoir quels sont les bon CellEditor et CellRenderer à appliquer).

    Le model que j'ai affiché ci-dessus comprend la nouvelle méthode getColumnClass où tout fonctionne à part la recherche dynamique du fichier properties des colonnes (2ème point).
    Ceci dit, ça fonctionne mais peut-être n'est-ce pas la bonne méthode ?

    Elhina

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Ben en fait j'ai pas trop compris comment tu fais l'association entre une colonne et son type...
    Tu ne peux pas récupérer ces infos de la BDD ???


    Mais bon j'ai quand même quelques remarques sur ton code :
    • A la place du @SuppressWarnings("serial"), il serait préférable de définir un serialVersionUID (FAQ Java : [Java 5.0] serial : "serializable class Main has no definition of serialVersionUID"
    • Pour le @SuppressWarnings("unchecked"), il serait préférable de définir correctement le type de retour (Class<?> à la place de Class).
    • A quoi servent les if/elses dans la méthode setValueAt() puisque tu fais la même chose à chaque fois ???
    • fireTableDataChanged() indique que toutes les lignes ont changées. Or dans tes méthodes addRow() et removeRow() il serait plus judicieux d'utiliser respectivement fireTableRowsInserted() et fireTableRowsDeleted()...
    • De même, la méthode setValueAt() devrait générer un évènement de type fireTableCellUpdated().



    a++

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 26
    Par défaut
    Je lis les types des colonnes dans un fichier.
    La BDD ne contient qu'une seule table contenant toutes les informations propres à chaque étudiant.

    Pour le suppressWarning, même si je ne serialisera jamais cette classe, je dois mettre un numéro ?
    La méthode setValueAt ne fait pas toujours la même chose : il y a un cast sur le type de la colonnes (d'où le if/else if).
    Sinon merci pour tes remarques sur les fireTable (ainsi que le Class<?>. J'en prend bien note .

    Elhina

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 906
    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 906
    Billets dans le blog
    54
    Par défaut
    Voyons voir...
    La dernière fois que j'ai réellement bosse sur du Swing a plein temps (c'est a dire il y a 2 ans), je commençais a en avoir le souper de ces faiblesses de l'architecture de la JTable et de son modèle et j'en étais venu à définir 2 nouvelles classes (de mémoire) :

    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
    public class CustomTableCellRenderer extends TableCellRenderer {
      private Map<Class<?>, TableCellRenderer>> rendererMap = new HashMap<Class<?>, TableCellRenderer>>();
     
      public CustomTableCellRenderer() {
         DefaultTableCellRenderer defaultRenderer = new DefaultTableCellRenderer();
         install(Object.class, defaultRenderer);
         install(Number.class, defaultRenderer);
         install(Boolean.class, defaultRenderer);
         install(String.class, defaultRenderer);
      }
     
      public TableCellRenderer install(Class<?> classType, TableCellRenderer renderer) throws IllegalArgumentException {
        if (classType == Object.class) {
          throw new IllegalArgumentException("Cannot change the base renderer.");
        }
        return rendererMap.put(classType, renderer);
      }
     
      public TableCellRenderer uninstall(Class<?> classType) throws IllegalArgumentException  {
        if (classType == Object.class) {
          throw new IllegalArgumentException("Cannot change the base renderer.");
        }
        return rendererMap.remove(classType);
      }
     
      /**
       * {@inheritDoc}
       */
      @Override
      public Component getTableCellRendererComponent(JTable table, Object value,  boolean isSelected, boolean hasFocus, int row, int column) {
        TableCellRenderer delegated = null;
        if (value == null) {
          delegated = rendererMap.get(Object.class);
        } else {
          Class<?> classType = value.getClass();
          // Remonter la hiérarchie des types (interfaces et classes) de l'objet jusqu’à trouver un renderer approprié. Sinon, utiliser par défaut le renderer de Object.class
        }
        return delegated.getTableCellRendererComponent(table, value,  isSelected, hasFocus, row, column);
      }
    }
    Et un truc similaire pour l'editor. Comme ca getColumnClass() peut se contenter de retourner Object.class, on peut mixer plusieurs types de valeurs pour chaque columne, etc...
    Raz la caquette qu'apres 13 ans ils soient toujours pas foutu de corriger ou d'offrir des implémentations alternatives pour pallier a tous ces défauts de mauvaise conception.

    Ce qui me fait remarquer que l'interface TableModel n'a pas ete generecifiee dans Java7... meme pas etonne...
    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

  7. #7
    Membre Expert Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 023
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 023
    Par défaut
    Salut,
    j'étais face au problème du mix de différents types dans une même colonne.
    Merci, bouye, pour ta classe qui fonctionne très bien, il fallait y penser.
    En revanche, à force de décortiquer les sources de JTable je suis arrivé à quelque chose de plus concis. Car JTable initialise déjà des éditeurs/renderers par défaut :

    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
    	this.table = new JTable(new EntitiesTableModel()) {
    			 @Override
    			 public TableCellRenderer getCellRenderer(int row, int column)    {
    			   TableCellRenderer renderer = getDefaultRenderer(dataModel.getValueAt(convertRowIndexToModel(row), convertColumnIndexToModel(column)).getClass());
    				if(renderer == null)	{
    					renderer = getDefaultRenderer(Object.class);
    					if(renderer == null)	{
    						renderer = new DefaultTableCellRenderer();
    						setDefaultRenderer(Object.class, renderer);				
    					}
    				}
    				return renderer;
    		    }
     
    			 @Override
    			 public TableCellEditor getCellEditor(int row, int column)    {
    				TableCellEditor editor = getDefaultEditor(dataModel.getValueAt(convertRowIndexToModel(row), convertColumnIndexToModel(column)).getClass());
    				if(editor == null)	{
    					editor = getDefaultEditor(Object.class);
    					if(editor == null)	{
    						editor = new DefaultCellEditor(new JTextField());
    						setDefaultEditor(Object.class, editor);						
    					}
    				}
    				return editor;
    			 }
     
    		};
    Si quelqu'un voit des problèmes, n'hésitez pas, merci
    En revanche, j'ai un plantage avec le tri, je ne sais pas encore si ça vient de cela.
    (Ça peut peut-être aller dans les contribs.)

    [Edit] Oui pour que le tri fonctionne il ne faut pas oublier de redéfinir dans le TableModel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	public Class getColumnClass(int c) {
    			 return Object.class;
    		}

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

Discussions similaires

  1. Ajouter Colonne dynamique
    Par benbrisefer dans le forum SAS Base
    Réponses: 5
    Dernier message: 04/10/2011, 15h01
  2. Réponses: 9
    Dernier message: 23/03/2010, 17h52
  3. Réponses: 4
    Dernier message: 17/09/2008, 18h05
  4. tsql : ajout des colonnes dynamiques
    Par silset dans le forum Langage SQL
    Réponses: 4
    Dernier message: 05/06/2008, 15h21
  5. [SQLServer] ajout de colonne dynamique
    Par pi05 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 19/05/2006, 11h14

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