JTable - DAO - MVC
Objectifs du chapitre
-
Apprendre à utiliser le composant graphique JTable.
-
Concevoir des classes utilitaires pour faciliter l’utilisation d’une JTable.
-
Concevoir une application en respectant le modèle MVC (Modèle - Vue - Contrôleur).
-
Concevoir une couche d’accès aux données de l’application (Data Access Object).
Fonctionnement par défaut d’une JTable
1. Fenêtre affichée
2. Classe Fenetre : utilisation d’une JTable
a. Classe Fenetre
La fenêtre contient trois composants : le panneau de fond, une JTable et un JScrollPane dont le client est la JTable :
public class Fenetre extends JFrame
{
private JPanel panneauFond;
private JTable table;
private JScrollPane defileur;
Le constructeur de la fenêtre reçoit la liste des lignes et des colonnes à afficher :
public Fenetre(String s, Vector<Vector<Object>> listeLignes,
Vector<String> listeColonnes)
{
super(s);
addWindowListener(new EcouteFenetre());
panneauFond = new JPanel();
Le panneau de fond est organisé en BorderLayout :
panneauFond.setLayout(new BorderLayout());
panneauFond.setPreferredSize(new Dimension(500, 150));
Pour l’instanciation de la JTable, on transmet en paramètres la liste des lignes et la liste des colonnes à afficher (le constructeur utilisé ici prend des Vector en paramètres) :
table = new JTable(listeLignes, listeColonnes);
L’instruction suivante permet d’éviter le changement automatique de taille des colonnes quand la fenêtre est redimensionnée. Sans cette instruction, le défilement horizontal n’apparaît pas.
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
defileur = new JScrollPane(table);
defileur.getViewport().setBackground(Color.pink);
panneauFond.add(defileur);
getContentPane().add(panneauFond);
pack();
setVisible(true);
}
}
Le JScrollPane est ajouté au panneau de fond. Comme celui-ci est organisé en BorderLayout, le défileur occupe tout le panneau....
Modèle de table
La construction d’une JTable à partir de deux vecteurs est simple, mais le comportement de la JTable est rudimentaire. D’autres constructeurs de JTable utilisent des modèles de tables.
1. Définition
Un modèle de table est une classe qui implémente l’interface TableModel. Cette interface contient des méthodes qui permettent de définir le comportement de la JTable.
2. Classes et interfaces pour créer un modèle de table
L’interface TableModel déclare toutes les méthodes à surcharger pour écrire un modèle de table.
La classe AbstractTableModel surcharge toutes les méthodes, sauf trois. Ces méthodes sont :
-
getRowCount() : retourne le nombre de lignes de la table.
-
getColumnCount() : retourne le nombre de colonnes de la table.
-
getValueAt(int ligne, int colonne) : retourne la valeur qui s’affiche dans la cellule de la table indiquée par les paramètres ligne et colonne.
La classe DefaultTableModel est celle que nous avons utilisée sans le savoir dans la JTable de la section Fonctionnement par défaut d’une JTable. Elle utilise un Vector de Vector pour stocker les valeurs des cellules.
Pour créer un modèle de table personnalisé (ModeleTable par exemple), il suffit de surcharger ces trois méthodes. Rien n’empêche d’en surcharger d’autres !
3. Modèle de table - Classe Colonne
a. Fenêtre affichée
L’objectif est de mettre au point une application présentant cet affichage :
b. Classe Colonne (package utilitairesMG.divers)
La classe Colonne du package utilitairesMG.divers définit trois propriétés :
-
nom : nom de la colonne
-
longueur : nombre de caractères maximum des données de la colonne
-
type : type de données affichées dans la colonne (exemple : java.lang.String).
La classe Colonne permet de stocker trois informations qui sont utiles pour définir le comportement de la JTable. La longueur permet d’ajuster la dimension de chaque colonne. Le type permet d’adapter la mise en page. Les deux renseignements servent également pour effectuer des contrôles de saisie.
package utilitairesMG.divers;
public class Colonne implements java.io.Serializable
{
private String nom; ...
Modèle de colonnes
Le comportement d’une JTable peut encore s’affiner en utilisant un modèle de colonnes. Des constructeurs de JTable utilisent des modèles de tables ET des modèles de colonnes.
1. Définition
Un modèle de colonnes de table est une classe qui implémente l’interface TableColumnModel.
2. Classes et interfaces pour créer un modèle de colonnes
-
L’interface TableColumnModel déclare toutes les méthodes à surcharger pour écrire un modèle de colonnes de table.
-
La classe DefaultTableColumnModel surcharge toutes les méthodes de l’interface. Elle est donc directement utilisable.
-
La classe TableColumn permet de définir toutes les informations concernant UNE colonne.
Pour créer un modèle de table personnalisé, on peut hériter de DefaultTableColumnModel, et y ajouter autant d’objets TableColumn que de colonnes affichées par la JTable.
3. Modèle de table et modèle de colonnes
a. Fenêtre affichée
L’écran qui doit s’afficher reste le même :
Notez cependant que la largeur des colonnes est adaptée à leur contenu.
b. Classe ModeleColonneTable
La classe ModeleColonneTable hérite de DefaultColumnModel :
public class ModeleColonneTable extends DefaultTableColumnModel {
-
tailleCaractere : c’est le nombre de points maximum occupé par chaque caractère. Par défaut, ce nombre est fixé à 10, mais un des constructeurs reçoit une taille en paramètre.
-
nombreCaracteresMin, nombreCaracteresMax : nombre de caractères minimum et maximum d’une colonne. Ces deux paramètres sont modifiables par les méthodes setNombreCaracteresMin() et setNombreCaracteresMax().
-
listeColonnes : Vector<Colonne> qui contient les informations sur les colonnes.
private int tailleCaractere = 10;
private int nombreCaracteresMin = 8;
private int nombreCaracteresMax = 20;
private Vector<Colonne> listeColonnes;
Les deux constructeurs font appel à la méthode creerColonnes(). Le premier constructeur reçoit le nombre de points occupé par un caractère :
public ModeleColonneTable(Vector<Colonne> listeColonnes,
...
JTable éditable
1. Fenêtre affichée
La JTable est éditable. Elle possède une ligne supplémentaire pour l’ajout d’un contact comme le montre l’écran ci-dessous :
2. Conception des classes ModeleTable et ModeleTableContact
a. Méthodes ajoutées dans la classe ModeleTableContact
-
Pour qu’une cellule de la JTable soit éditable, la méthode isCellEditable() de la classe AbstractTableModel doit être surchargée. Cette méthode retourne un boolean qui vaut true si la cellule de la ligne lig et de la colonne col est éditable, false sinon.
public boolean isCellEditable(int lig, int col)
{
return true;
}
Ainsi surchargée, toutes les cellules de la JTable sont éditables.
-
La méthode getRowCount() de la classe ModeleTable doit être surchargée dans la classe ModeleTableContact pour retourner une ligne supplémentaire destinée à l’insertion :
public int getRowCount()
{
return super.getRowCount() + 1;
}
Par défaut, une JTable n’est pas éditable. La classe ModeleTable respecte cette option. C’est aux classes héritières de modifier cette option si le concepteur le souhaite. Les surcharges des méthodes isCellEditable() et getRowCount() sont donc placées dans ModeleTableContact.
b. Méthodes ajoutées ou modifiées dans ModeleTable
-
La méthode getValueAt() doit retourner des valeurs pour les cellules de la ligne supplémentaire. Il faut donc la redéfinir. Elle retourne null pour les cellules de la ligne vide supplémentaire :
public Object...
Le package utilitairesMG.graphique.table
Les classes ModeleTable et ModeleColonneTable du package utilitairesMG.graphique.table sont enrichies de nombreuses méthodes.
1. ModeleTable
La classe ModeleTable prévoit tous les traitements de mise à jour du vecteur des lignes, en cas de modifications effectuées dans la JTable (ajout, suppression, modification de lignes). Les méthodes suivantes ont été ajoutées :
-
public int supprimer(int[] lignesSelectionnees) permet de supprimer des lignes du vecteur de lignes listeLignes. Les numéros de ces lignes sont contenus dans le tableau lignesSelectionnees.
-
public void restaurer() permet de restaurer les lignes supprimées.
-
public Vector<Vector<Object>> getListeLignesSupprimees() permet d’obtenir la liste des lignes supprimées.
-
public Vector<Character> getMarqueursLignes() permet d’obtenir une liste de caractères correspondant à chaque ligne du vecteur listeLignes.
-
Ce caractère vaut ’M’ si la ligne correspondante a été modifiée.
-
Ce caractère vaut ’I’ si la ligne correspondante a été insérée (ajoutée).
-
Ce caractère vaut ’ ’ (blanc) si la ligne correspondante est inchangée.
2. ModeleColonneTable
La classe ModeleColonneTable utilisée dans les exemples de ce chapitre utilise les options d’édition...
Couche d’accès aux données - DAO (Data Access Object)
1. Application JTable éditable (paragraphe 5)
Le diagramme de séquence de cette application est :
La méthode main() appelle les méthodes creerListeContacts() et creerListeColonnes() et crée la Fenêtre, qui s’affiche.
2. La couche d’accès aux données : la DAO
Dans l’exemple précédent, la classe principale (Controleur) crée la liste des objets Contact et la liste des objets Colonne. Si on initialise ces objets à partir de données provenant d’une source de données (SGBD, réseau…), il faut modifier considérablement la classe principale.
Il est préférable de déléguer la création de ces listes à une autre classe. C’est l’objectif de la couche d’accès aux données.
La classe ContactDAO est chargée de constituer les deux vecteurs nécessaires à l’affichage de la table des contacts. Le diagramme devient :
-
Les flèches pleines sont les appels de méthodes.
-
Les flèches pointillées sont les valeurs de retour des méthodes.
Le code s’obtient par la création d’une nouvelle classe (ContactDAO) et par de judicieux copiés/collés. Mais finissons notre conception en respectant une deuxième contrainte : le modèle...
Modèle MVC (Modèle - Vue - Contrôleur)
1. Définition
Le modèle MVC répartit les classes de l’application en trois catégories :
-
La Vue (View) : c’est ce que l’utilisateur de l’application voit, l’interface visuelle avec laquelle il communique.
-
Le Modèle (Model) : les classes du modèle contiennent la logique de traitement des données de l’application. Les accès aux différentes sources de données (bases de données, flux) se font dans cette partie de l’application.
-
Le Contrôleur (Controller) : c’est la partie de l’application qui sert d’intermédiaire entre la Vue et le Modèle.
Dans le modèle MVC, les objets de la vue n’ont pas de contact avec ceux du modèle. On peut dire que les objets de la Vue et du Modèle ne se connaissent pas. Leurs relations passent obligatoirement par le Contrôleur.
Le schéma suivant illustre les relations entre classes dans le modèle MVC :
2. Application "JTable éditable", version finale
a. L’application "JTable éditable" respecte le MVC
La classe Fenetre est la Vue.
La classe ContactDAO fabrique les données de l’application. C’est le Modèle.
La classe Controleur s’adresse au Modèle et à la Fenêtre. C’est le Contrôleur.
Le diagramme de séquence le montre clairement. Notre application respecte le MVC. Toutes les communications entre la vue et le modèle passent par le contrôleur.
Aucune flèche ne traverse le contrôleur.
b. Arrêt de l’application
L’écouteur d’évènements WindowEvent de la Fenêtre est la classe EcouteFenetre, du package utilitairesMG.graphique :
public Fenetre(String s, Vector<Contact> listeContacts,
Vector<Colonne> listeColonnes)
{
super(s);
addWindowListener(new EcouteFenetre());
. . .
La classe EcouteFenetre surcharge la méthode windowClosing() :
public class EcouteFenetre extends WindowAdapter
{
public void windowClosing(WindowEvent...
Travail pratique : Projet GestionContactLocal
1. Objectif
Améliorer l’interface graphique de l’application "JTable éditable".
-
Modifier la classe Fenetre et adapter la classe Controleur aux nouvelles fonctionnalités.
-
Respecter l’architecture MVC.
2. Sujet
a. Fonctionnement de l’application
Écrire une application permettant d’afficher l’écran ci-dessous :
Quand on choisit Versement ou Secteur : afficher une boîte de message (fenêtre modale) :
Quand on clique sur Contact : afficher une fenêtre interne contenant la liste des contacts :
-
Il est possible d’ajouter et de modifier les contacts.
-
La fenêtre interne CONTACTS possède un menu permettant de supprimer et de restaurer des lignes de la table.
Quand la fenêtre interne CONTACTS est fermée, les modifications s’affichent à la console.
Exemple
b. Conception
À partir du diagramme de séquence de "JTable éditable", écrire le diagramme de séquence de l’application GestionContactLocal.
c. Programmation
Les classes Contact, ContactDAO, ModeleTableContact sont utilisables sans modification.
Facultatif :
-
Il est possible de modifier la méthode isCellEditable() de la classe ModeleTableContact pour limiter la saisie du numéro de contact à la dernière ligne de la table.
-
Remplacer JDesktopPane par JDesktopPaneMG, remplacer JScrollPane par JScrollPaneMG dans la classe Fenetre principale. C’est plus beau !
d. Documentation
Ne pas hésiter à consulter la Javadoc des classes pour l’utilisation des fenêtres internes : JDesktopPane, JInternalFrame, InternalFrameEvent.
JDesktopPane est un panneau spécial destiné à contenir des fenêtres internes (JInternalFrame). On peut l’utiliser comme un JPanel…
L’écriture d’une fenêtre interne (classe héritée de JInternalFrame) ressemble beaucoup à celle d’une fenêtre principale (héritée de JFrame). Il faut gérer des InternalFrameEvent au lieu de gérer des WindowEvent.
La classe utilisée pour afficher une fenêtre modale est JOptionPane.
3. GestionContactLocal : proposition de correction
a. Diagramme de séquence
-
L’utilisateur démarre l’application...