Td corrigé Cahier de TP Java - Examen corrige pdf

Cahier de TP Java - Examen corrige

2 déc. 2002 ... Programmation avancée: TP Java. ... 2.8 Vos notes. 3 TP n°3 : Affiner la définition des classes ? Constructeurs et visibilités. 3.1 Constructeurs.




part of the document



DESS IGSI
Java
À : DESS IGSI
De : Laurent Perrussel (Laurent.Perrussel@univ-tlse1.fr)
Date :  DATE \@ "dd/MM/yy" \* MERGEFORMAT 02/12/02

Introduction
L’objectif de ce mémo est de présenter le langage Java. La programmation Java s’effectuera à l’aide de l’outil de développement JBuilder. Chaque chapitre fait l’objet d’une séance de travaux pratiques. Les travaux pratiques complètent le cours de programmation : les concepts de programmation (structures de données et de contrôles) sont supposés connus.
Le mémo est organisé en chapitres : chaque chapitre traite d’un thème et fait l’objet d’une mise en pratique en T.P. Les thèmes ne sont pas indépendants : ils supposent une certaine continuité dans l’apprentissage.


TABLES DES MATIERES


 TOC \o "1-4" Introduction  PAGEREF _Toc464381576 \h 1
1 TP n° 1 : Concepts de base  PAGEREF _Toc464381577 \h 6
1.1 Programmation orienté-objet  PAGEREF _Toc464381578 \h 6
1.2 Identifier et créer un objet  PAGEREF _Toc464381579 \h 6
1.3 Les données  PAGEREF _Toc464381580 \h 7
1.3.1 Données primitives  PAGEREF _Toc464381581 \h 8
1.3.2 Les tableaux  PAGEREF _Toc464381582 \h 8
1.3.3 Les chaînes de caractères  PAGEREF _Toc464381583 \h 9
1.3.4 Accès aux données  PAGEREF _Toc464381584 \h 9
1.4 Les classes  PAGEREF _Toc464381585 \h 7
1.4.1 Description type d’une classe  PAGEREF _Toc464381586 \h 7
1.5 JBuilder 3  PAGEREF _Toc464381587 \h 10
1.6 Exercice  PAGEREF _Toc464381588 \h 10
1.6.1 A faire  PAGEREF _Toc464381589 \h 14
1.7 Ce qu’il faut retenir  PAGEREF _Toc464381590 \h 14
1.8 Vos notes  PAGEREF _Toc464381591 \h 14
2 TP n° 2 : définir des méthodes  PAGEREF _Toc464381592 \h 15
2.1 Squelette d’une méthode  PAGEREF _Toc464381593 \h 15
2.2 Valeur de retour  PAGEREF _Toc464381594 \h 16
2.3 Appeler la méthode d’un objet  PAGEREF _Toc464381595 \h 16
2.4 La liste des arguments  PAGEREF _Toc464381596 \h 16
2.5 Les instructions de traitements  PAGEREF _Toc464381597 \h 17
2.5.1 Opérateurs mathématiques  PAGEREF _Toc464381598 \h 17
2.5.2 Instructions de contrôle  PAGEREF _Toc464381599 \h 17
2.5.2.1 Instruction conditionnelle  PAGEREF _Toc464381600 \h 18
2.5.2.2 Les instructions d’itérations  PAGEREF _Toc464381601 \h 18
2.6 Exercice  PAGEREF _Toc464381602 \h 19
2.6.1 A faire  PAGEREF _Toc464381603 \h 20
2.7 Ce qu’il faut retenir  PAGEREF _Toc464381604 \h 20
2.8 Vos notes  PAGEREF _Toc464381605 \h 20
3 TP n°3 : Affiner la définition des classes – Constructeurs et visibilités  PAGEREF _Toc464381606 \h 21
3.1 Constructeurs  PAGEREF _Toc464381607 \h 21
3.2 Visibilité des classes et de leur contenu  PAGEREF _Toc464381608 \h 22
3.2.1 Visibilité de la classe  PAGEREF _Toc464381609 \h 22
3.2.2 Visibilité des données et méthodes  PAGEREF _Toc464381610 \h 22
3.3 Exercice  PAGEREF _Toc464381611 \h 23
3.3.1 A faire  PAGEREF _Toc464381612 \h 24
3.4 Ce qu’il faut retenir  PAGEREF _Toc464381613 \h 24
3.5 Vos notes  PAGEREF _Toc464381614 \h 24
4 TP 4 : Création d’un dialogue  PAGEREF _Toc464381615 \h 25
4.1 La construction d’une interface  PAGEREF _Toc464381616 \h 25
4.2 Les composants  PAGEREF _Toc464381617 \h 25
4.2.1 Chargement des bibliothèques  PAGEREF _Toc464381618 \h 25
4.2.2 Type de composants  PAGEREF _Toc464381619 \h 25
4.2.2.1 Les conteneurs  PAGEREF _Toc464381620 \h 25
4.2.2.2 Les contrôles  PAGEREF _Toc464381621 \h 26
4.3 Description des contrôles  PAGEREF _Toc464381622 \h 27
4.3.1 Les boutons  PAGEREF _Toc464381623 \h 27
4.3.1.1 Constructeurs  PAGEREF _Toc464381624 \h 27
4.3.1.2 Quelques méthodes  PAGEREF _Toc464381625 \h 27
4.3.2 Les boites à cocher  PAGEREF _Toc464381626 \h 28
4.3.2.1 Constructeurs  PAGEREF _Toc464381627 \h 28
4.3.2.2 Quelques méthodes  PAGEREF _Toc464381628 \h 28
4.3.3 Les listes de choix  PAGEREF _Toc464381629 \h 28
4.3.3.1 Constructeurs  PAGEREF _Toc464381630 \h 28
4.3.3.2 Quelques méthodes  PAGEREF _Toc464381631 \h 29
4.3.4 Les listes  PAGEREF _Toc464381632 \h 29
4.3.4.1 Constructeurs  PAGEREF _Toc464381633 \h 29
4.3.4.2 Quelques méthodes  PAGEREF _Toc464381634 \h 30
4.3.5 Les zones de saisie  PAGEREF _Toc464381635 \h 30
4.3.5.1 Constructeurs  PAGEREF _Toc464381636 \h 30
4.3.5.2 Quelques méthodes  PAGEREF _Toc464381637 \h 31
4.4 Disposer les contrôles  PAGEREF _Toc464381638 \h 31
4.4.1 FlowLayout  PAGEREF _Toc464381639 \h 31
4.4.2 BorderLayout  PAGEREF _Toc464381640 \h 32
4.4.3 GridLayout  PAGEREF _Toc464381641 \h 32
4.4.4 GridBagLayout  PAGEREF _Toc464381642 \h 32
4.5 Exercice  PAGEREF _Toc464381643 \h 32
4.6 A faire  PAGEREF _Toc464381644 \h 35
4.7 Ce qu’il faut retenir  PAGEREF _Toc464381645 \h 35
4.8 Vos notes  PAGEREF _Toc464381646 \h 35
5 TP n°5 : Gérer des événements  PAGEREF _Toc464381647 \h 36
5.1 La gestion des événements  PAGEREF _Toc464381648 \h 36
5.1.1 Le contrôleur de la fenêtre  PAGEREF _Toc464381649 \h 36
5.1.2 Le contrôleur des contrôles  PAGEREF _Toc464381650 \h 36
5.2 question de méthode  PAGEREF _Toc464381651 \h 37
5.3 Exercice  PAGEREF _Toc464381652 \h 37
5.4 A faire  PAGEREF _Toc464381653 \h 38
5.5 Ce qu’il faut retenir  PAGEREF _Toc464381654 \h 38
5.6 Vos notes  PAGEREF _Toc464381655 \h 39
6 TP n°6 : Héritage et interface  PAGEREF _Toc464381656 \h 40
6.1 Héritage  PAGEREF _Toc464381657 \h 40
6.1.1 Une seconde visite du parking  PAGEREF _Toc464381658 \h 40
6.2 Classes abstraites  PAGEREF _Toc464381659 \h 42
6.3 Interface  PAGEREF _Toc464381660 \h 42
6.4 Exercice  PAGEREF _Toc464381661 \h 43
6.5 Ce qu’il faut retenir  PAGEREF _Toc464381662 \h 43
Vos notes  PAGEREF _Toc464381663 \h 43
7 TP n° 7 : Vecteurs et listes  PAGEREF _Toc464381664 \h 44
7.1 Description d’un vecteur  PAGEREF _Toc464381665 \h 44
7.1.1 Création d’un vecteur  PAGEREF _Toc464381666 \h 44
7.1.2 Quelques méthodes  PAGEREF _Toc464381667 \h 44
7.2 Concordance de types et transtypage  PAGEREF _Toc464381668 \h 45
7.3 Exercice  PAGEREF _Toc464381669 \h 45
7.4 Ce qu’il faut retenir  PAGEREF _Toc464381670 \h 46
Vos notes  PAGEREF _Toc464381671 \h 46
8 TP n°8 : L’architecture modèle – Vue – Contrôleur  PAGEREF _Toc464381672 \h 47
8.1 Fonctionnement  PAGEREF _Toc464381673 \h 47
8.2 Présenter des données dans des tables  PAGEREF _Toc464381674 \h 48
8.3 Description des composants Listes et Tables  PAGEREF _Toc464381675 \h 50
8.3.1 Les Listes  PAGEREF _Toc464381676 \h 50
8.3.1.1 Constructeurs  PAGEREF _Toc464381677 \h 50
8.3.1.2 Quelques méthodes  PAGEREF _Toc464381678 \h 50
8.3.2 Les modèles de données « Liste »  PAGEREF _Toc464381679 \h 50
8.3.2.1 L’interface ListModel  PAGEREF _Toc464381680 \h 50
8.3.2.2 La classe abstraite AbstractListModel et la classe DefaultListModel  PAGEREF _Toc464381681 \h 50
8.3.3 Les Tables  PAGEREF _Toc464381682 \h 51
8.3.3.1 Constructeurs  PAGEREF _Toc464381683 \h 51
8.3.3.2 Quelques méthodes  PAGEREF _Toc464381684 \h 52
8.3.4 Les modèles de données « Table »  PAGEREF _Toc464381685 \h 52
8.3.4.1 L’interface TableModel  PAGEREF _Toc464381686 \h 52
8.3.4.2 La classe abstraite AbstractTableModel et la classe DefaultTableModel  PAGEREF _Toc464381687 \h 53
8.4 Exercice  PAGEREF _Toc464381688 \h 54
8.4.1 A faire  PAGEREF _Toc464381689 \h 54
8.5 Ce qu’il faut retenir  PAGEREF _Toc464381690 \h 55
8.6 Vos Notes  PAGEREF _Toc464381691 \h 55
9 TP n°9 : Hashtables  PAGEREF _Toc464381692 \h 56
9.1 Description de la classe HashTable  PAGEREF _Toc464381693 \h 56
9.1.1 Constructeurs  PAGEREF _Toc464381694 \h 56
9.1.2 Quelques méthodes  PAGEREF _Toc464381695 \h 56
9.2 Description de l’interface Enumeration  PAGEREF _Toc464381696 \h 57
9.2.1 Les méthodes  PAGEREF _Toc464381697 \h 58
9.3 Exercice  PAGEREF _Toc464381698 \h 58
9.4 A faire  PAGEREF _Toc464381699 \h 58
9.5 Ce qu’il faut retenir  PAGEREF _Toc464381700 \h 58
9.6 Vos Notes  PAGEREF _Toc464381701 \h 59
10 TP n° 10 : Arbres, récursivité  PAGEREF _Toc464381702 \h 60
10.1 Spécification d’un arbre  PAGEREF _Toc464381703 \h 61
10.2 Exercice  PAGEREF _Toc464381704 \h 62
10.2.1 A faire  PAGEREF _Toc464381705 \h 63
10.3 Ce qu’il faut retenir  PAGEREF _Toc464381706 \h 63
Vos Notes  PAGEREF _Toc464381707 \h 63
A. Quelques Références  PAGEREF _Toc464381708 \h 64


TP n° 1 : Concepts de base
Programmation orienté-objet
Java est un langage orienté objet. Un objet est, de manière intuitive, un ensemble de données et un ensemble de fonctions/procédures s’appliquant sur ces données.
Exemple : une calculatrice élémentaire. Les deux nombres représentent les données et les opérations de base comme la multiplication ou la soustraction sont les fonctions.

Les fonctions/procédures sont appelées des méthodes. Les méthodes décrivent le comportement de l’objet.
Un programme en Java est un ensemble d’objets exécutant des méthodes ou demandant l’exécution de méthodes par les autres objets en leur envoyant des messages.
L’ensemble des objets de même type forme une classe d’objets.
Identifier et créer un objet
Tous les objets manipulés en Java doivent être identifiés. Cette identification permet de désigner et donc de manipuler l’objet : modifier ses données ou demander l’exécution de méthodes. Une identification s’effectue en mentionnant deux caractéristiques : quel est l’identifiant de l’objet et sa classe :
ClasseObjet NomObjet ;
Exemple : Pour pouvoir manipuler la calculatrice, nous déclarons un identifiant d’objet : c. Cet identifiant permettra de désigner des objets de la classe des calculatrices.
Calculatrice c ;
La ligne précédente est une déclaration. Cette définition ne permet pas d’avoir l’objet identifié par c à notre disposition, c’est-à-dire qu’on ne peut pas, par exemple, demander à la calculatrice ayant l’identifiant c d’effectuer une opération arithmétique. Il faut pour cela créer l’objet. La création s’effectue à l’aide de l’opérateur new. Cette instruction fait partie du jeu d’instructions de base du langage. Une création d’objet suit la syntaxe suivante :
NomObjet = new ClasseObjet(…) ;
Exemple : Pour pouvoir manipuler la calculatrice, nous créons un objet de la classe Calculatrice. L’objet est désigné à l’aide de l’identifiant c. Autrement dit, c référence un objet de la classe des calculatrices
c = new Calculatrice() ;
Les données
Les données manipulées dans un objet décrivent l’état d’un objet. Ainsi dans un objet de la classe des thermostats, la température qui est une valeur numérique représente la température désirée. Le comportement est lui limiter à deux fonctionnalités : monter la température et descendre la température.
Maintenant considérons un client et ses commandes :

 SHAPE \* MERGEFORMAT 
Si nous considérons maintenant des objets de ces classes :







Un client à des caractéristiques de base (nom, ville,…) qui sont du texte et des caractéristiques plus complexes : la liste des commandes. Cette liste est en fait un objet composé d’un ensemble de commandes. De fait, nous voyons que chaque commande est-elle même un objet et, que chaque ligne de commande contient deux informations : l’article et la quantité commandé. L’article est un objet et la quantité est une valeur numérique.
Les classes
Une classe est décrite dans un document portant l’extension .java. Ce document ne doit contenir qu’une seule classe et le nom du document est le même nom que celui de la classe.
Exemple : Nom du fichier associé à la classe LignesDeCdes : LignesDeCdes.java
Description type d’une classe
Une classe est décrite à l’aide du mot-clef class :
class maClasse {
…
description de la classe (données + méthodes)
…
}
La description proprement dite, appelée corps de la classe, est spécifiée entre accolades.
Exemple : description de la classe lignes de commandes. Une ligne de commande contient un article et une quantité commandée. L’article s’appelle article_commande et est un objet de la classe Article. La quantité est une valeur entière.
class LignesDeCdes  {
Article article_commande ; int qte_cdee ;
}
Dans un objet il ne peut y avoir que deux types d’attributs :
des objets,
des valeurs primitives (qui ne sont pas des objets).


Données primitives
Les principaux types de données primitives sont représentés dans le tableau ci-après.
NomDescriptionbooleanValeur logique (true, false)charCaractèreintEntierlongEntier longfloatRéeldoubleRéel long
La déclaration de variables primitives nécessite uniquement une déclaration.
Exemple : Pour pouvoir manipuler une quantité
int qte ;
Les tableaux
Les tableaux permettent de manipuler des listes d’objets ou de données primitives. Un tableau qu’il soit un tableau d’objets ou un tableau de valeurs primitives est lui-même un objet.
La déclaration et la manipulation des tableaux s’effectuent à l’aide des crochets []. Le premier indice du tableau est toujours 0. Le nom du tableau indicé permet d’accéder à un item du tableau.
Exemple : déclaration d’un tableau tableauValeurs de valeurs entières. Ce tableau contient dix cases.
int[] tableauValeurs ;
Les tableaux étant des objets, il convient donc de créer le tableau proprement dit après l’avoir identifié. Cette opération est effectuée à l’aide du mot clef new.
tableauValeurs = new int[10] ;
Accès au cinquième élément du tableau et initialisation de sa valeur (à 9) :
tableauValeurs[4] = 9 ;
Plus généralement, il est tout à fait possible d’avoir un tableau d’objets. Dans ce cas, nous avons la même procédure en deux temps : déclaration puis création du tableau :
LignesDeCdes[] les_lignes ; … les_lignes = new LignesDeCdes[10] ;
Le résultat produit par cette dernière instruction a été la déclaration d’un tableau de 10 identifiants d’objets LignesDeCdes. Il faut donc ensuite créer chaque élément du tableau individuellement. Ainsi, si nous considérons la création de la troisième ligne de commande :
les_lignes[2] = new LignesDeCdes() ;
Les chaînes de caractères
Pour manipuler les chaînes de caractères, Java propose une classe prédéfinie : String. Pour créer une chaîne, plusieurs commandes sont possibles : création d’un objet ou affectation directe.
String chaine1, chaine2; … chaine1 = new String("toto") ; chaine2 = "titi" ;
Accès aux données
Les fonctions et procédures vont manipuler les données. L’accès aux données d’un objet doit mentionner deux éléments : quel est l’objet accédé et quelle information de cet objet souhaitons nous consulter et/ou modifier. En Java, nous « connectons » ces deux informations à l’aide d’un point : NomObjet.NomDonnee
Exemple : modifier la valeur du premier nombre, nommé Nombre1 de notre calculatrice c, en initialisant la valeur à 10
c.Nombre1 = 10 ;
Traduction Java de l’exemple
Nous nous limitons ici à la définition des attributs. Lorsque les attributs sont des objets, nous n’avons donc que la spécification de l’identifiant.
Notons que chaque classe est contenue dans un fichier différent :
Client.java, Commande.java, LigneCommande.java, Article.java.
class Client  {
String nom, ville, telephone ; Commande[] commandes ;
}
class Commande  {
String noCde  ; LigneDeCde[] lesLignes;
}class LigneCommande  {
Article articleCommande  ; int qte;
}
class Article  {
…;
}JBuilder 3
JBuilder est un outil d’aide au développement : aide à la définition d’interfaces, documentation, déboguage… La réalisation d’un programme s’effectue dans un projet : un projet regroupe un ensemble de classes et de fichiers de documentation.
Les classes sont des fichiers textes portant l’extension .java et les documents sont des pages Web portant l’extension .html.
Exercice
L’objectif est de créer une première classe élémentaire pour découvrir l’environnement JBuilder 3.
Cette classe a pour objet de décrire des bureaux. Un bureau est défini par un numéro de bureau et un occupant.
La première étape est de créer un projet : l’appel de l’expert se fait avec la commande Fichier/Nouveau Projet. L’expert projet permet de donner une première description du projet.

Cette description est utilisée par JBuilder pour créer le premier document décrivant votre projet. Ce document est présenté dans l’outil de navigation du projet. Le navigateur présente dans la partie gauche deux zones : la zone supérieure répertorie l’ensemble des composants du projet. La partie inférieure gauche indique les caractéristiques du composant sélectionné. La partie droite affiche le document.



La seconde étape consiste à créer notre première classe. La création d’une classe s’effectue à l’aide de la commande Fichier/Nouveau…, commande présentant l’invite suivant :

Après avoir choisi le composant Classe, spécifier la description de votre classe : indiquer Bureau comme nom de classe et cochez la case public.


La description de votre classe est la suivante :
class Bureau {
}
Compléter votre classe en précisant les données manipulées :
String nom_bureau; String occupant;
L’étape suivante consiste à créer deux bureaux : bureau1 et bureau2 et à garnir les informations de ces bureaux.
Pour que le programme puisse fonctionner, nous devons indiquer un point de démarrage. Au démarrage, le programme créera les deux bureaux. Dans une classe le point de démarrage est spécifier à l’aide d’une fonction particulière appelée main. La déclaration complète de cette fonction est :
public static void main(String[] args)
La description de notre classe est donc maintenant
class Bureau {
…
public static void main(String[] args) {
Bureau bureau1 ;
bureau1 = new Bureau() ; bureau1.nom_bureau = "ME403" ; …
}
}
Le programme écrit il faut compiler et exécuter le programme :
La compilation du programme s’effectue à l’aide de la commande Projet/Make pour le projet.
L’exécution du programme s’effectue à l’aide de la commande Exécuter/Exécuter "bureau". L’exécution ouvre une fenêtre console et le programme s’exécute dans cette fenêtre. Si la fenêtre console se referme automatiquement, bloquez son affichage en modifiant les paramètres d’exécution avec le menu Exécuter/Paramètres… et inhiber la fermeture de la fenêtre :



La compilation et l’exécution ne produisent aucun résultat. Il faut demander à ce que le programme affiche des données. L’instruction d’affichage est la suivante :
System.out.println(valeurAAfficher) ;
Si vous demander l’affichage d’un des numéros de bureau, vous obtenez :
AppAccelerator(tm) 1.2.010 for Java (JDK 1.2), x86 version.
Copyright (c) 1997-1999 Inprise Corporation. All Rights Reserved.
ME403

Tapez Ctrl+C pour terminer l'application…


A faire
Créer une seconde classe dans votre projet décrivant les occupants des bureaux. Les occupants ont un numéro de badge (valeur entière), un nom et un prénom.
Modifiez la classe Bureau afin que l’occupant soit un objet de la classe créée précédemment. Demandez la création de deux bureaux et affichez leurs contenus.
Modifiez la classe Bureau afin de pouvoir représenter le fait qu’il y ait deux personnes occupant un bureau. Prenez cette modification en compte en utilisant un tableau à deux positions. Demandez la création d’un bureau, initialisez les valeurs et affichez les valeurs.
Ce qu’il faut retenir
Comment définir une classe ;
Comment identifier et créer des objets ;
Les types de données primitives ;
La méthode main ;
Ecrire, compiler et exécuter un programme avec JBuilder.

Vos notes


TP n° 2 : définir des méthodes
Dans le TP précédent, nous nous sommes focalisés sur la description des données. Nous abordons dans ce TP la description du comportement des données. Le comportement des données est décrit à l’aide de méthodes. Les méthodes sont des fonctions ou procédures. Les méthodes décrivent des traitements.
Squelette d’une méthode
La description d’une méthode contient les éléments suivants : son nom, les arguments, la valeur de retour et la description du traitement. Autrement dit :
TypeDonneeRetour NomMethode(ListeDesArguments) {
Description de la méthode
}
De fait, la description d’une classe devient : description des données et description des méthodes.
class NomClasse {
/* Description des données */
typeDonnee1 nomDonnee1 ; typeDonnee2 nomDonnee2 ; …
/* Description des méthodes */
typeRetour1 methode1(…) { … }
typeRetour2 methode2(…) { … }
…
}

Exemple : reprenons l’exemple du TP précédent : une calculatrice élémentaire. Nous ajoutons une méthode additionner à la classe. La classe contient deux nombres entiers nb1 et nb2 :
class Calculatrice {
/* Description des données */
int nb1, nb2 ;
/* Description des méthodes */
…
}
Décrivons tout d’abord l’entête : la valeur retournée est un nombre entier, le nom de la méthode est additionner et la liste des arguments est vide car les deux nombres à additionner sont déjà dans la calculatrice (nb1 et nb2). Le corps de la méthode doit additionner ces deux valeurs et indiquer que le total doit être la valeur à retourner. Autrement dit :
int additionner() {
int total ; // déclaration d’une variable
total = nb1 + nb2 ; // traitement
return total ; // retour de la méthode
}
Nous voyons sur l’exemple que nous pouvons déclarer des variables ou plus généralement des données dans le corps d’une méthode. Le corps d’une méthode contient trois éléments principaux :
Instructions de déclarations de données + instructions de traitements + instructions de retour
Notons aussi dans l’exemple que la valeur retournée est bien une valeur entière (cf. déclaration de total).
Valeur de retour
L’instruction de retour, qui « normalement » conclut le corps de la méthode est return suivi de l’objet retourné. Le type de l’objet doit être le même que celui mentionné dans l’entête de la méthode. Notons qu’une méthode peut aussi bien retourner un objet, qu’une valeur primitive.
Lorsqu’une méthode ne retourne aucune valeur celle-ci est de type void. L’instruction return qui apparaît dans la liste des instructions ne mentionne pas dans ce cas d’objet.
Appeler la méthode d’un objet
Les méthodes sont dans des objets. L’appel d’une méthode doit donc mentionner l’objet associé. Autrement dit, il faut mentionner : le nom de l’objet + le nom de la méthode. L’association entre ces deux éléments se fait avec un point :
variableRecuperation = nomObjet.nomMethode(listeDesArguments) ;
Il est clair que la variable récupérant la valeur renvoyée par la méthode doit être compatible avec la valeur retournée par la méthode.
Lorsque la méthode est de type void, il ne faut pas mentionner de variable de récupération :
nomObjet.nomMethode(listeDesArguments) ;
La liste des arguments
La liste des arguments spécifie les informations additionnelles nécessaires au traitement effectué par la méthode. Additionnelles car elles ne sont pas présentes dans les données internes à la classe. La liste des arguments est une liste d’objets et/ou de données de base. Chaque argument de la liste est séparé par une virgule, et la description de l’argument se fait en deux temps : type de la variable et nom de la variable. Autrement dit :
TypeRetour nomMethode(typeVar1 nomVar1, typeVar2 nomVar2,…) {…} 
Exemple : supposons que nous ajoutions une méthode pour initialiser les deux nombres de notre calculatrice. Cette méthode reçoit en paramètre deux valeurs entières et ne retourne aucune valeur.
void initNombres(int valeur1, int valeur2) {
nb1 = valeur1 ; // traitement nb2 = valeur2 ;
return ; // retour de la méthode
}
L’appel se fera comme suit, si nous supposons disposer d’un objet calculatrice nommé c :
c.initNombres(3,7) ;
i = 10 ; c.initNombres(i,8) ;
Les instructions de traitements
Le dernier point concerne le jeu d’instructions proprement dit. Nous donnons ici quelques instructions types. Pour une liste exhaustive, se référer au manuel Java en ligne.
Opérateurs mathématiques
Les opérateurs mathématiques se subdivisent en trois catégories : les opérateurs arithmétiques, les opérateurs de comparaison, les opérateurs logiques.
Tableau  SEQ Tableau \* ARABIC 1 : opérateurs arithmétiques
SymboleDescription+Addition-Soustraction*Multiplication/Division%Modulo =Assignation++Opérateur unaire d’incrémentation.--Opérateur unaire de décrémentation.
Tableau  SEQ Tableau \* ARABIC 2 : opérateurs de comparaison
SymboleDescription>Supérieur valeur2) rst =  1; else rst = -1 ;
return rst;
Les instructions d’itérations
Les instructions d’itérations sont au nombre de trois : le TANTQUE – FIN TANTQUE, le REPETER – JUSQUA et la boucle POUR. Les deux premières boucles sont représentées ci-après. Notons que le REPETER – JUSQUA (boucle de droite) n’a pas de représentation directe. En effet la condition est une condition d’arrêt alors que la traduction en Java par un do… while exige une condition de poursuite.
while(condition) instruction do instruction while(condition) ;
La boucle POUR est représentée par l’instruction for. L’instruction exige trois arguments : une instruction d’initialisation, une expression logique de poursuite et une instruction à exécuter à chaque boucle.
for(initialisation ; condition de poursuite ; pas) instruction 
Exemple : initialiser un tableau à 0. Supposons une classe Tableau contenant comme attribut un tableau de valeurs entières :
class Tableau {
static int DIMENSIONTABLEAU = 10;
int[] tableau;
}
La méthode initialise crée le tableau et initialise toutes les valeurs à zéro.
class Tableau {
static int DIMENSIONTABLEAU = 10;
int[] tableau;
void initialiser() {
int i ;
tableau = new int[DIMENSIONTABLEAU]; for(i = 0 ; i < DIMENSIONTABLEAU ; i++) tableau[i]=0 ;
}
}
Exercice
L’objectif de ce programme est de pouvoir calculer des résultats électoraux. Il s’agit de pouvoir construire des méthodes simples et de les appeler.
IL s’agit de décrire des élections locales. Dans une élection, il y a plusieurs candidats. Chaque candidat a un nom et un prénom. Nous supposons qu’à chaque élection il y a trois candidats. Dans une élection, chaque candidat obtient des suffrages (nombres de voix). Autrement dit, les données vont être structurées comme suit :

Implémenter les classes en Java.
Ajouter une méthode main à votre classe Election et créer des objets des différentes classes.
Implémenter les fonctionnalités ci-après. Pour chaque service, définissez tout d’abord à quelle classe celui-ci doit être attaché. Ensuite, déterminez la spécification de vos méthodes : valeur retournée et paramètres attendus :
Un service calculant la proportion de voix obtenues par un candidat.
Un service déterminant si un candidat est éliminé (nb. voix < 25%), maintenu au second tour (25% < nb. voix < 50%) ou élu (> 50%).

Prenez soin de créer un nouveau projet pour votre travail. Vous supposerez que les données sont chargées dans la fonction main. La fonction main appellera aussi les méthodes et affichera les résultats.
A faire
Modifier le programme pour qu’il puisse prendre en compte plusieurs bureaux de vote. La définition de classe(s) supplémentaire(s) est nécessaire.
Définir une méthode retournant un tableau contenant le(s) nom(s) des candidats admis au second tour ou du candidat élu.
Ce qu’il faut retenir
Description d’une méthode (Type de donnée en retour, arguments,…) ;
Appel de méthodes ;
Instructions de traitement : les instructions, bloc d’instructions, les boucles les conditionnels.

Vos notes

TP n°3 : Affiner la définition des classes – Constructeurs et visibilités
L’objectif du TP est de détailler le processus de création des classes : travail d’initialisation lors de la création d’objets et contrôle des accès aux données internes d’une classe.
Constructeurs
Il est fréquent lors de la création d’objets qu’une étape d’initialisation soit nécessaire. Il s’agit par exemple d’initialiser un tableau à zéro, ou bien effectuer des créations préalables. Ces instructions sont à effectuer à la création de l’objet. Il faut donc préciser dans le programme qu’à l’exécution de l’instruction new Classe(), il faut exécuter un bloc d’instructions additionnel. Ce mécanisme peut être garanti par l’utilisation de constructeurs. Un constructeur est une méthode spéciale où sont spécifiées les instructions d’initialisation. Un constructeur est facilement identifiable car il porte le même nom que la classe.
La présence d’un constructeur n’est pas obligatoire. Il y a toujours une procédure de création implicite par défaut définie dans Java.
Exemple : constructeur initialisant directement les valeurs d’un occupant de bureau. Un occupant est décrit par un nom et un prénom ainsi qu’un numéro de badge.
class Occupant {
String nom, prenom ; int num_badge ;
Occupant(String nom, String prenom, int badge) {
this.nom = nom ; // description du constructeur this.prenom = prenom ; this.num_badge = badge ; }
}
Notons qu’un constructeur ne retourne jamais de valeur. Autrement dit un constructeur n’est pas une méthode. Les instructions sont exécutées lors de la création de l’objet. A l’utilisation de l’instruction, il doit y avoir correspondance entre les types de données spécifiés dans le constructeur et les arguments envoyés :
o = new Occupant("Sartre","Raymond",12) ;
Le constructeur permet d’unifier la création et l’initialisation. Si l’objet doit être initialisé différemment en fonction des paramètres reçus, il faut alors définir plusieurs constructeurs.
Exemple : dans la classe Occupant, nous ajoutons un second constructeur. Ce constructeur permet de créer un occupant sans initialiser les valeurs.
class Occupant {
String nom, prenom ; int num_badge ;
Occupant() {
nom = "" ; // description du premier constructeur prenom = ""; num_badge = 0 ;
}
Occupant(String nom, String prenom, int badge) {
this.nom = nom ; // description du second constructeur this.prenom = prenom ; num_badge = badge ;
}
}
Visibilité des classes et de leur contenu 
Les informations contenues dans une classe sont accessibles, par défaut, depuis les autres classes. Cette visibilité n’est que partiellement nécessaire, certaines données sont des informations temporaires ou de travail et n’exigent pas d’être visibles depuis l’extérieur, c’est-à-dire des autres classes.
Visibilité de la classe 
Afin que les classes soient accessibles elles doivent être déclarées publiques (public). Les classes qui ne sont pas publiques sont accessibles uniquement par les classes contenues dans le paquetage d’origine de cette classe.
Visibilité des données et méthodes
Les droits d’accès aux données et méthodes d’un objet sont de trois niveaux : public, privé et protégé.
public : les méthodes et données mentionnées comme publiques sont visibles depuis n’importe quel autre objet (i.e. les données étant accessibles, elles sont donc modifiables).
private : les méthodes et données privées sont inaccessibles depuis les autres classes. Le seul moyen d’accès est depuis la classe elle-même.
protected : les données sont visibles et modifiables par les sous-classes de la classe. Elles sont aussi accessibles depuis les classes du même paquetage.
Une règle, qui n’est pas systématique, veut que les données soient privées. Ceci permet de les protéger d’accès malencontreux mais garantit une indépendance des services : les classes sont utilisées conformément aux services annoncés et les services utilisent les données qu’ils souhaitent (autrement dit peu importe la manière dont le service est rendue).
L’accès aux données sera défini plus finement en spécifiant des méthodes permettant de connaître une valeur (get) et des méthodes permettant de modifier une valeur (set).
Exemple : La classe Occupant est spécifiée publique et les données privées. Nous donnons une méthode d’accès aux noms et de modification du prénom qui sont publiques. Les constructeurs sont spécifiés en tant que publics.
public class Occupant {
private String nom, prenom ; private int num_badge ;
public Occupant() {
nom = "" ; // description du premier constructeur prenom = ""; num_badge = 0 ;
}
public Occupant(String nom, String prenom, int badge) {
this.nom = nom ; // description du second constructeur this.prenom = prenom ; num_badge = badge ;
}
public String getNom() {
return nom ;
}
public void setPrenom(String p) {
prenom = p ; return ; }
}
Exercice
L’objectif du programme est de pouvoir ranger des véhicules dans un parking. Un parking est un ensemble de places et à chaque place il peut y avoir un véhicule :

1111 AA 312222 BB 324444 DD 33Vide3333 EE 34
Un véhicule est identifié par son numéro et est localisé par son numéro de place. Un véhicule est rangé à la première place libre trouvée.
La classe parking doit rendre les services suivants :
Ranger une voiture,
Enlever une voiture,
Indiquer le nombre de places libres.

Faire le diagramme de classes. Spécifiez les attributs et méthodes. Précisez la visibilité des attributs et méthodes.
Définissez le constructeur de chaque classe.
Prenez soin de créer un nouveau projet pour votre travail. En plus de vos classes, créez une classe Programme. La classe Programme contiendra uniquement une fonction main qui créera un parking et chargera des valeurs dans celui-ci (c.à.d. ranger des voitures). La fonction main appellera aussi les méthodes et affichera les résultats. Cette distinction permettra de réutiliser la classe Parking ultérieurement.
A faire
Réutiliser votre classe pour définir les parkings de bateau : dans un bateau (un ferry) les véhicules sont rangés les uns derrière les autres. L’entrée des véhicules s’effectue par une porte et la sortie s’effectue soit par la même porte ou soit par la porte opposée. Dans le petit parking de bateau ci-après la porte avant est à gauche :
3333 EE 342222 BB 324444 DD 331111 AA 31Vide 
Vous détaillerez les deux cas suivants (les classes représentant les parkings de ferry doivent rendre les mêmes services que pour les parkings simples) :
Entrée par la porte arrière et sortie par la porte avant. (cf. illustration ci-dessus). Le dernier véhicule entré est le véhicule 1111 AA 31 et le seul véhicule pouvant sortir est celui près de la porte, à savoir le 3333 EE 34.
Entrée par la porte avant et sortie par la porte avant. Le dernier véhicule entré est le véhicule 1111 AA 31. Ce véhicule est le seul pouvant sortir car il est le plus près de la porte (avant).
2. Grand parking : un grand parking est un parking composé de plusieurs rangées de places. Autrement dit un grand parking est composé de plusieurs parkings élémentaires. Lorsqu’une voiture veut stationner dans un grand parking, elle se range dans la première place libre d’une rangée incomplète.
Un véhicule est localisé par son numéro de rangée et numéro de place dans la rangée.
Un grand parking rend les mêmes services qu’un parking élémentaire.
Ce qu’il faut retenir
Les constructeurs, constructeurs multiples et leur rôle d’initialisation ;
La visibilité des classes et de leur contenu (plus particulièrement les droits public et private).
Vos notes

TP 4 : Création d’un dialogue
L’objectif de ce TP est de créer une interface simple afin de mettre en œuvre les principaux concepts nécessaire à la gestion de dialogue.
Java fourni en standard une bibliothèque de composants pour la création d’interfaces graphique : fenêtre, boutons, menus… Cette bibliothèque permet de construire des applications qui auront le même aspect quelque soit la machine cible (Unix, MacOS, Windows…).
Une première version appelée AWT (Abstract Window Toolkit) a été proposée et grandement amélioré avec les JDK de la série 1.1.x. Avec Java 2, ou encore Java 1.2, Sun a proposé une deuxième bibliothèque appelé Swing et exploitant l’AWT. Swing permet de construire des interfaces ayant un aspect beaucoup plus agréable et offrant des possibilités beaucoup plus importante.
La construction d’une interface
La définition de l’interface utilisateur se décompose en trois activités principales :
Création des composants,
Placement des composants,
Rendre actif les composants : prise en compte des événements.
Les composants
Chargement des bibliothèques
Afin de pouvoir utiliser les composants Swing, il faut faire appel à cette bibliothèque. En Java, une bibliothèque est un paquetage et le chargement d’un paquetage s’effectue avec la clause import. Le nom de la bibliothèque est javax.swing. Dans cette bibliothèque, nous souhaitons utiliser de nombreux composants, aussi chargeons nous toute la bibliothèque :
import java.awt.*; import javax.swing.*;
Nous chargeons l’ensemble des composants de la bibliothèque AWT car Swing s’appuie sur celle-ci. Toutes les classes définies dans ces deux paquetages (packages) sont maintenant accessibles.
Type de composants
Les composants sont de deux types : les conteneurs et les contrôles. Les conteneurs sont les espaces d’accueil des contrôles.
Conteneurs : fenêtre, panneau,…
Contrôles : bouton, liste, boite à cocher,…

Les conteneurs 
On distingue deux principaux types de conteneur (Container) : une fenêtre ou un morceau de fenêtre. Un morceau de fenêtre est un panneau (classe Panel en AWT ou la classe JPanel en Swing). Les fenêtres (Window ou JWindow) se subdivisent en deux catégories : les fenêtres de dialogue souvent appelée boites de dialogue (Dialog ou JDialog) et les fenêtres de travail (Frame ou JFrame). C’est dans ces dernières que s’exécutent les applications. Les boites de dialogue servent principalement à la production de messages d’information ou à la saisie d’information. La hiérarchie des conteneurs est la suivante :
 EMBED OrgPlusWOPX.4 
Dimensionner une fenêtre
Spécifier la taille de la fenêtre :

// longueur et largeur : nombre de pixels.
d = new Dimension(longueur, largeur);
nomFenetre.setSize(d);

Laisser JAVA dimensionner la fenêtre en la compactant :

nomFenetre.pack(d);

Les contrôles

Les contrôles permettant de conduire des dialogues simples avec un utilisateur sont respectivement : JButton (bouton), JCheckbox (boite à cocher), JChoice (les listes à choix), JList (listes simples). Parmi les contrôles auxiliaires citons ceux relatifs aux menus : JMenu, JMenuitem (les différents choix d’un menu), JMenubar (un ensemble de menus).

Les contrôles de bases sont suffisants pour effectuer nombre de tâches. Les contrôles offerts par JBuilder (paquetage com.borland.jbcl.control.*) et par AWT utilisent des méthodes « relativement » similaires à celles du paquetage Swing. Comme pour les conteneurs, nous indiquons la hiérarchie des contrôles :
 EMBED OrgPlusWOPX.4 
Ajouter un contrôle à un conteneur
L’ajout d’un contrôle à un conteneur s’effectue toujours dans un panneau JPanel. Par défaut toutes les fenêtres ont un panneau central. Pour accéder à ce panneau, il faut utiliser l’instruction getContentPane().
Exemple : Ajouter un bouton dans une fenêtre s’appelant maFenetre.
maFenetre.getContentPane().add(new JButton("OK"))
L’ajout d’un composant s’effectue à l’aide de la commande add.
Un contrôle qui est ajouté est positionné dans le conteneur en fonction du gestionnaire de positionnement (layout).
Quelques méthodes communes à tous les contrôles

Nom méthodeRôleboolean isEnabled()Renvoie si le contrôle est actif ou nonvoid setEnabled(boolean b)b specifie si le composant doit être actif ou non.Void setSize(int l, int h) Dimensionne le composant aux tailles l(ongueur) et h(auteur).String toString()Transforme l’objet au format chaîne.
Description des contrôles
Les boutons
Constructeurs
JButton()
JButton(String caption)

Quelques méthodes

Nom méthodeRôleString getText()Obtenir le texte s’affichant dans le boutonvoid setText(String s)La chaîne s est le nouveau texte s’affichant dans le bouton.
Exemple :
b1 = new JButton() ;
b1.setText("OK") ;
maFenetre.getContentPane().add(b1) ; // ajout à la fenêtre courante.
maFenetre. getContentPane().add(new JButton("Cancel")) ; // idem mais plus compact.


Les boites à cocher
Une boite à cocher est un contrôle pouvant être à vrai ou faux.
Constructeurs
JCheckbox()
JCheckbox(String label) : label contient le libelle de la boite.
JCheckbox(String l, boolean s) : l contient le libelle et s l’état initial de la boite.
Quelques méthodes

Nom méthodeRôleCheckboxGroup getCheckboxGroup()Obtenir le groupe où la boite est membreString getText()Obtenir le libellé de la boite.Boolean getSelected()Obtenir l’état de la boite (vrai ou faux)void setText(String s)Assigner le libellé s à la boite.void setSelected(boolean b)Assigner l’état b à la boite (vrai ou faux)
Exemple :
c = new JCheckbox() ;
c2 = new JCheckBox("Me tenir informé", true)
c.setSelected(true) ;

Les listes de choix
Les listes de choix (ComboBox) fonctionnent comme un menu : l’utilisateur sélectionne un composant dans la liste proposée et celui-ci devient actif. Les listes de choix permettent d’offrir différentes éventualités en un espace compacte.
Constructeurs
JComboBox()
JComboBox(Object[] tableauObjets) : la liste des choix qui doit être présentée à l’utilisateur est transmise avec un tableau d’objets.
JComboBox(Vector vecteurObjets) : idem sauf que la liste est transmise avec un vecteur.
Quelques méthodes

Nom méthodeRôlevoid addItem(Object o)Ajouter l’objet o à la liste de choix. void addItemAt(Object o, int p)Ajouter l’objet o à la liste de choix à la place mentionné par p.Object getItemAt(int i)Obtenir le ième élément sous la forme d’une chaîne. int getItemCount()Obtenir le nombre d’éléments dans la liste.int getSelectedIndex()Obtenir la position dans la liste de l’élément sélectionné. La liste débute à zéro.Object getSelectedItem()Obtenir l’élément sélectionné dans la liste.void insertItemAt(Object o, int i)Ajoute l’élément o à la position i dans la liste.void removeItemAt(int i)Oter le ième élément de la liste.void removeItem(Object o)Oter l’élément o de la liste.void removeAllItems()Oter tout les éléments de la liste.void setSelectedIndex(int i)L’élément sélectionné est le ième élément.void seSelectedItem(Object o)L’élément sélectionné est l’élément o.
Exemple :
coloris = new JComboBox();
coloris.addItem("Vert");
coloris.addItem("Rouge");
coloris.addItem("Bleu");

coloris.setSelectedIndex(2)
// la couleur sélectionnée par défaut est le bleu.
System.out.println(coloris. GetItemCount()) // affiche 3 dans la console

String[] oiseaux = {"corbeau", "canari", "perroquet"} ;
// créer et charger un tableau de chaines
listeOiseaux = new JcomboBox(oiseaux) ;

Les listes
Les listes fonctionnent différemment des liste de choix : l’utilisateur fait défiler la liste pour sélectionner (éventuellement) un ou plusieurs éléments. Un élément est sélectionné en cliquant sur celui-ci (une nouvelle sélection annulant la première).
Constructeurs
JList()
JList(Object[] tableauObjets) : les données qui doivent être présentées à l’utilisateur sont transmises avec un tableau d’objets.
JList(Vector vecteurObjets) : idem sauf que les données sont transmises avec un vecteur.

Quelques méthodes

Nom méthodeRôlevoid clearSelection()Effacer la sélection.int getSelectedIndex()Obtenir la position dans la liste de l’élément sélectionné. La liste débute à zéro.int[] getSelectedIndices()Obtenir l’ensemble des positions sélectionnés dans la liste. Le résultat est donné sous la forme d’un tableau.Object getSelectedValue()Obtenir l’élément sélectionné dans la liste.Object[] getSelectedValues()Obtenir sous la forme d’un tableau d’objets, l’ensemble des éléments sélectionnés de la liste.boolean isSelectedIndex(int i)Renvoie vraie si l’élément i est sélectionné (sinon faux).boolean isSelectionEmpty()Vrai si aucun élément n’est sélectionné dans la liste.void setSelectedIndex(int i)Sélectionne l’élément d’indice i dans la liste.void setSelectedIndices(int[] tab)Sélectionne la valeur spécifiée par les indices du tableau tab.void setSelectionMode(int mode)Spécifie le mode de sélection unitaire ou multiple. Les valeurs possibles sont SINGLE_SELECTION, SINGLE_INTERVAL_SELECTION, MULTIPLE_INTERVAL_SELECTION.void setVisibleRowCount(int i)Spécifie le nombre de lignes affichées par la liste.
Exemple :
String[] oiseaux = {"corbeau", "canari", "perroquet"} ;
// créer et charger un tableau de chaines
String s ;
listeOiseaux = new JList(oiseaux) ;
listeOiseaux.setSelectedIndex(1) ; // sélection de canari
s = (String)listeOiseaux.getSelectedValue // s contient canari.


Les zones de saisie
Les zones de saisie sont des contrôles textuels. Ils permettent l’édition de texte sur une seule ligne.
Constructeurs
JTextField()
JTextField(int nbChar) : créer une zone de saisie de nbChar caractères.
JTextField(String s) : créer une zone de saisie contenant la chaîne s (valeur par défaut).
JTextField(String s, int nbChar) : créer une zone de saisie contenant la chaîne s (valeur par défaut) et ayant un longueur de nbChar caractères.
Quelques méthodes

Nom méthodeRôleString getText()Obtenir le texte s’affichant dans la zone de saisie.Boolean isEditable()Renvoie vraie si la zone peut être éditée (c’est-à-dire saisie).Void setEditable(boolean b)Spécifie si le contenu de la zone est modifiable ou non.Void setText(String s)La chaîne s est le nouveau texte de la zone de saisie.
Disposer les contrôles
Les programmes en Java sont supposés s’exécuter sur tout type de machine. Ceci contraint à exclure le plus possible les références au matériel dans la définition et le placement des composants. La disposition des contrôles est relative. C’est-à-dire qu’il faut indiquer les positions à l’aide de balises : à gauche, au nord…

Pour effectuer la disposition des contrôles, les contrôleurs ont besoin d’un gestionnaire de disposition. En Java, un gestionnaire de disposition s’appelle un LayoutManager. L’association se fait en plusieurs temps :
Création d’un gestionnaire de disposition ;
Association du gestionnaire au conteneur ;
Utilisation du gestionnaire pour placer les contrôles.

// associer un gestionnaire de type BorderLayout.
g = new BorderLayout();
nomFenetre.getContentPane().setLayout(g);
// ajout d’un controle
nomFenetre.getContentPane().add(nomControle, "North") ;

En fonction de la disposition souhaitée, Swing (et AWT) nous propose différents gestionnaires de disposition :

 EMBED OrgPlusWOPX.4 

FlowLayout
Les éléments sont en ligne les uns après les autres. Si la ligne ne peut contenir tous les composants, ceux-ci sont alors disposés sur plusieurs lignes.

BorderLayout
Les éléments sont placés dans un espace de cinq zones : North, South, West, Center, East


.


GridLayout
Les éléments sont placés dans un espace divisés en ligne et colonnes. Le nombre de lignes et colonnes est indiqué en paramètre dans le constructeur du gestionnaire.

GridBagLayout
Les éléments sont placés dans un espace divisés en ligne et colonnes. Le nombre de lignes et colonnes est indiqué en paramètre dans le constructeur du gestionnaire. Ce gestionnaire est plus sophistiqué que le précédent car il permet d’avoir des lignes et colonnes de taille différente et il permet aussi de poser des contrôles sur plus d’une cellule.



Exercice
L’objectif de ce programme est de définir une interface pour une utilisation ultérieure de la classe Parking. Pour ceci nous allons créer deux classes : une classe programme et une fenêtre. La classe programme contient la fonction main. Cette fonction va créer la fenêtre et afficher la fenêtre. Pour effectuer cette opération, il faut créer une application dans JBuilder.

La seconde étape consiste à donner la description de la fenêtre:

La seule option nécessaire pour le moment, c’est le centrage de la fenêtre à l’écran. Dans le navigateur de projet les deux classes sont ajoutés.
Analyser les instructions.
Nous allons maintenant construire la fenêtre à l’aide de l’assistant de conception de JBuilder. Cet assistant est appelé à l’aide de l’onglet Conception (il faut bien sur demander l’assistant pour la fenêtre).




Associez maintenant un gestionnaire de disposition de type FlowLayout et posez les contrôles Swing pour aboutir au résultat suivant :

Pour la construction d’interfaces plus complexes, les gestionnaires de disposition sont insuffisants. Leur rusticité est compensée par un recours aux panneaux (JPanel).







Créer une fenêtre similaire à la fenêtre suivante en utilisant différents panneaux et gestionnaires de disposition :

A faire
Ajouter un label spécifiant combien de places sont libres dans le parking ainsi qu’un bouton pour quitter le programme.
Déterminer une représentation du parking simple (les places avec leurs véhicules).
Ce qu’il faut retenir
La distinction conteneur/composant ;
La disposition relative des composants dans les conteneurs ;
La conception de fenêtre avec JBuilder.
Vos notes


TP n°5 : Gérer des événements
L’objectif de ce TP est d’aborder la dynamique des interfaces utilisateurs. Dans le TP précédent, nous avons montré comment définir des fenêtres et des composants. Les interfaces sont pour l’instant statiques : il faut spécifier les actions devant être exécutées lorsque l’utilisateur effectuera certaines commandes. Ces commandes sont appelés des événements.
La gestion des événements
La gestion des événements s’appuie sur un modèle de délégation des événements. Les sources des événements sont les composants Swing ou awt :

Un événement est propagé d’une source à un contrôleur.

Le gestionnaire s’assure de la création et de la propagation de l’événement : seul le contrôleur reste à implémenter. Une interface, c’est-à-dire un gabarit, est prédéfini dans JAVA pour tous les types de contrôleur.

Pour utiliser le gestionnaire d’événements il faut utiliser le paquetage java.awt.event.*.

Le contrôleur de la fenêtre

La classe WindowAdapter est une implémentation prédéfinie de l’interface WindowListener. Pour utiliser ce dernier comme base :

public class maClasseControleurDeFenetre extends WindowAdapter

Pour associer le contrôleur à la fenêtre :

NomObjetControleur = new maClasseControleurDeFenetre() ;
MaFenetre.addWindowListener(nomObjetControleur) ;


Exemple de contrôleur :

public class maClasseControleur extends WindowAdapter {

// l’evenement fermeture declenche l’arret du
// programme.
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}

Le contrôleur des contrôles

Les contrôles doivent eux aussi être associé à des événements. Ceux-ci prennent en charge la demande d’une action, comme le changement d’une valeur par exemple. Les contrôleurs type prédéfinis sont ActionEvent, TextEvent, ItemEvent. Ils sont décrits à l’aide d’interface et doivent donc être implémentés.

public class monControleur implements ActionListener

Pour associer un contrôleur monControleur à un bouton monBouton :

monBouton .addActionListener(monControleur) ;


Dans une classe implémentant un contrôleur de commande (pour les boutons par exemple), il faut ensuite décrire la méthode donnant les instructions à exécuter : celle-ci a comme nom actionPerformed :

public class btnQuitterControleur implements ActionListener {

/* action a executer avec le bouton quitter
il faut arreter le programme */

public void actionPerformed(ActionEvent e) {

System.exit(0);
}
}

question de méthode
Dans un programme orienté-objet, pour des considérations de conception et de maintenance, il faut limiter les objets à un seul rôle : il ne faut pas confondre, par exemple : un traitement et la représentation de ce traitement.
Si nous reprenons des travaux effectués précédemment sur les parkings et l’interface utilisateur pour les parkings, nous devons retrouver cette dichotomie :
création / définition d’un objet Parking,
création / définition d’une interface utilisateur s’appliquant à cet objet,
L’interface permet d’envoyer des messages à l’objet Parking pour ranger ou enlever des voitures.
Autrement dit, la gestion des événements doit se limiter à trois grandes opérations :
récupérer les données fournies par l’utilisateur grâce à l’interface, 
transmettre ces données aux objets « application » (éventuellement reformatées) sous la forme d’envoi de message,
transmettre à l’utilisateur le compte-rendu transmis par l’appel des méthodes, ce compte-rendu est transmis grâce à l’interface.
Exercice
L’objectif de l’exercice est d’associer l’interface définie dans le TP précédent à l’objet Parking. L’application comprendra trois classes : PrgParking, WinParking, Parking. La première des trois classes contient la fonction main qui :
Crée un objet Parking p.
Crée une fenêtre f, instance de la classe parking. La fenêtre est une représentation du parking p. Celui-ci est donc transmis en paramètre de création de la fenêtre.
Affichage de la fenêtre f.
Concernant la classe winParking, il faut maintenant définir la gestion des événements. La création des contrôleurs peut être faite à partir de JBuilder :



JBuilder propose un nom de méthode par défaut et génère son gabarit. Il suffit alors de compléter les instructions. Ainsi pour le bouton ranger qui se nomme btnRanger, le gabarit est le suivant :
void btnRanger_actionPerformed(ActionEvent e) {

}
Compléter les gestionnaires d’événements : les instructions exécutées par un bouton sont :
mise à jour du parking (retrait, enlever) ou demande d’information (nb. véhicules);
affichage d’un compte-rendu à l’opérateur par une boite de dialogue d’information (méthode de classe JOptionPane.showMessageDialog(…)).
A faire
1.  Créer les interfaces utilisateurs pour les deux types de parkings de ferry.
2. Coupler une interface utilisateur à la classe des grands parkings.
Ce qu’il faut retenir
La séparation application / représentation de l‘application.
La notion d’événements,
La notion de contrôleur d’événements,
Un composant « actif » a au moins un contrôle.

Vos notes


TP n°6 : Héritage et interface
L’objectif de ce TP est de mettre en pratique les notions d’héritage et de classes abstraites.
Héritage
L’héritage consiste à spécifier qu’une classe est similaire à une autre classe. En indiquant qu’une classe hérite d’une autre classe, vous obtenez accès à toutes les données et méthodes membres de la classe ancêtre.








L’héritage sert donc à étendre des classes, soit en Java :
Class VoituresCarburant extends Voiture {
…
}
Une seconde visite du parking
Voici une description des parkings simples et parking de ferry mettant en œuvre les concepts d’héritage.
public class parking {

/* les donnees sont declarees Protected
car elles doivent etre visibles des
sous-classes
*/
protected static int NBMAXPLACES = 5;
protected String[] Places;

public parking() {
int i;
Places = new String[NBMAXPLACES];
for (i = 0; i < NBMAXPLACES; i++)
Places[i] = "";
}

public int getNbPlaces() {
int i, nbplaces;

nbplaces = 0;
for(i = 0; i < NBMAXPLACES; i++) {
if(Places[i].equals(""))
nbplaces = nbplaces + 1;
}
return nbplaces;
}

public boolean rangerVoiture(String numVoiture) {
int i, noplace;
boolean trouvePlace;
// quid si on range deux fois la meme voiture.
trouvePlace = false;
noplace = 0;

for(i = 0;(trouvePlace == false) && (i < NBMAXPLACES); i++) {
if(Places[i].equals("")) {
noplace = i;
trouvePlace = true;
}
}

if(trouvePlace == true)
Places[noplace] = numVoiture;

return trouvePlace;
}

public boolean enleverVoiture(String numVoiture) {
int i, noplace;
boolean trouveVoiture;

trouveVoiture = false;
noplace = 0;

for(i = 0; i < NBMAXPLACES; i++) {
if(Places[i].equals(numVoiture)) {
noplace = i;
trouveVoiture = true;
}
}
// liberation de la place
if(trouveVoiture == true)
Places[noplace] = "";

return trouveVoiture;
}

}/* la classe parkingAvantArriere est une classe derivee de parking.
*/

public class parkingAvantArriere extends parking {

protected int position;
/* specifie l'emplacement de la prochaine voiture a ajouter.
la premiere place face a la porte avant est en position zero. La place pres de la porte arriere est en NBMAXPLACES - 1
c'est-a-dire la derniere place du tableau. l'information est de type protogee car elle est reutilisee dans les classes parentes.
*/

public parkingAvantArriere() {
/* appel du constructeur de la classe parente
c'est-a-dire parking
*/
super();
position = NBMAXPLACES - 1;
}

/* la classe getNbPlaces n'est pas
implementee : elle est heritee de parking

la methode parkingPlein() est une methode
auxiliaire pour ajouter des voitures. elle n'est donc visible que de la classe (declaration en "private").
*/

private boolean parkingPlein() {

// le parking est plein si la 1ere place face
// a la porte avant est occupee.

return (!Places[0].equals(""));
}

public boolean rangerVoiture(String numVoiture) {

if(parkingPlein() == false) {
Places[position] = numVoiture;
position--;
return(true);
} else
return(false);
}

/* le retrait de voiture n'exige plus de recevoir en parametres le numero de la voiture:
la voiture qui sort est celle qui est devant la porte.
la methode renvoie non plus un booleen pour indiquer si la voiture a pu etre sortie mais une chaine contenant le numero de la voiture qui vient d'etre enlevee. Si la voiture ne peut être enlevee, la valeur null est alors retournee.
lorsque la voiture est retiree du parking : toutes les voitures avancent pour se mettre pres de la porte arriere : la place est ainsi liberee cote porte avant.
*/
public String enleverVoiture() {

String voiture;
int i;

voiture = Places[NBMAXPLACES - 1];

/* toutes les voitures avancent d'une place :
elles prennent la place de la suivante
sauf la derniere qui laisse une place libre.
*/
for(i = NBMAXPLACES - 1; i > position + 1; i--)
Places[i] = Places[i - 1];

Places[position + 1] = "";

// la premiere place libre est maintenant plus pres de
// la porte arriere.
position++;

if(voiture.equals(""))
return null;
else
return voiture;
}
}
Classes abstraites
Dans une classe, les données et les entêtes des méthodes donnent la spécification de la classe. Ces informations sont les informations visibles depuis l’extérieur. Une classe abstraite a pour objet de donner non pas une implémentation de la classe mais de décrire simplement sa spécification. Les classes abstraites contiennent des méthodes abstraites. Toutes les méthodes ne sont pas forcément abstraites dabs une classe abstraite.
Les classes et/ou les méthodes abstraites permettent de représenter des notions génériques. Considérons par exemple, une classe représentant des clients. Ces clients sont des clients douteux ou des clients « neutres » ou, enfin, des bons clients.
 EMBED Word.Picture.8 
L’implémentation du calcul de la ristourne ne peut être décrit avec le client générique. Elle doit être concrétisée avec la description des sous-classes.
La définition de la classe client est elle la suivante :
public abstract class Client {
public abstract void ristourne() ;
}
Interface
Une interface est une classe abstraite où toutes les méthodes sont abstraites et où les seules données spécifiées sont des constantes.
Tout comme pour les classes abstraites, les interfaces ne peuvent être instanciées. La définition de classes interfaces héritant de classes interfaces est possible. Une classe interface permet de spécifier les méthodes devant être implémentée par toute classe issue de la classe interface.
Reprenons notre exemple précédent et considérons que nous considérions la classe client comme une classe interface. Nous obtenons alors pour la définition de la classe client et la description des classes héritées :
public interface Client {
public abstract void ristourne() ;
}
public class ClientDouteux implements Client {
public void ristourne() {…}
}
Toute classe ne peut héritée que d’une seule classe. Toutefois elle peut implémenter simultanément plusieurs interfaces.
public maFenetre extends Jframe implements windowListener
implements mouseListener
implements keyListener {
…
}
Exercice
L’objectif de cet exercice est d’écrire un programme rassemblant un ensemble de classes se combinant entre elles par héritage et/ou implémentant une ou plusieurs interfaces.
Il s’agit de représenter des séjours hôteliers et des locations de voitures. Une location de voiture consiste à louer un véhicule d’une catégorie c pendant n jours. A cette catégorie c correspond un niveau de confort et un prix par jour. Il est d’usage qu’un véhicule loué soit ramené au lieu où a été pris le véhicule. Toutefois il existe un autre type de location de voiture : les locations où le véhicule est rendu dans un lieu différent du lieu de départ. Dans ce cas le prix est fixé non seulement en fonction du nombre de jours et de la catégorie du véhicule mais aussi en fonction de la distance entre les points de départ et d’arrivée.
Un séjour hôtelier peut être effectué dans un « bed & breakfast », hôtel, club,… Selon le type « d’hôtel » et les accords avec l’agence de voyage la règle pour calculer le prix du séjour hôtelier varie (à la nuit, forfait,…).
Un autoTour est une location de voiture sans remise de véhicule dans un lieu d’arrivée distinct combinée à un séjour à l’hôtel. Le nombre de jours est déjà fixé. Le prix du séjour à l’hôtel est fixé par un prix forfaitaire.
Dans chaque classe, vous définirez le(s) constructeur(s) ainsi qu’une méthode pour obtenir le prix du service (location, séjour, autotour).
Ce qu’il faut retenir
Méthodes et données héritées,
Spécification partielle ou totale de classes : classes abstraites et interface. Combinaisons héritage et implémentation d’interface.
Vos notes
TP n° 7 : Vecteurs et listes
L’objectif de ce TP est de manipuler des structures de données de type liste. Ces structures de données sont des structures avancées. Elles permettent de stocker des séquences d’objet. Ces objets ne nécessitent pas d’être de même nature :
listeObjets = (client1, fournisseur2, produit12) 
Un vecteur est une liste. Tout comme pour un tableau, les éléments sont ordonnés et indexés. Les similitudes s’arretent là. Un vecteur n’a pas de taille prédéfinie. Elle peut donc évoluer contrairement à celle d’un tableau et permettre ainsi de gérer des ensembles d’objets dont le nombre n’est pas préalablement fixé.
Un vecteur ne peut contenir que des objets, les types primitifs ne sont pas admis . Puisque toutes les classes dérivent de la classe Object, tout type d’objet peut être stocké dans le vecteur.
Le premier élément d’un vecteur est en position 0. La classe des vecteurs est dans le paquetage
java.util.*
Description d’un vecteur
Création d’un vecteur
Vector()
Vector(int taille) : n contient une taille initiale.
Lorsque le vecteur est rempli, celui-ci est automatiquement augmenté.
Quelques méthodes

Nom méthodeRôleObject firstElement()Obtenir le premier élément du vecteurObject lastElement()Obtenir le dernier élément de la liste.Object elementAt(int i)Obtenir l’élément rangé à la ième place.boolean contains(Object o)Vérifier que l’objet o en dans le vecteur.int indexOf(Object o)Rechercher la première occurrence de l’objet o dans le vecteur et retourner sa position.int lastIndexOf(Object o)Rechercher la dernière occurrence de l’objet o dans le vecteur et retourner sa position.void addElement(Object o)Ajouter un objet o à la fin du vecteur.void insertElementAt(Object o, int i)Insérer l’objet o dans le vecteur à la place i. Tous les éléments suivants ont leur position incrementée d’un.Void setElementAt(Object o, int i)L’élément de la ième place est assignée à la valeur o.void removeElementAt(int i)Retirer l’objet assigné à la place i du vecteur.boolean removeElement(Object o)Retirer la première occurrence de l’objet o du vecteur. La méthode renvoie true si l’opération a été effectuée.void removeAllElements()Retirer tous les éléments du vecteur.int size()La méthode retourne le nombre d’éléments dans le vecteur.boolean isEmpty()Vrai si le vecteur est vide
Concordance de types et transtypage
Les objets stockés peuvent être de n’importe quelle classe. Toutefois, le seul type renvoyé par les méthodes de la classe vecteur sont des objets. Il faut donc connaître la classe « réelle » de l’objet pour que celui soit correctement utilisé. Ceci est effectuer en « transtypant » l’objet.
Exemple :
String chaine, chaineBis ;
Vector v ;
Object o ;

V = new Vector() ;

chaine = "bonjour" ;
v.addElement(chaine) ; // ajout d’un objet String

o = v.elementAt(0) ; // o est un objet
chaineBis = (String)v.elementAt(0) ; // l’objet est converti en String

Notons que l’instruction
chaineBis = v.elementAt(0) ;

produit une erreur car chaineBis est de la classe String alors que l’élément renvoyé est de type Object.
Exercice
Il s’agit de représenter un système d’aide pour des déplacements en transport en commun afin de se rendre dans des lieux publics. Les principaux objets sont :
les lignes de bus : elles sont représentées sous la forme d’une liste d’arrêts. L’ensemble des lignes, représentable aussi sous la forme d’une liste, forme le réseau.
Un ensemble de lieux publics. Un lieu public est décrit par son nom (mairie, piscine municipale,…) et par l’arrêt d’autobus le plus proche.
Il vous est demandé d’implémenter des classes représentant ces différents concepts. Vous n’hésiterez pas à définir les classes de type listes avec des liens d’héritage avec la classe des vecteurs. Vous prendrez soin de redéfinir les méthodes d’insertion et d’accès aux éléments pour éviter les conversions de type. La méthode d’ajout de lieux publics devra conserver un ordre alphabétique sur les noms de lieux. Votre application doit permettre de compléter des lignes de bus (ajouter un arrêt entre deux arrêts).
Votre application doit permettre d’indiquer, pour un lieu public, la ligne le desservant. Elle doit permettre de connaître le départ et terminus d’une ligne.


Ce qu’il faut retenir
La représentation des données avec des listes, structures de données de haut niveau ,
Transtypage.
Vos notes




TP n°8 : L’architecture modèle – Vue – Contrôleur
L'architecture modèle – Vue – Contrôleur est un moyen de séparer le cœur d'une application avec sa représentation. Il s'agit d'une extension des concepts qui nous ont conduits à séparer la gestion des données dans un ensemble d’objets modèle d'une part, et le comportement de l'interface utilisateur dans un ou plusieurs objets vue d'autre part.
L'architecture modèle – Vue – Contrôleur sépare encore davantage l'affichage des données en réduisant au minimum le couplage application / représentation. Ceci est effectué en diminuant le plus possible la dépendance par rapport aux types de données dans l’objet application.
Fonctionnement 
Supposons que l’application doive présenter un ensemble de données dans une liste. La technique usuelle est :
de transmettre les données à un composant liste de base,
d’associer un gestionnaire de contrôle (contrôleur) à la liste.
Nous devinons qu’il y a une forte dépendance des données vis-à-vis de la présentation. Pour éviter cet écueil, nous associons un élément intermédiaire : un « modèle » des données. Les différentes étapes sont maintenant :
construire un modèle de données,
d’associer ce modèle de données à la liste, c’est-à-dire à la vue sur les données,
d’associer un contrôleur à la liste.
Pour chaque valeur que la liste doit afficher, elle interroge le modèle (1). Le modèle interroge alors l’ensemble de données sources (2), obtient les données (3) et les transmet à la liste (4). La liste affiche alors la valeur :
 EMBED Word.Picture.8 
Cette technique permet de pouvoir prendre en compte de manière beaucoup plus aisée les ensembles de valeurs dynamique. Elle permet de voir différemment les données : on ne transmet plus les données à la vue mais on définit un moyen d’accès à celles-ci. Qui plus est maintenant le modèle est le seul élément à connaître la représentation interne des informations.
Cette architecture ne peut être mise en place qu’avec la bibliothèque Swing et ne s’adresse, évidemment, qu’aux composants gérant des volumes de données qui peuvent être importants. C’est-à-dire :
Les listes, les tableaux, les « combos » et les composants textes
Les classes modèles sont des classes abstraites. Elles sont abstraites car elles nécessitent de définir les méthodes dialoguant avec l’ensemble de données.
Exemple : implémentation d’un modèle pour une liste de données. Dans un premier temps, nous définissons une classe représentant un modèle de données. Cette classe hérite de la classe abstraite des modèles de données pour les listes. Seules deux méthodes nécessitent d’être implantées : la méthode déterminant le nombre d’éléments dans la liste et la méthode permettant d’obtenir le ième élément à afficher dans la liste.
Supposons que nous décrivions un modèle de la liste des voitures. Le modèle du parking reçoit le parking en paramètre et accède ensuite au parking.
class MyListModel extends AbstractListModel {

private Parking leParking ;

public MyListModel(Parking p) {
leParking = p ;
}

public int getSize() {
return leParking.getNbPlaces() ;
}

public Object getElementAt(int index) {
return leParking.obtenirVoiture(index);
}
}

Dans second temps, nous créons un modèle et nous appliquons le modèle à la liste. Le modèle est appliqué en le transmettant en paramêtre de construction de la liste :
MyListModel monModele ;
Jlist monComposantListe ;

monModele= new MyListModel(unParking) ;
monComposantListe = new JList(monModele) ;

Présenter des données dans des tables
Le composant Swing JTable permette d’afficher un tableau de données. Ce tableau peut être soit simplement affiché, mais peut aussi être modifié. Le modèle joue donc un double rôle : Il donne un moyen pour accéder aux données pour les présenter mais il s’assure aussi, lorsqu’il y a modification des données dans la vue, de la synchronisation entre la source de données et sa présentation.
La représentation de données non homogènes est tout à fait possible : une première colonne présente des données textuelles, la seconde une valeur numérique, etc…

Afin de pouvoir définir des tables et des modèles associés, il faut importer le paquetage :
javax.swing.table.*
Les items présentés dans la table sont référencés par deux valeurs : ligne et colonne. Ces valeurs sont des valeurs entières. La première méthode à définir est celle offrant l’accès aux données :
getValueAt(int ligne, int colonne)
Exemple : Supposons que les données à présenter soient des couples (nomLogiciel, nomEditeur( et que ceux-ci soient stockés dans deux tableaux portant les noms nomLogiciel et nomEditeur. La méthode est la suivante :
Object getValueAt(int ligne, int colonne) {

if (ligne==0)
return nomLogiciel[ligne] ;
else
return nomEditeur[ligne] ;
}
Pour éviter les débordements, il faut donc indiquer à la vue le nombre de lignes et de colonnes. Pour ceci, il faut implanter deux nouvelles méthodes : getRownCount() et getColumnCount(). Si nous poursuivons notre exemple, nous obtenons :
int getRowCount() {

return Array.getLength(nomLogiciel) ;
}

int getColumnCount() {

return 2 ;
}

Pour parfaire l’affichage, il faut définir l’entête des colonnes du tableau. La méthode est getColumnName(int noColonne). L’entête est représenté à l’aide d’un composant intermédiaire appelé JtableHeader.
Dans notre exemple, nous obtenons :
String getColumnName (int noColonne) {

if (noColonne ==0)
return "Nom du Logiciel" ;
else
return "Editeur" ;
}

L’ensemble des méthodes définies dans le modèle permettent de contrôler son affichage. Le dernier point consiste à définir si la table peut être éditer ou non. Le contrôle des mises à jour est autorisé avec la méthode isCellEditable(int ligne, int colonne). Cette méthode renvoie une valeur booléenne indiquant si la modification est autorisée. Dans notre exemple, si nous supposons que le nom de l’éditeur est modifiable mais pas le nom du produit, nous obtenons :
boolean isCellEditable(int ligne, int noColonne) {

if (noColonne ==0)
return false ;
else
return true ;
}

Le dernier point consiste à synchroniser la mise à jour faite dans la table avec les données. Ceci est effectué avec la méthode setValueAt(Object nouvelleValeur, int ligne, int colonne). L’objet transmis contient la nouvelle valeur à répercuter dans les données. Dans notre exemple nous devons prendre en compte les modifications des noms des éditeurs
void setValueAt(Object nouvelleValeur, int ligne, int colonne) {

nomEditeur[ligne] = (String)nouvelleValeur ;
}

Notre modèle est maintenant complet. Pour l’affichage de la liste, il est d’usage d’utiliser un panneau permettant les défilements verticaux et horizontaux (barres de défilement). Les panneaux de ce type sont appelés des JScrollPane. Le panneau s’assure de la synchronisation entre le défilement demandé par l’utilisateur et le rafraîchissement des informations affichées. Dans notre exemple, nous obtenons :
JScrollPane panneauTable ;
JTable maTable ;

monModele = new maClasseModele() ;
maTable = new JTable(monModele) ;

panneauTable = new JScrollPane(maTable) ;

maFenetre.getContentPane().add(panneauTable,BorderLayout.CENTER) ;

Description des composants Listes et Tables
Les Listes
Cette section complète la description des composants JList décrits dans le chapitre 5.
Constructeurs

JList(ListModel modele) : les données qui doivent être présentées à l’utilisateur sont transmises avec un modèle modele.
Quelques méthodes

Nom méthodeRôlevoid setModel(ListModel modele)Modifier le modèle de données de la liste.ListModel getModel()Obtenir l’objet modèle de données utilisé par la liste.
Les modèles de données « Liste »
Les modèles de données pour les listes se décomposent en deux classes : l’interface ListModel et la classe abstraite AbstractListModel qui implémente une partie de l’interface ListModel.
L’interface ListModel
Cette interface spécifie principalement les méthodes suivantes :
Nom méthodeRôleObject getElementAt(int i)Obtenir l’élément i du modèle de données.int getSize()Retourner le nombre d’éléments dans la liste.
La classe abstraite AbstractListModel et la classe DefaultListModel
La classe AbstractListModel est la classe de base pour la définition des modèles de données listes. Elle offre des services de bas niveaux. La classe DefaultListModel est une implémentation « générique » d’un modèle de données liste. Elle permet d’avoir une représentation de la liste en tant que pseudo-vecteur.
Constructeurs

DefaultListModel() : construit un modèle de liste « générique ».
Quelques méthodes
Nom méthodeRôleObject firstElement()Obtenir le premier élément de la liste.Object lastElement()Obtenir le dernier élément de la liste.Object elementAt(int i)Obtenir l’élément rangé à la ième place.boolean contains(Object o)Vérifier que l’objet o en dans la liste.int indexOf(Object o)Rechercher la première occurrence de l’objet o dans la liste et retourner sa position.int lastIndexOf(Object o)Rechercher la dernière occurrence de l’objet o dans la liste et retourner sa position.void addElement(Object o)Ajouter un objet o à la fin de la liste.void insertElementAt(Object o, int i)Insérer l’objet o dans la liste à la place i. Tous les éléments suivants ont leur position incrementée d’un.void setElementAt(Object o, int i)L’élément de la ième place est assignée à la valeur o.void removeElementAt(int i)Retirer l’objet assigné à la place i de la liste.Les Tables
Cette section présente la description du composant JTable. Nous ne décrivons pas les composants associés permettant la gestion de l’entête (JTableHeader), de la présentation des cellules (TableCellRenderer), la présentation des colonnes (TableColumn).
Constructeurs

JTable() : construit une table par défaut. Celle-ci est créée avec un modèle de donnée par défaut, un modèle de colonnes par défaut et un modèle de sélection par défaut.
JTable(Object[][] lesDonnees, Object[] entetes) : construit une table dont les données sont stockées dans la matrice lesDonnees et les entêtes de colonnes sont décrits dans le tableau entetes.
JTable(Vector lesDonnees, Vector entetes) : construit une table dont les données sont stockées dans la vecteur de vecteurs lesDonnees et les entêtes de colonnes sont décrits dans le vecteur entetes.
JTable(TableModel modeleDonnees) : construit une table dont les données sont décrites dans le modèle de données modeleDonnees.
Quelques méthodes

Nom méthodeRôlevoid clearSelection()Dé-sélectionner toutes les lignes et colonnes.boolean editCellAt(int i, int j)Permet de redéfinir l’éditeur de cellule. Renvoie faux si un problème a eu lieu a l’édition.Class getColumnClass(int col)Retourner la classe de la colonne ayant la position col.String getColumnName(int col)Retourner le nom de la colonne ayant la position col.TableModel getModel()Obtenir le modèle de données de la table.int getRowCount()Nombre de lignes dans la table.int getSelectedRow()Retourner l’indice de la première ligne sélectionnée.int getSelectedCount()Retourner le nombre de lignes sélectionnées.int[] getSelectedRows()Retourner les indices des lignes sélectionnées.boolean getShowHorizontalLines()Vrai si les lignes doivent être dessinées dans la vue.boolean getShowVerticalLines()Vrai si les colonnes doivent être dessinées dans la vue.Object getValueAt(int i, int j)Retourner l’élément en ligne i et colonne j.boolean isCellEditable(int i, int j)Vrai si la cellule peut être éditer.boolean isCellSelected(int i, int j)Vrai si la cellule est sélectionnée.void selectAll()Sélectionner toutes les cellules.void setModel(TableModel m)Assigner le modèle de données m à la table.void setValueAt(Object o, int i, int j)L’élément o devient la nouvelle valeur de la cellule en en ligne i et colonne j.
Les modèles de données « Table »
Les modèles de données pour les tableaux se décomposent en deux classes : l’interface TableModel et la classe abstraite AbstractTableModel qui implémente une partie de l’interface TableModel.
L’interface TableModel
Cette interface spécifie principalement les méthodes suivantes :
Nom méthodeRôleClass getColumnClass(int j)Obtenir la classe des éléments en colonne j.int getColumnCount()Retourner le nombre de colonnes.String getColumnName(int j)Obtenir le nom de la colonne j.int getRowCount()Obtenir le nombre de lignes.Object getValueAt(int i, int j)Obtenir l’élément en ligne i et colonne j.boolean isCellEditable(int i, int j)Vrai si la cellule est modifiable.void setValueAt(Object o, int i, int j)La valeur de l’objet en cellule i, j est assignée à o.
La classe abstraite AbstractTableModel et la classe DefaultTableModel
La classe AbstractTableModel est la classe de base pour la définition des modèles de données pour les tableaux. Elle offre des services de bas niveaux pour la gestion des évènments dans la liste ; la classe implémente de manière basique les méthodes suivantes :
getColumnClass, getColumnName, isCellEditable (fixé à non), setValueAt.
La classe DefaultTableModel est une implémentation « générique » d’un modèle de données de type tableau. Elle offre une représentation des données sous la forme de vecteurs de vecteurs et permet d’avoir un modèle de base offrant la plupart des services courants.
Constructeurs

DefaultTableModel() : construit un modèle de données « générique » sans lignes ni colonnes.
DefaultTableModel(int nbLignes, int nbCols) : construit un modèle de données de nbLignes et nbCols. Toutes les cellules sont initialisées à null.
DefaultTableModel (Object[][] lesDonnees, Object[] entetes) : construit un modèle de données dont les données sont stockées dans la matrice lesDonnees et les entêtes de colonnes sont décrits dans le tableau entetes.
DefaultTableModel (Vector lesDonnees, Vector entetes) : construit un modèle de données dont les données sont stockées dans la vecteur de vecteurs lesDonnees et les entêtes de colonnes sont décrits dans le vecteur entetes.
Quelques méthodes
Nom méthodeRôlevoid addColumn(Object nomCol, Vector donneesCol)Ajouter une colonne au modèle. Cette colonne a pour nom nomCol et les données sont spécifiées dans un vecteur donneesCol.void addRow(Vector laLigne)Ajouter une ligne au modèle. La ligne est ajoutée à la fin et est spécifiée avec un vecteur.int getColumnCount()Retourner le nombre de colonnes.String getColumnName(int j)Obtenir le nom de la colonne j.Vector getDataVector()Retourne un vecteur de vecteur contenant l’ensemble des données du modèle de données.int getRowCount()Obtenir le nombre de lignes.Object getValueAt(int i, int j)Obtenir l’élément en ligne i et colonne j.void insertRow(int ligne Vector laLigne)Ajouter une ligne au modèle. La ligne est ajoutée à la ligne ligne et est décrite avec un vecteur.Boolean isCellEditable(int i, int j)Vrai si la cellule est modifiable (par défaut tout est à faux).void removeRow(int ligne)Supprimer la ligne ligne du modèle.void setColumnIdentifiers(Vector nomCols)Remplacer les identifiants des colonnes.void setDataVector(Vector nouvellesDonnees, Vector nomCols)Remplacer l’ensemble des données par les données indiquant dans le vecteur de vecteur. Les noms des colonnes sont aussi modifiés.void setValueAt(Object o, int i, int j)La valeur de l’objet en cellule i, j est assignée à o.
Exercice
Le but de cet exercice est de concevoir un ensemble de classes reproduisant l’architecture modèle, vue, contrôleur.
L’application doit permettre de représenter des données représentant des ventes automobiles d’un garage :
MéganeSafraneTwingoJanvier8421Février2717Mars11518Total2116 =SUM(AUDESSUS) 56
Les données doivent être représentées de manière autonome. Vous prendrez soin de définir des classes permettant un extension aisée à la fois des mois et des modèles de voitures.
Vous devez définir un modèle de données pour afficher les données dans une table Swing. Les totaux sont des valeurs calculées et non prédéfinies.
Vous supposerez que les données ne sont pas modifiables.
A faire
Modifier le programme pour permettre la mise à jour des valeurs numériques de base. Les libellés ne sont pas modifiables. Les totaux ne sont pas modifiables et la modification d’une valeur doit déclencher une mise à jour du total correspondant.
Limitez la modification en permettant la saisie de valeurs correctes uniquement (valeur entière positive ou nulle).
Ce qu’il faut retenir
Principe de fonctionnement de l’architecture : il s’agit de définir un moyen d’accès aux données devant être présentées.
Son application dans la manipulation de données tabulaires. Comment la vue interroge le modèle et comment le modèle interroge la source de données.
Le travail de synchronisation entre la source et la vue effectuée par le modèle lorsqu’il y a modification des données.
Vos Notes



TP n°9 : Hashtables
Une table de hachage est une structure de données permettant d’effectuer des accès « rapides » à des informations. Le plus souvent, les données sont représentables sous la forme :
Clef ( valeurs
Ce principe est par exemple usuel dans la manipulation de tables en bases de données. Les objets stockés dans une table de hachage doivent donc pouvoir être identifiés. Les données sont stockées dans la table et sont transmis sous la forme de couple ObjetClef, objetValeur. La table de hachage utilise l’objet clef pour définir une clef de hachage. Cette clef permettra ensuite un accès direct aux informations car elle permet de localiser l’objet valeur dans la table.
La classe table de hachage est dans le paquetage :
java.util.*
La classe des tables de hachage s’appelle Hashtable.
La table de hachage s’appuie sur deux méthodes devant être définies dans la classe des objets clefs. La méthode hashCode et equals. La méthode hashCode est la méthode permettant de calculer la clef de hachage. Notons que la classe Object ou bien encore String ont cette méthode. La méthode equals est une méthode permettant de comparer deux objets :
egal = personne.equals(individu) ;
Cette méthode est implantée dans les classes Object, String ainsi que dans de nombreuses autres classes. Par défaut, deux objets distincts ne sont pas égaux. Il faut parfois redéfinir la méthode. Par exemple, deux objets livres sont identiques si leurs identifiants sont égaux.
Description de la classe HashTable
Cette section présente la description du composant Hashtable.
Constructeurs

Hashtable () : construit une table vide.
Quelques méthodes

Nom méthodeRôlevoid clear()Oter tous les éléments de la table.boolean containsKey(Object clef)Vrai si l’objet ayant comme clef clef est dans la table.boolean containsValue(Object valeur)Vrai si la table de hachage peut trouver au moins une clef associée à l’objet valeur.Enumeration elements()Ensemble des valeurs contenues dans la table retourné sous la forme d’une énumération.Object get(Object clef)Renvoyer l’objet valeur associé à clef.boolean isEmpty()Vrai si la table est vide.Enumeration keys()Ensemble des clefs contenues dans la table retourné sous la forme d’une énumération.void put(Object clef, Object valeur) Insérer l’objet valeur dans la table, l’identifiant de l’objet est clef.Object remove(Object clef)Retirer l’objet ayant pour identifiant clef de la table. La valeur renvoyé est la valeur associé à la clef.int size()Nombre de clefs dans la table.
Exemple :
Hashtable maTable ;
maTable = new Hashtable() ;
livre = new Roman(…) ; recueil = new Recueil(…) ; illustre = new BandeDessinee(…) ;
maTable.put(livre.getNoISBN(),livre) ; maTable.put(recueil.getNoISBN(),recueil) ; maTable.put(illustre.getNoISBN(),illustre) ;
Pour parcourir l’ensemble de la table de hachage, il faut tout d’abord disposer de la liste des clefs pour ensuite accéder à tous les objets de la table. L’accès s’effectue avec la méthode keys(). Cette méthode retourne une énumération (Enumeration).
Une énumération est une interface pour accéder aux éléments de manière séquentielle : elle propose deux méthodes 
Une méthode pour accéder à un élément et passer au suivant (nextElement)
Une méthode pour vérifier qu’il y ait des éléments dans la liste (hasMoreElement)
Par exemple, pour parcourir la table de hachage
for (Enumeration e = maTable.keys() ;
e.hasMoreElements() ;) {

System.out.println((Ouvrage)maTable.get(e.nextElement()).getNomTitre()));
}

Description de l’interface Enumeration
Cette section présente la description de l’interface Enumeration. Cette interface permet d’accéder à des séquences d’objets sans se préoccuper du format interne des données et de l’ensemble des données. On peut aussi bien demander une énumération à une table de hachage qu’à un vecteur par exemple. Elle permet de parcourir une séquence sans considérer la structure de la séquence.
Les méthodes

Nom méthodeRôleboolean hasMoreElements()Vrai s’il y a encore des éléments dans l’énumération.Object nextElement()Retourne l’élément suivant.
Exercice
Il s’agit de représenter une mini base documentaire cinématographique. Nous nous limitons à présenter un répertoire de réalisateurs et pour chacun des réalisateurs leur filmographie.
Exemple :
Réalisateur : Sergio Leone, Italien, parfois crédité sous le nom « Bob Roberson »
Filmographie :
Il était une fois dans l’ouest (1969)
Pour une poignée de dollars (1965)
Il était une fois en Amérique (1984)
Pour un réalisateur, nous avons les informations suivantes :
Nom, prénom, nationalité, nom auxiliaire et prénom auxiliaire.
Nous supposerons qu’il n’y a pas deux réalisateurs avec le même nom et prénom. Un second nom de crédit désigne le même réalisateur. Pour un film, les informations manipulées sont le titre du film et l’année de réalisation. Nous avons une structure de données semblable à :
Réalisateur ( Filmographie.
Construire une application permettant de stocker la base filmographique à l’aide d’une table de hachage. Dans un premier temps, vous vous limiterez à définir une méthode pour insérer la filmographie d’un réalisateur ainsi que sa fiche descriptive.
Vous étendrez ce travail en implantant une méthode permettant de complèter la filmographie d’un metteur en scène : on « informe » la base que nous souhaitons ajouter la fiche suivante à notre base :
Nom, prénom, film, année (le nom et le prénom peuvent être auxiliaires).
A faire
Compléter le programme en ajoutant un interface graphique. Cette interface combine deux listes : une première liste où sont présentés les réalisateurs et une seconde liste asservie à la première et présentant la filmographie du réalisateur sélectionné. Vous implanterez cette interface en vous conformant à l’architecture modèle-vue-contrôleur.
Ce qu’il faut retenir
L’accès rapide aux données avec des tables de hachage.
Le structure abstraite Enumeration.
Vos Notes



TP n° 10 : Arbres, récursivité
Les arbres permettent de représenter des données structurées de manière hiérarchique. L’organisation des documents en dossiers et sous-dossiers en est un bon exemple. Les données sont organisées selon une relation de parenté. La relation de parenté associe des nœuds parents à des nœuds fils. Un nœud contient une donnée.
Chaque nœud parent peut avoir un ou plusieurs fils, le nombre de fils n’étant défini préalablement. Citons par exemple, un diagramme d’héritage entre classes. Une autre hypothèse consiste à fixer préalablement le nombre de fils. Si le nombre de fils est fixé à n, on parlera alors d’arbres n-aires. Citons par exemple, un arbre de décision.


Dans ce chapitre, nous nous focalisons uniquement sur les arbres binaires. Les arbres binaires sont des arbres ou chaque parent a au plus deux fils.

L’une des utilisations les plus usuelles des arbres en informatique concerne la représentation de données ordonnées. Lorsqu’on utilise un arbre binaire pour représenter des données triées, le nœud parent représente une valeur médiane (relativement aux deux fils). Le fils gauche représente une valeur « plus petite » que le parent et le nœud fils droit représente une valeur « plus grande » que le nœud parent.
Plus généralement, les fils gauche et droit jouent eux-mêmes le rôle de parents et ont donc eux aussi des fils droit et gauche. On parlera alors de sous-arbre et sous-arbre gauche. Si nous revenons au problème de tri des données, nous avons toutes les valeurs du sous-arbre gauche inférieure à la valeur du nœud parent et toutes les valeurs du sous-arbre droit sont des valeurs supérieures au nœud parent.
Si, nous représentons la séquence de données suivante
Haddock, Tournesol, Tintin, Dupond, Milou, Dupont
dans un arbre binaire, nous obtenons (le choix de l’élément central est arbitraire)
 EMBED OrgPlusWOPX.4 
Spécification d’un arbre
Comme nous l’avons évoqué précédemment, un arbre est composé
Un nœud parent
Un sous-arbre gauche (éventuellement)
Un sous-arbre droit (éventuellement)

Les sous-arbres gauche et droit sont en fait des arbres. Autrement dit un arbre est une structure dont la définition fait appel à elle-même. C’est une structure de données récursives. Intuitivement nous obtenons :
class Arbre {
private ClasseDonnee donnee ;
private Arbre sousArbreGauche ;
private Arbre sousArbreDroit ;
}
Sur cette donnée, nous allons définir des méthodes :
Des méthodes pour insérer des éléments dans l’arbre.
Des méthodes pour accéder aux nœuds de l’arbre.
Quand nous créons un arbre, nous créons tout d’abord un le nœud parent puis ensuite les nœuds droit ou gauche si besoin. Nous en déduisons le constructeur : il initialise la donnée et prépare les nœuds fils.
public Arbre(ClasseDonnee d) {
donnee = d ; sousArbreGauche = null ; sousArbreDroit = null ;
}

Sachant créer un arbre nous pouvons maintenant détailler les méthodes. Comme nous l’avons préciser, nous devons définir une méthode, ou plusieurs, méthode(s) pour insérer un éléments dans l’arbre. Cette élément va être inséré à gauche ou à droite. Pour insérer un élément à gauche, il faut tout d’abord vérifier que celui est vide pour ensuite créer un sous-arbre. Le raisonnement est identique pour le sous-arbre droit. Autrement dit, nous avons quatre méthodes à notre disposition :
abstract boolean insererDonnee(ClasseDonnee donnee) ;
abstract boolean estVideSousArbreGauche() ;
abstract boolean estVideSousArbreDroit() ;
abstract void creerSousArbreGauche(ClasseDonnee donnee) ;
abstract void creerSousArbreDroit(ClasseDonnee donnee) ;
Supposons maintenant que sous-arbre gauche et le sous-arbre droit soient définis. Dans ce cas, nous devons essayer d’insérer de créer un sous-sous-arbre, c’est-à-dire créer un sous-arbre dans le sous-arbre gauche ou créer un sous-arbre dans le sous-arbre droit. Autrement dit, la méthode pour insérer les données suit la trame suivante :
SI estVideSousArbreGauche() = vrai
CreerSousArbreGauche(donnee)
SINON
SI estVideSousArbreDroit() = vrai
CreerSousArbreDroit(donnee)
SINON
sousArbreGauche.insererDonnee(donnee) ou
sousArbreDroit.insererDonnee(donnee)
FIN SI
FIN SI

Dans la troisième éventualité, il faut choisir où va se faire l’insertion. Le choix représente la politique de construction de l’arbre.
Dans le contexte où l’arbre doit être ordonné, nous obtenons comme algorithme :
SI donnee < this.donnee
SI estVideSousArbreGauche() = vrai
CreerSousArbreGauche(donnee)
SINON
sousArbreGauche.insererDonnee(donnee)
FIN SI
FIN SI

SI donnee > this.donnee
SI estVideSousArbreDroit() = vrai
CreerSousArbreDroit(donnee)
SINON
sousArbreDroit.insererDonnee(donnee)
FIN SI
FIN SI

Exercice
Créer un mini-répertoire contenant une liste de personnes. Chaque personne a un nom et un prénom. Le répertoire est représenté sous une forme arborescente. L’arbre permettra ainsi de conserver un ordre permanent et d’obtenir un accès rapide aux informations.
Vous définirez une méthode permettant de savoir si un élément est présent dans l’arbre.
Vous définirez une méthode pour parcourir tous les éléments de l’arbre (ceci permettra une vérification aisée de la bonne exécution de l’insertion des éléments dans l’arbre).
A faire
Compléter le programme en ajoutant une méthode pour ôter un élément de l’arbre.
Compléter le programme en y ajoutant une interface graphique. Vous pouvez utiliser à cet effet le composant Swing JTree. Ce composant permet de représenter visuellement des arbres (exemple : arborescence de documents). L’architecture modèle-vue-contrôleur s’appliquant à ce composant, il est conseillé de créer un modèle (classes TreeModel et DefaultTreeModel).
Couplage d’un vecteur et d’un arbre : les données sont stockées dans le vecteur (sans tri particulier) et l’arbre contient uniquement les clefs et index des éléments du vecteur. Comment coupler ces deux ensembles de données ?
Ce qu’il faut retenir
La structure récursive des arbres.
Le couplage entre des structures de données évoluées et sa visualisation (cf. à faire).
Vos Notes



Quelques Références
Le site de référence de Sun :
 HYPERLINK http://java.sun.com/docs/books/tutorial/ http://java.sun.com/docs/books/tutorial/
Un cours en français :
 HYPERLINK http://www.inf.enst.fr/~charon/coursJava/index.html http://www.inf.enst.fr/~charon/coursJava/index.html
et un autre :
 HYPERLINK http://www.eteks.com/ http://www.eteks.com/
un ouvrage en ligne assez complet (plus de 1000 pages et en anglais) :
 HYPERLINK "http://www.mindview.net/Books/TIJ/" http://www.mindview.net/Books/TIJ/
un site de référence en anglais contenant de nombreux programmes et renseignements (en anglais) :
HYPERLINK "http://www.gamelan.com/"http://www.gamelan.com/





 La notion de paquetage fera l’objet d’une section plus détaillée dans un chapitre ultérieur.
 Les sous-classes et les notions d’héritage seront aussi détaillées dans un chapitre ultérieur.
 Cf. ci-après.
 Excepté si le type est « emballé » dans un objet correspond à sa classe : classe Integer, Float, Boolean,…
 Les vecteurs et tableaux sont des structures à accès séquentiels.

PAGE 1


( Page  PAGE 17

( Page  PAGE 1

PAGE 1


( Page  PAGE 63

( Page  PAGE 64


 EMBED Word.Picture.8 

Client Dupond
Toulouse
01.01.01.01.01
liste des commandes

Commande 2
Ligne 1
Ligne 2

Commande 1
Ligne 1
Ligne 2

…


Article 1
Quantité (20)

Article 2
Quantité (4)

Les composants du projet (classes et documentation)

La description du projet

0..*

Option de fermeture de la console

Valeur affichée par le programme

1..*

1..1

Nom de la classe fenêtre

Nom de la classe Programme

Informations complémentaires

Titre de la classe fenêtre

L’éditeur de propriétés

La fenêtre WinParking à définir

Panneau d’entête (GridLayout)

Panneau total (FlowLayout)

Panneau détail contenant deux panneaux

Choix de l’événement

Onglet proposant les événements possibles

Voitures

VoituresCarburant

VoituresElectriques

Diesel

SansPlomb

1..*

1..1

 EMBED Word.Picture.8 

 EMBED Word.Picture.8 

1..*

0..*

1..*

noCde : String

Commande

telephone : String

ville : String

nom : String

Client

Article

qte : Integer

LigneCommande