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 :

getModel() ne permet pas l'accès à une méthode 'public' dans 'monModèleTable'


Sujet :

Composants Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    263
    Détails du profil
    Informations personnelles :
    Âge : 73
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 263
    Points : 121
    Points
    121
    Par défaut getModel() ne permet pas l'accès à une méthode 'public' dans 'monModèleTable'
    Bonjour - bonsoir,
    Me voici de retour avec une question, après un an environ.

    J'ai une application Swing comportant 3 panneaux à onglet. Chacun de ceux-ci comporte une JTable à laquelle est associée un MonModèleTable, dérivé d'un AbastracTableModel, qui lui est propre. Mon package contient donc principalement
    - 3 classes public class TabPan_X extends JPanel implémentant chacune une JTable.
    - 3 classes public class MonModTable_X extends AbstractTableModel
    - 1 classe 'public class Energie extends JScrollPane' comportant quelques méthodes utilisées pas ces 3 classes 'class TabPan_X' et surtout nécessitant l'accès aux tables et aux modèles de tables précitées, pour passage de données.

    Dans chaque classe 'TabPan_X extends JPanel'
    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
        private final Energie énergie;
        private final JTable table_X;
        private MonModTable_X monModTable_X;
        ...
        public TabPan_X(EnergElectr energie)
        {   
            this.énergie = energie;
     
            monModTable_X = new MonModTable_X();
            table_X = new JTable(monModTable_X)
            {   
                // Overrides method from javax.swing.JTable
                @Override public Component prepareRenderer(TableCellRenderer renduCelluleTable, int rang, int col)
                {   // Energie.this.renduCelluleTable = renduCelluleTable;
                    // Le 'super' de 'TabPan_X' devrait être le 'JPanel'.
                    Component compos_X = super.prepareRenderer(renduCelluleTable, rang, col);
                    compos_X.setBackground(...
                    ...
                    return compos_...
                }
            };
            ...
        }
        ...
        public JTable getTable_X()
        {   return table_X;
        }
        ...
    }
    et dans chaque classe MonModTable_X extends AbstractTableModel
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class MonModTable_X extends AbstractTableModel{   
        ...
        private ArrayList<Object> donnéesDUneTranPuiss;
        // Où le modèle tiendra ses données.
        private final ArrayList<ArrayList<Object>> donnéesTteLaTable;
        ...
            donnéesTteLaTable = new ArrayList<>();
        ...
        public ArrayList<ArrayList<Object>> getDonnéesTteLaTable()
        {   return donnéesTteLaTable;
        }
        ...
    Dans tout autre classe instanciée (energie, monModTable_Y, ...), il me faut pouvoir accéder à une méthode ('getDonnéesTteLaTable()') dans 'monModTable_X', par exemple pour remplacer des valeurs de cellules par d'autres, en faisant suivre par exemple par un 'fireTableCellUpdate()' ou un 'fireTableRowsInserted(). Pour réussir ces accès, je m'attendais appliquer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        tab_Energie.getTabPnl_X().getTable_X().getModel().getDonnéesTteLaTable(...);
    En tapant '.' après 'getMode()', mon IDE me présente la liste d'une vingtaine de membres atteignables, tel que 'getValueAt(int i, int i1)', mais hélas pas ma méthode publique 'getDonnéesTteLaTable()'.
    Comment cela se fesse-t-il ? J'ai beau revoir Creating a Table Model.

    Et l'interface javax.swing.table.TableModel ne mentionne pas une méthode équivalente à 'getDonnéesTteLaTable()' que je devrais sur-écrire.

    J'y remédie en implémentant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        tab_Energie.getTabPnl_X().monModTable_X.getDonnéesTteLaTable());
    , mais cela m'a l'air moins orthodoxe, puisque j'accède à 'monModèleTable' sans utiliser 'getTable_X()'.

    Merci d'avance de tenter de m'aider.
    "Ah oui ! Juste encore cette toute dernière petite question ..." (Columbo - Peter Falk)

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Si tu regardes la javadoc de la méthode JTable.getModel(), tu peux voir que son type de retour est l'interface TableModel. Interface qui est implémentée par la classe AbstractTableModel que tu as étendue pour faire ta classe de modèle MonModTable_X. C'est cette interface qui permet à la JTable d'utiliser la classe comme modèle de table. Et donc c'est normal que la méthode retourne ce type. Mais si tu fournis une instance d'une classe concrète MonModTable_X comme modèle à une JTable, quand tu récupères cette instance par la méthode getModel(), elle est typée TableModel (forcément ceux qui ont écrit la classe JTable ne pouvaient pas connaitre ta classe à toi), mais c'est bien une instance de ta classe concrète, donc tu peux la caster vers cette classe.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    TableModel model = tab_Energie.getTabPnl_X().getTable_X().getModel();
    MonModTable_X modelSpecifique = (MonModTable_X)tab_Energie.getTabPnl_X().getTable_X().getModel(); // on aurait pu faire aussi MonModTable_X modelSpecifique = (MonModTable_X)model;
    Les méthodes spécifiques à ta classe, qui n'existent pas dans l'interface TableModel, ne peuvent être appelées sur model, mais peuvent être appelées sur modelSpecifique.

    Par contre, si tu as besoin de faire beaucoup de manipulation sur ton modèle, il est préférable que tu maintiennes une variable typée de ta classe afin d'éviter d'avoir à récupérer le TableModel sur la JTable et le caster, à moins que tu ne puisses vraiment pas faire autrement. Dans ce cas, tu peux aussi vérifier que c'est bien une instance de la classe en question, en particulier si c'est une méthode susceptible de traiter différente JTable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    TableModel model = tab_Energie.getTabPnl_X().getTable_X().getModel();
    if ( model instanceof MonModTable_X ) {
        MonModTable_X modelSpecifique = (MonModTable_X)model;
        // faire les traitements spécifiques à ton modèle
    }
    // faire les autres traitements
    Par ailleurs, regarde plus précisemment la notion d'interface, essentielle en Java.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    263
    Détails du profil
    Informations personnelles :
    Âge : 73
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 263
    Points : 121
    Points
    121
    Par défaut
    Cher Joël,
    Merci beaucoup pour toutes tes explications.
    Mais oui, bien sûr : caster à l'aide de ma classe le type retourné par l'interface qui retourne bien entendu un type générique - interface TableModel dont les méthodes sont implémentées dans AbstractTableModel ou dans ma classe - que getModel() n'aurait pu connaître.
    Fait, testé et cela fonctionne.

    Ah oui ! encore cette toute dernière petite question, pour terminer :
    Comme exposé dans ma première intervention de cette conversation, toutes les classes que j'utilise héritent chacune déjà d'une classe de Swing
    - 3 classes public class TabPan_X extends JPanel
    - 3 classes public class MonModTable_X extends AbstractTableModel
    - 1 classe public class Energie extends JScrollPane
    et bien d'autres encore.
    Java n'autorisant pas le multiple héritage, les utilisateurs de Swing sont vite empêchés d'implémenter une hiérarchie de classes héritées et propres à une application sérieuse, non ?

    Merci d'avance.
    "Ah oui ! Juste encore cette toute dernière petite question ..." (Columbo - Peter Falk)

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    1. Il n'y a aucune raison de vouloir tout implémenter dans une même classe. Il vaut mieux au contraire multiplier les classes pour découpler : chaque classe doit être responsable d'une seule "chose". Dans ton cas, un modèle, une vue (le panel) et Energie, une classe utilitaire graphique, probablement réutilisable avec d'autres composants (dans le cas contraire, il n'y aurait pas vraiment de raison d'étendre JScrollPane). Surtout avec des composants Swing : quel raison y-aurait-t-il à avoir un composant qui a le comportement de 2 composants en même temps (qui risquent d'être en conflit). Par ailleurs, je vois beaucoup de gens créer des MyFrame, ou des MyPanel : personnellement, je ne le fait que très rarement. La plupart du temps, tout ce qui est fait dans la classe fillle, c'est de la décoration (donner une taille, un titre, ajouter un ActionListener) : tout ceci peut être fait à l'extérieure. En cas de nécessité de réutilisation, il est préférable de faire un wrapper :
      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
      public Decorator {
       
             /* ... */
       
          public Decorator(Color fg, Color bg) {
                /* ... */
          }
       
          public void decorate(JComponent component) {
                component.setDoreground(fg);
                component.setBackground(bg);
                component.setFont(myFont);
                /* ... */
          }
       
      }
      On peut l'utiliser pour des JButton, des JLabel, etc...

      On peut être utiliser une enum pour enfaire des singletons :

      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
      public enum Decorators {
             RED(Color.RED),
             BLUE(Color.BLUE);
       
             private final Color fg;
             private final Font font;
             private Decorators(Color fg) {
                /* ... */ 
          }
       
          public <T extends Component> T decorate(T component) {
                component.setForeground(fg); 
                component.setFont(font);
                /* ... */
                return component;
          }
       
      }
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      JPanel panel = Decorators.RED(new JPanel());
      JButton button = Decorators.RED(new JButton("Toto"));
      Pour les JPanel, on peut avoir besoin de gérer un JPanel custo réutilisable (comme une combinaison de boutons standards et autres qu'on utilise dans différents dialogues, pour de la pagination (first, previous, next, last et affichage du numéro de page/nombre de page), par exemple, ou un composant complètement Java2D, comme un afficheur de courbes, par exemple),
    2. On ne peut pas faire de héritage multiple certes, mais, aidé éventuellement par des interfaces, on peut encapsuler. C'est le cas principale où ça peut être nécessaire : on a une classe pour gérer un truc, et on veut pouvoir gérer les instances de cette classe par une API qui manipule ses instances par une interface, qui a déjà une implémentation abstraite (voire concrète) fournie par défaut, ou une classe spécifique. Surtout que pour les composants Swing, ils héritent tous d'une classe commune, et peuvent se mettre les uns dans les autres (si avoir un JButton qui fait en même temps champ de saisie est absurde, faire un JButton qui a une fonction spéciale qui permet à l'utilisateur de changer son texte inline, ça peut-être intéressant (voir windowbuilder/palette netbeans).
      Par exemple, on a par exemple une interface ICustomObject, avec une méthode setProperty(String property, String value) et String getProperty(String property), et addPropertyChangeListener(PropertyChangeListener listener) (et removePropertyChangeListener... ), et une classe de bean :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      public class Person { 
         private String name;
         /* ... */
         public void setName(String name) {
             this.name=name;
         }
         public String getNam(e) {
            return name;
         }
      }
      On peut toujours faire :
      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
      public class CustomPerson extends Person implements ICustomObject { // héritage par implémentation d'interface
       
         public static final String PROPERTY_NAME = "NAME";
         /* ... */     
       
         private final PropertyChangeSupport propertyChangeSupport; // apport du comportement de PropertyChangeSupport par encapsulation
       
         public CustomPerson() {
                 propertyChangeSupport = new PropertyChangeSupport(this);
         }
       
         public void setName(String name) {
             String old = getName();
             super.setName(name);
             propertyChangeSupport.firePropetyChange(CustomPerson.NAME, old, name);
         }
       
         public void setProperty(String property, String value) {
              switch( property ) {
                  case CustomPerson.PROPERTY_NAME: 
                       setName(value);
                       break;
                  /* ... */
                  default:
                        throw new IllegalArgumentException("Property not found: " + property);
              }
         }
       
         public String getProperty(String property) {
               final String value;
               switch( property ) {
                  case CustomPerson.PROPERTY_NAME: 
                       value = getName();
                       break;
                  /* ... */
                  default:
                        throw new IllegalArgumentException("Property not found: " + property);
              }
              return value;
         }
       
       
         public void addPropertyListener(PropertyChangeListener listener) {
               propertyChangeSupport.addPropertyListener(listener);
         }
       
         /* ... */
       
      }
      L'utilisation de l'instance propertyChangeSupport permet d'implémenter le comportement commun dont on voudrait hériter dans toutes les classes. Bien sûr, ça oblige à écrire un peu plus de code que de faire simplement extends machin, PropertyEventSupport. Mais au niveau conception et mise au point, ça évite bien des déboires (conflits, effets de bord).

      Si en plus l'instance est injectable (comme pour les TableCellRenderer de JTable) : on peut personnaliser le composant (en faire plusieurs versions différentes, sans écrire du code en double), sans modifier la hiérarchie de classe, et en découplant.
    3. Dans le cas pratique mettons d'une JTable spéciale par son modèle spéciale, on peut définir aussi :
      1. Une interface MonModelSpecial extends TableModel
      2. Une classe MaTableSpeciale :
        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
        public class MaTableSpeciale extends JTable {
         
                /* ... les constructeurs qui vont bien ... */
         
        	@Override
        	protected TableModel createDefaultDataModel() {
        		return new MonModelDeTableParDefaut();
        	}
         
        	@Override
        	public MonModelSpecial getModel() {
        		return (MonModelSpecial)super.getModel();
        	}
         
        	@Override
        	public void setModel(TableModel dataModel) {
        		if ( dataModel instanceof MonModelSpecial ) {
        			setModel((MonModelSpecial)dataModel);
        		}
        		throw new IllegalArgumentException("Le modèle doit implémenter MonModelSpecial");
        	}
        	public void setModel(MonModelSpecial dataModel) { 
        		super.setModel(dataModel);
        	}
         
         
        }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    263
    Détails du profil
    Informations personnelles :
    Âge : 73
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 263
    Points : 121
    Points
    121
    Par défaut
    Merci Joël, depuis tout ce temps.

    Entretemps, j'ai plutôt acquis la conviction que le multiple héritage est nécessaire, pour des héritages de classes personnelles en parallèle avec des héritages de classes de Swing. J'ai l'intention de donner quelques exemples pertinents dans une discussion séparée, dès que j'en trouve le temps.

    Grand merci.
    "Ah oui ! Juste encore cette toute dernière petite question ..." (Columbo - Peter Falk)

Discussions similaires

  1. Accès à une méthode directement dans sa classe
    Par nico78200 dans le forum jQuery
    Réponses: 2
    Dernier message: 03/02/2011, 13h06
  2. Réponses: 8
    Dernier message: 22/03/2010, 16h52
  3. Réponses: 2
    Dernier message: 18/12/2008, 14h15
  4. MDI, accès à une méthode de la fenêtre parente
    Par JuTs dans le forum Windows Forms
    Réponses: 2
    Dernier message: 15/03/2007, 17h17
  5. Réponses: 3
    Dernier message: 15/12/2006, 16h14

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