Vous êtes sur la page 1sur 191

Programmation

orientée Objet Java


2ème Partie (Java avancé)

Pr ADG
UADB - 2021
Plan du cours
v Chapter 1: Rappel sur les Exceptions
v Chapter 2: Threads
v Chapter 3: Interfaces graphiques
v Chapter 4: JDBC
v Chapter 5: Collections
v Chapter 6: Fichiers
v Chapter 7: Programmation réseau: Sockets
v Chapter 8: Applications distribuées avec RMI

2
Chapitre 1: Les Exceptions

3
Exceptions
q Souvent, un programme doit traiter des situations exceptionnelles qui
n’ont pas un rapport direct avec sa tâche principale
q Ceci oblige le programmeur à réaliser de nombreux tests avant d’écrire les
instructions utiles du programme
q Cette situation a deux inconvénients:
§ le programmeur peut omettre de tester une condition
§ le code devient illisible car la partie utile est masquée par les tests
q Java remédie à cela en introduisant un mécanisme de gestion des
exceptions
q Grâce à ce mécanisme, on peut améliorer la lisibilité du code en séparant:
§ le code utile (code métier)
§ de celui qui traite des situations exceptionnelles

4
Hiérarchie des exceptions

q Java peut générer deux types d’erreurs au moment de


l’exécution:
§ Des erreurs produites par l’application dans des cas
exceptionnels que le programmeur devrait prévoir et
traiter dans son application. Ces genres d’erreur sont de
type Exception
§ Des erreurs qui peuvent être générées u niveau de la JVM
et le programmeur ne peut prévoir dans son application.
Ces types d’erreurs sont de type Error
5
6
Les Exceptions

q En java, on peut classer les exceptions en deux catégories:


§ Les exceptions surveillées
§ Les exceptions non surveillées
q Java oblige le programmeur à traiter les erreurs surveillées.
Elles sont surveillées par le compilateur
q Les erreurs non surveillées peuvent être traitées ou non. Et
ne sont pas signalées par le compilateur

7
Un premier exemple
q Considérons une application qui permet de:
§ saisir au clavier deux entiers a et b
§ Faire appel à une fonction qui permet de calculer et de retourner a divisé par b
§ affiche le résultat
Import java.util.Scanner;
public class App1 {
public static int calcul (int a, int b) {
int c =a/b;
return c;
}

8
Un premier exemple
public static void main (String[] args) {
Scanner cl =new Scanner (System.in);
System.out.println("Donner a: "); int a =cl.nextInt();
System.out.println("Donner b: "); int b =cl.nextInt();
int result=calcul(a,b);
System.out.println(" Résultat=" + result);
}
}

9
Exécution
Donner a: 12
Donner b: 0

10
Un bug dans l’application
Une erreur fatale s’est produite dans l’application au moment de
l’exécution
q Cette exception est de type ArithmeticException. Elle concerne une
division par zéro
q Cette exception n’a pas été traitée dans calcul. Elle remonte ensuite
vers main dont elle n’a pas été traitée non plus.
q Après l’exception est signalée à la JVM. Cette dernière arrête
l’exécution de l’application, ce qui constitue un bug fatal

11
Traiter l’exception
q Pour traiter les exceptions, on doit utiliser le bloc try catch de la manière suivante
Import java.util.Scanner;
public class App1 {
public static int calcul (int a, int b) {
int c =a/b;
return c;
}
public static void main (String[] args) {
Scanner cl =new Scanner (System.in);
System.out.println("Donner a: "); int a =cl.nextInt();
System.out.println("Donner b: "); int b =cl.nextInt();
int result=0;
try {
result= calcul (a, b);
}
catch( ArithmeticException e) { System.out.println(" Division par zero"); }

System.out.println(" Résultat=" + result);


}
}
12
Principales méthodes d’une Exception
Tous les types d’exceptions possèdent les méthodes suivantes:
q getMessage(): retourne le message de l’exception
System.out.println (e.getMessage());
Résultat affiché: /by zero
q toString(): retourne une chaine qui contient le type d’exception et le
message de l’exception
System.out.println (e.toString());
Résultat affiché: java.lang.ArithmeticException

q printStackTrace: affiche la trace de l’exception


e.printStackTrace();
Résultat affiché:
java.lang.ArithmeticException:/by zero
at App1.calcul (App1.java:4)
at App1.main (App1.java:13)
13
Exemple: Générer, Relancer ou Jeter une
exception surveillée de type Exception
Considérons le cas d’un compte qui est défini par un code et un solde et sur lequel, on peut verser un montant,
retirer un montant et consulter le solde
public class Compte {
private int code;
private float solde;
public void verser (float mt) {
solde=solde+mt;
}
public void retirer (float mt) throws Exception {
if (mt>solde) throw new Exception (" Solde insuffisant");
solde=solde-mt;
}
public float getSolde() {
return solde;
}
} 14
Utilisation de la classe Compte
En faisant appel à la méthode retirer, le compilateur signale que cette dernière peut générer une exception de type Exception
C’est une exception surveillée. Elle doit être traitée par le programmeur
Import java.util.Scanner;
public class Application {
public static void main (String[]args) {
Compte cp=new Compte ();
Scanner clavier=new Scanner (System.in);
System.out.println(" Montant à verser: ");
float mt1=clavier.nextFloat();
cp.verser(mt1);
System.out.println(" Solde actuel:" +cp.getSolde());
System.out.println(" Montant à retirer:");
float mt2=clavier.nextFloat();
cp.retirer(mt2); // Le compilateur signe l’exception
}
}

15
Traiter l’exception
Deux solutions:
q Soit utiliser le bloc try catch
try {
cp.retirer (mt2);
} catch (Exception e) {
System.out.println (e.getMessage ());
}

q Ou déclarer que cette exception est ignorée dans la méthode main et


dans ce cas, elle remonte vers le niveau supérieur. Dans notre cas la JVM
public static void main (String[] args) throws Exception {
16
Exécution de l’exemple
Import java.util.Scanner;
public class Application {
public static void main (String[]args) {
Compte cp=new Compte ();
Scanner clavier=new Scanner (System.in);
System.out.println(" Montant à verser: ");
float mt1=clavier.nextFloat();
cp.verser(mt1);
System.out.println(" Solde actuel:" +cp.getSolde());
System.out.println(" Montant à retirer:");
float mt2=clavier.nextFloat();
try {
cp.retirer(mt2);
} catch (Exception e) {
System.out.println (e.getMessage());
}
System.out.println (" Solde Final=" +cp.getSolde()-;
}
17
Exécution de l’exemple
Scénario 1:
Montant à verser: 5000
Solde Actuel: 5000.0
Montant à retirer:2000
Solde Final=3000.0

Scénario 2:
Montant à verser: 5000
Solde Actuel: 5000.0
Montant à retirer:7000
Solde Insuffisant
Solde Final=5000.0
18
Exemple: Générer une exception non surveillée
de type RuntimeException
public class Compte {
private int code;
private float solde;
public void verser (float mt) {
solde=solde+mt;
}
public void retirer (float mt) {
if (mt>solde) throw new RuntimeException(" Solde insuffisant");
solde=solde-mt;
}
public float getSolde() {
return solde;
}
}

19
Utilisation de la classe Compte
En faisant appel à la méthode retirer, le compilateur ne signale rien
C’est une exception non surveillée. On est pas obligé de la traiter pour que le programme soit compilé
public class Application {
public static void main (String[]args) {
Compte cp=new Compte ();
Scanner clavier=new Scanner (System.in);
System.out.println(" Montant à verser: ");
float mt1=clavier.nextFloat();
cp.verser(mt1);
System.out.println(" Solde actuel:" +cp.getSolde());
System.out.println(" Montant à retirer:");
float mt2=clavier.nextFloat();
cp.retirer(mt2); // Le compilateur signe l’exception
}
}
20
Personnaliser les exceptions métier
q L’exception générée dans la méthode retirer, dans le cas où le solde
est insuffisant est une exception métier
q Il est plus professionnel de créer une nouvelle exception nommée
SoldeInsuffisantException de la manière suivante:
public class SoldeInsuffisantException extends Exception{
public SoldeInsuffisantException (String message) {
super (message);
}
}
qEn héritant de la classe Exception, nous créons une exception
surveillée
qPour créer une exception non surveillée, vous pouvez hériter de la
classe RuntimeException
21
Chapitre 2: THREADS JAVA
Threads Java

Un thread est un "processus léger" en cours d’exécution dans un programme.


Cette unité d’exécution fonctionne de façon autonome parallèlement à d’autres threads
(ie à d’autres traitements).
Les threads sont donc des traitements qui vivent au sein d’un même processus.
Dans un système monoprocesseur, à chaque tâche, il est attribué des quantum de temps
au cours desquels les ressources systèmes leur sont entièrement données pour accomplir
leurs traitements.
Les threads partagent la même mémoire contrairement aux processus.

Le grand avantage de l’utilisation des threads est de pouvoir répartir différents


traitements d’un même programme en plusieurs processus distincts pour permettre
leur exécution « simultanée ».

La classe java.lang.Thread et l’interface java.lang.Runnable sont les bases du


développement des threads. 23
Principes de base des threads

Les threads peuvent être créés comme instance d’une classe dérivée de la
classe Thread. Elles sont lancées par la méthode start ( ) (pour allouer
les ressources système nécessaires), qui demande à
l’ Ordonnanceur de threads de lancer la méthode run ( ) du thread.
La méthode run ( ) doit être implantée dans le programme.
Le schéma ci-après illustre les temps d’exécution et de latence des threads:

Thread 1

Thread 2

Thread 3

Thread 4
24
Types de threads

En Java, on distingue deux grandes catégories de threads: ceux dits utilisateurs


et les démons.

Les threads utilisateurs se terminent lorsque les instructions dans le corps de leur
méthode run ( ) sont toutes exécutées.

Un thread démon continue indéfiniment si aucune précaution n’a été prise pour
l’arrêter.

Nous commencerons par étudier les threads dits utilisateurs pour terminer sur
une analyse portant sur les threads démons.

25
Cycles de vie d’un Thread (1/2)

Un thread peut être dans 4 états différents:

État nouveau C’est l’état initial après l’instanciation du thread. Le thread est
opérationnel mais n’est pas encore actif. Un thread prend toujours cet
état après son instanciation.

État exécutable Un thread est dans cet état à partir du moment où il a été lancé par la
méthode start ( ) et le reste tant qu’il n’est pas sorti de la méthode
run ( ) . Le système donnera du temps d’exécution à votre thread dès
qu’il le pourra.
Il s’agit de thread qui n’exécute aucun traitement et ne consomme
État en attente aucune ressource CPU. Il existe plusieurs manières de mettre un
thread en attente:
- appeler la méthode Thread.sleep ( long temps_en_millisecondes)
- appeler la méthode wait ( )
- appeler une ressource bloquante (flux, accès base de données, …) 26
- accéder à une instance sur laquelle un verrou a été posé
Cycles de vie d’un Thread (2/2)

État mort Il s’agit d’un thread qui est sorti de sa méthode run ( ) soit de façon
naturelle, soit de manière subite (exception non interceptée).

Regardons maintenant comment créer des threads avec l’instanciation d’objets


de la classe java.lang.Thread .
Nous verrons par la suite comment créer également un thread avec l’interface
Runnable. Cette dernière permettra de créer des threads de classe qui dérive
déjà d’une autre classe (l’héritage multiple étant interdit en Java).

En programmation WEB (avec les applets) il faudra recourir à cette interface.

27
Constructeurs de Thread

La classe Thread dispose de plusieurs constructeurs que vous pouvez utiliser


aisément pour instancier des objets threadés:
/*crée un Thread dont le nom est généré automatiquement (aléatoirement)*/
public Thread ( )
/*target est le nom de l’objet dont la méthode run ( ) est utilisée pour
lancer le thread*/
public Thread (Runnable target )
/*on précise l’objet et le nom du thread*/
public Thread (Runnable target, String name)
/*on ne précise que le nom du thread*/
public Thread (String name)
Il existe aussi des constructeurs de groupe de Threads que nous allons voir plus tard.

28
Méthodes de la classe Thread

/*met fin au thread brutalement, à n’utiliser qu’en dernier recours*/


void destroy ( )
/*renvoie la priorité du thread*/
int getPriority ( )
/*retourne le nom du thread*/
String getName( )
/*pour interrompre le thread*/
void interrupt ( )
/*teste si le thread courant a été interrompu*/
static boolean interrupted ( )
/*attendre la mort du thread*/
void join ( ) | void join (long millis) | void join (long millis, int nanos)
/*redémarre le thread :cette méthode est DEPRECIEE*/
void resume ( )
/*méthode contenant le code à exécuter par le thread*/
void run ( )
29
Méthodes de la classe Thread

/*changer la priorité du thread*/


void setPriority (int newpriotity)
/*mettre en veille le thread*/
static void sleep (long millis) | static void sleep (long millis, int nanos)
/*démarre l’exécution du thread*/
void start ( )
/*renvoie le nom du thread, sa priorité et le groupe auquel il appartient*/
String toString ( )
/*renvoie un booléen qui indique si le thread est actif ou non*/
boolean isAlive ( )
/*renvoie un objet qui encapsule le groupe auquel le thread appartient*/
ThreadGroup getThreadGroup ( )
/*indique à l’interpréteur que le thread peut être suspendu pour permettre à
d’autres threads de s’exécuter*/
void yield ( )

30
Premier Thread avec java.lang.Thread

(programme qui simule l’exécution de deux threads)

public class FirstThread extends Thread { sortie

FirstThread (String name) { 0 thread 1


super (name ); 0 thread 2
} 1 thread 1
public void run ( ) { // code à exécuter par chaque thread 1 thread 2
try { for ( int i = 0;i < 5; i++) 2 thread 1
{ System.out .println (i+" "+ this.getName ( ) ) ; 2 thread 2
Thread.sleep ((int) Math.random ( )*10) ;// mise en attente 3 thread 1
} 3 thread 2
} 4 thread 1
catch (InterruptedException e) { } 4 thread 2
}
public static void main(String [ ] args) {
new FirstThread("thread 1").start ( ) ; //le code lancé par start ( ) est le code de run ( )
new FirstThread("thread 2").start ( ) ;
} 31
Notes

Un appel de la méthode start ( ) dans une instruction de la forme new FirstThread("thread 1").start ( ) ;
assure qu’un thread sera bien pris en compte par la machine virtuelle et par le système d’exploitation
puis lance l’exécution de la méthode run ( ) de l’objet thread correspondant.

L’usage de la méthode statique sleep (long millis) nous permet de voir que les deux threads s’exécutent
en apparente simultanéité.
Cette méthode peut lever une exception de type InterruptedException qu’il faut donc intercepter et
capturer.

La méthode start ( ) ne peut être appelée qu’une une seule fois pour un thread donné, sinon une
exception de type IllegalThreadStateException est levée.

Il est possible d’appeler la méthode run ( ) pour chaque thread mais cela entraîne l’exécution complète
du thread 1 puis celle complète du thread 2.
L’appel de sleep entraînerait alors l’exécution d’autres threads autres que ceux–ci, donc ralentissement
de l’exécution de notre programme. 32
Deuxième Thread avec java.lang.Runnable
(le premier exemple réalisé ici avec l’interface Runnable)

public class SecondThread implements Runnable { sortie


String name;
SecondThread(String name){ 0 thread 1
this.name = name ); } 0 thread 2
public void run ( ) { // code à exécuter par chaque thread 1 thread 1
try { for ( int i = 0;i < 5; i++) 1 thread 2
{ System.out .println (i+" "+ this ) ; 2 thread 1
Thead.sleep ((int) Math.random ( )*10) ;// mise en attente 2 thread 2
} 3 thread 1
} 3 thread 2
catch (InterruptedException e) { } 4 thread 1
} 4 thread 2
public static void main(String [ ] args) {
SecondThread t1 = new SecondThread("thread 1") ;
SecondThread t2 = new SecondThread("thread 2") ;
Thread thread1 = new Thread (t1); thread1.start ( ) ;
Thread thread2 = new Thread (t2); thread2.start ( ) ; } 33
Notes

Avec cet deuxième exemple, pour lancer l’exécution d’un thread, nous sommes
dans l’obligation d’instancier un objet de la classe implémentant Runnable:
SecondThread objetRun = new SecondThread ("thread 1");. 1

Mais cet objet n’est pas de type Thread, c’est pourquoi on ne peut pas lui appliquer
directement la méthode start ( ), il faut absolument l’enroller dans un autre objet
de type Thread pour pouvoir lancer son exécution via l’appel de start ( ).

Thread thread1 = new Thread (objetRun );


thread1.start ( );
Mais il est tout à fait possible, à partir de 1 de faire objetRun.start ( ). Il faut alors au
préalable implémenter la méthode start ( ) dans la classe comme ceci:
public void start ( ) {
Thread t = new Thread (this);
t.start ( ) ;} 34
0 thread 1
Interruption des Threads 0 thread 2
1 thread 1
1 thread 2
(bloquer un thread pour laisser un autre continuer) 2 thread 1
public class TestInterrupt extends Thread { 3 thread 1
long attente; 2 thread 2
TestInterrupt (String name, long attente) 4 thread 1
{ super(name); this.attente = attente;} thread 1 interrompu true
public void run( ){ 3 thread 2
try { for (int i = 0;i < 10;i++) thread 1 redémarré
{ System.out .println (i+ " "+this.getName ( ) ) ; Thread.sleep (attente) ; 5 thread 1
if (i = = 4) 6 thread 1
7 thread 1
{this.interrupt ( );boolean trv = this.isInterrupted ( );
4 thread 2
System.out .println (this.getName() +" "+"interrompu "+ trv) ;
8 thread 1
}
thread 2 interrompu true
if (this.isInterrupted ( ))
9 thread 1
{ this.interrupted ( ) ;
thread 2 redémarré
System.out .println (this.getName ( ) +" "+"redémarré") ;
5 thread 2
}}}
6 thread 2
catch (InterruptedException e) { }
7 thread 2
}
8 thread 2
public static void main(String[] args) {
9 thread 2
new TestInterrupt ("thread 1",5).start ( ) ; 35
new TestInterrupt ("thread 2",10).start ( ) ; }}
Notes importantes

L’interruption d’un thread se contente d’attirer son attention.


L’appel de la méthode interrupt ( ) n’entraîne pas automatiquement
Attention l’interruption du thread courant . Il ne s’agit qu’une demande.
Cette méthode entre en vigueur que si le thread entre en
sommeil ou et en attente (via l’appel de sleep (…) ou wait (…)).

Comme la méthode interrupt( ) ne fait que placer un indicateur


de demande d’arrêt, il est tout à fait bon de connaître l’état de
celui-ci à un instant donné en appelant la méthode isInterrupted ( ).
Si la méthode interrupt ( ) a été appelée pendant que le thread
n’était pas en sommeil ou en attente, aucune
InterruptedException ne peut être générée.
La méthode non statique isInterrupted ( ) permet de voir si le
thread correspondant est effectivement interrompu et alors
l’appel de interrupted( ) repositionne l’indicateur à false (pour
redémarrer le thread).
36
java.lang.ThreadGroup

Par défaut un thread appartient (est créé) au groupe (de threads) courant càd
celui qui l’a créé.
Il faut savoir que le premier thread que l’on rencontre est la méthode main.
Par défaut donc, un thread est créé dans ce groupe.

Mais il est possible de créer des groupes de threads autre que le groupe courant, et à
chacun, associé un certain nombre de threads.
Dans ce cas, il sera plus facile d’interrompre un ensemble de threads, en
interrompant simplement le groupe.

Pour cela, on crée une instance de la classe ThreadGroup avec l’un des constructeurs:

ThreadGroup ( String name) // groupe de threads de nom name


ThreadGroup ( ThreadGroup parent, String name) // sous-groupe d’ un autre groupe

37
Thread démon

L’exécution de tels threads peut se poursuivre même après l’arrêt de l’application


qui les a lancés. On dit qu’ils s’exécutent en tâche de fond.

Une application dans laquelle les seuls threads actifs sont des démons est
automatiquement fermée.

Un thread doit toujours être créé comme thread standard, puis il peut être
transformé en thread démon grâce à un appel de la méthode setDaemon( true).
Mais cet appel doit se faire avant le lancement du thread sinon une exception
de type IllegalThreadStateException est levée.
Un thread démon dépend du thread parent qui l’a lancé et s’exécute en arrière plan
de ce dernier.

38
Synchronisation de Threads

(utilisation d’un moniteur (ou sémaphore) pour l’accès à une ressource partagée)

La synchronisation permet de gérer les accès concurrents concernant la


manipulation simultanée de données partagées. Elle permet de sauvegarder
l’intégrité des données.
La synchronisation peut être analysée à deux niveaux:
- le premier niveau a trait à la manipulation de données partagées dans un bloc
- le second niveau permet de sécuriser l’accès au code d’une méthode
La synchronisation utilise la notion de verrou: à un instant donné, une seule méthode
synchronisée peut accéder à un objet donné.
Ceci est dû au fait que pour chaque objet doté d’une méthode synchronisée,
le système pose un verrou (ou clé) unique permettant l’accès à cet objet.
Le verrou est attribué à la méthode (ou bloc) synchronisé et restitué à la sortie de
celui-ci.
Tant que le verrou n’est pas repris par l’environnement, aucune autre méthode
synchronisée ne peut le recevoir et donc ne peut manipuler l’objet associé à l’appel de
cette méthode.
39
Synchronisation de Threads: le Moniteur

(Attribution du verrou par le moniteur)


Le moniteur est utilisé pour synchroniser l’accès à une ressource partagée (qui
peut être un segment de code donné). Un thread accède à cette ressource par
l’intermédiaire de ce moniteur.

Ce dernier est attribué à un seul thread à la fois.

Pendant que le thread exécute la ressource partagée aucun autre thread ne peut y
accéder.
Le thread libère le moniteur dès qu’il a terminé l’exécution du code synchronisé ou bien
s’il a fait appel à la méthode wait ( ) de l’objet.
Il faut faire très attention aux méthodes statiques. Synchroniser de telles méthodes revient
à bloquer le moniteur de la classe ce qui peut être source de performances médiocres
dans certains cas, puisque vous bloquez l’accès à toute la classe.

Un thread détient le moniteur s’il exécute une méthode synchronisée, un bloc synchronisé
ou une méthode statique synchronisée d’une classe.

40
Synchronisation pour un bloc

Ici, il s’agit d’interdire à deux threads différents d’accéder simultanément


à un même objet, en plaçant le mot clé synchronized pour le bloc concerné.

Dans une instruction telle que:


synchronized (expression) { // du code}
où expression repère un objet quelconque, le système Java pose un verrou
sur cet objet pendant l’exécution du bloc. Aucun autre bloc synchronized sur
cet objet APPARTENANT A UN AUTRE THREAD ne peut être exécuté
et un tel bloc ne peut être lancé qu’après avoir obtenu ce verrou.

On définit ainsi une section critique.

41
Premier exemple Synchronisation de bloc (1/5)

Considérons une classe Compte permettant de gérer les comptes de clients dans une
quelconque banque disposant de plusieurs agences.
Pour une gestion efficace et sécurisée des comptes client, il ne faudrait pas permettre
par exemple que deux (au moins) transactions s’effectuent simultanément sur un même
compte à un instant donné (exemple: le retrait et le dépôt).

Les opérations de retrait et de dépôt sont gérées séparément par deux threads distincts.

Notre travail sera de créer ces deux threads de telle sorte qu’ils ne pourront jamais s’
exécuter simultanément.

42
Premier exemple Synchronisation de bloc (2/5)

(Compte.java)

package thread.compte;
public class Compte {
private double solde;
private double decouvert;
public Compte(double solde, double decouvert){
this.solde = solde;
this.decouvert = decouvert;
}
public void deposer (double montant){
this.solde += montant;
}
public void retirer (double montant){
if (montant + decouvert <= solde)
this.solde -= montant;
}
public void imprimeHistorique ( ) {
System.out .println ("votre solde est: "+solde) ; 43
}}
Premier exemple Synchronisation de bloc (3/5)

(ThreadCompteDepot .java)

package thread.compte;
public class ThreadCompteDepot extends Thread {
private Compte c;
private double depot;
public ThreadCompteDepot (String name, Compte c, double depot){
super (name);
this.c =c;
this.depot = depot;
}
public void run ( ){
synchronized (c) { // fondamental: on pose un verrou sur le compte
try {
System.out.print (this.getName ( ) + ":avant le depot: "); c.imprimeHistorique();
c.deposer (this.depot);
Thread.sleep (1000);
System.out.print (this.getName() + ":apres le depot: "); c.imprimeHistorique();
}
44
catch (InterruptedException e) { System.out.println("dépot avorte"); } } }}
Premier exemple Synchronisation de bloc (4/5)

(ThreadCompteRetrait .java)

package thread.compte;
public class ThreadCompteRetrait extends Thread {
private Compte c;
private double retrait;
public ThreadCompteRetrait (String name, Compte c, double retrait){
super (name);
this.c = c;
this.retrait = retrait;
}
public void run ( ){
synchronized (c) { // fondamental: on pose un verrou sur le compte
try {
System.out.print (this.getName ( ) + ":avant le retrait:"); c.imprimeHistorique();
c.retirer (this.retrait);
Thread.sleep (1000);
System.out.print (this.getName() + ":apres le retrait:"); c.imprimeHistorique();
}
45
catch (InterruptedException e) { System.out.println("retraitt avorte"); } } }}
Premier exemple Synchronisation de bloc (5/5)

(TestThreadsCompte .java)

package thread.compte; Le choix du thread à exécuter


en premier lieu est aléatoire,
public class TestThreadsCompte { les deux threads étant de
public static void main(String [ ] args) { même priorité.
Compte c = new Compte (5000,100) ;
ThreadCompteRetrait tcr = new ThreadCompteRetrait ("retrait",c,2000);
ThreadCompteDepot tcd = new ThreadCompteDepot ("depot",c,1500);
tcr.start ( ) ;
retrait: avant le retrait votre solde est: 5000.0
tcd.start ( ) ; } BON retrait: apres le retrait votre solde est: 3000.0
}
depot: avant le depot: votre solde est: 3000.0
depot: apres le depot: votre solde est: 4500.0

retrait:avant le retrait votre solde est: 5000.0 Si vous ne synchronisez pas le Compte
depot:avant le depot: votre solde est: 3000.0 dans les deux threads, vous aurez un
retrait: apres le retrait votre solde est: 4500.0 solde erroné .
depot:apres le depot: votre solde est: 4500.0 46
Deuxième Exemple de bloc synchronisé

On considère une classe qui permet d’inverser les éléments d’un tableau d’entiers.
Mais avant que l’inversion ne se fasse, les éléments du tableau doivent être incrémentés
d’une valeur égale à l’indice de l’élément en cours. Et après, l’inversion pourra se faire
après un certain délai.
On disposera d’une méthode affiche qui nous permettra d’envoyer sur la console
les éléments du tableau inversé.
Mais ici, nous avons un problème à gérer:
Avant que la méthode affiche n’accède au tableau pour l’afficher, il faudra que la
méthode qui se charge de l’incrémentation et de l’inversion finisse carrément son
travail, sinon l’affichage sera complètement faux.

Regardons maintenant comment on peut passer d’un mauvais exemple vers un cas où
les données seront correctes.

47
Exemple de bloc NON synchronisé (1/4)

(la classe qui gère l’inversion et l’affichage du tableau)

class TabInverse {
int tabres [ ];
int [ ] inverse (int tableau [ ])
{ tabres = new int [tableau.length ];

for (int i = 0; i < tableau.length; i++) tableau [i]+=i;


try {Thread.sleep (1000) ;} // pour marquer une pause entre l’incrémentation
catch (InterruptedException er) { }// et l’inversion des éléments du tableau
for (int i = 0;i < tableau.length ;i++)
tabres [tableau.length -i-1] = tableau[i];
return tabres;
}
void affiche (int t [ ] ){
for (int i = 0 < t.length ;i++)
System.out .print (t[i]+":::::") ;
}
}
48
Exemple de bloc NON synchronisé (2/4)

/*cette classe permet de créer un thread qui n’accédera qu’à la methode inverse
Cet objet peut donc manipuler simultanément le tableau qu’un autre thread */
class EssaiSynchroInverse extends Thread{
TabInverse inv;
int tab[ ];
public EssaiSynchroInverse (String name, TabInverse inv, int tab [ ] )
{ super (name);
this.inv = inv;
this.tab = tab;
}
public void run ( )
{System.out .println (this.getName ( ) ) ;
inv.inverse (tab) ;
try {Thread.sleep (1000) ;}
catch (InterruptedException er) { }
System.out .println("FIN de "+this.getName ( ) ) ;
}} 49
Exemple de bloc NON synchronisé (3/4)

/*cette classe permet de créer un thread qui n’accédera qu’à la methode affiche
Cet objet peut donc manipuler simultanément le tableau qu’un autre thread */
class EssaiSynchroAffiche extends Thread{
TabInverse inv;
int tab[ ];
public EssaiSynchroAffiche (String name, TabInverse inv, int tab[] )
{ super (name);
this.inv = inv;
this.tab = tab;
}
public void run ( )
{ System.out .println (this.getName ( ) ) ;
inv.affiche (tab) ;
try {Thread.sleep(1000) ;}
catch (InterruptedException er) { }
System.out .println ("FINITION de "+ this.getName ( ) ) ;
}} 50
Exemple de bloc NON synchronisé (4/4)

/*pour tester l’accès simultané à un même objet tableau*/ ThreadInv


public class TestSynchroBloc { ThreadAff
static int t [ ] = {1,2,3,4,5}; 0::0::0::0::0::
public static void main (String [ ] args) { FINITION de ThreadAff
TabInverse ti = new TabInverse ( ); FIN de ThreadInv

EssaiSynchroInverse es = new EssaiSynchroInverse("ThreadInv",ti, t);


EssaiSynchroAffiche ess = new EssaiSynchroAffiche("ThreadAff",ti, t);
es.start ( ) ;
Ici, on crée deux threads es et ess qui accèdent au tableau t
ess.start ( ) ;
} simultanément. Le thread ess va vouloir afficher un résultat qui
} n’est pas encore entièrement connu, puisque es n’a pas terminé
l’incrémentation et l’inversion.
Le résultat affiché sera donc erroné.

Pour corriger ce défaut, il faut poser un verrou sur l’objet tableau partagé… 51
Deuxième Exemple de bloc synchronisé

(voici comment il faut implémenter la classe TabInverse)


Résultat attendu
class TabInverse {
int tabres [ ]; ThreadInv
int [ ] inverse (int tableau [ ]) ThreadAff
{ tabres = new int [tableau.length ]; 9::7::5::3::1::
synchronized (tableau) { // verrouillage du tableau FINITION de ThreadAff
FIN de ThreadInv
for (int i = 0;i < tableau.length ;i++) tableau [i]+=i;
try {Thread.sleep (1000) ;}
catch (InterruptedException er) { }
for (int i = 0;i < tableau.length ;i++)
tabres [tableau.length -i-1] = tableau[i];
}
return tabres;}
void affiche (int t [ ] ){
synchronized (t) {
for (int i = 0 < t.length ;i++) System.out .print (t[i]+":::::") ;
52
} }}
Synchronisation de méthodes

Chaque fois que deux threads s’exécutent en même temps, il faut souvent prendre des
mesures adéquates pour qu’ ils n’accèdent pas simultanément à une même variable.

Le principe d’exclusion mutuelle doit être assuré sur le partage simultané d’objet
(pour assurer la cohérence des données) par l’utilisation de méthodes dites synchronisées.
Ce principe est assuré lorsqu’une méthode est déclarée avec le mot clé synchronized.
Une méthode synchronisée appartient à un objet quelconque, pas forcément à un thread.

Lorsqu’une méthode déclarée synchronized, est en cours d’exécution par un thread, tous
les autres threads qui en auraient besoin doivent attendre la fin de son exécution.

Lorsque synchronized est utilisé comme modifieur de méthode d’instance, une instruction
telle que: synchronized void method ( ) {…….} est équivalente à:
void method ( ) {
synchronized (this) { ….}
53
}
Exemple 1: Synchronisation de méthodes (1/2)

54
Exemple 1: Synchronisation de méthodes (2/2)

Ce code spécifie que les méthodes deposer et retirer ne


peuvent pas être exécutées simultanément par deux
threads différents pour une même instance de Compte.
Par exemple, si un thread exécute deposer sur un objet
de la classe Compte, alors tous les threads essayant
d’exécuter deposer et retirer sur un même objet seront
mis en attente

55
Exemple 2: Synchronisation de méthodes (1/5)

Considérons un exemple qui permet de réaliser deux opérations (addition et affichage)


sur deux champs d’une instance d’un objet (syn) d’une classe Synchro. Il s’agit
d’incrémenter la valeur du premier champ (de 1) et de faire la somme avec le deuxième
champ. On souhaite que les deux champs sont accédés dans les deux méthodes et utilisés
de façon concurrente par trois threads que nous créerons dans le main.

Regardons d’abord comment les valeurs des deux champs sont erronées et incohérentes si
l’exclusion mutuelle n’est pas bien gérée: l’incohérence s’explique par le fait que les
trois threads manipulent les deux champs pèle mêle.

Nous verrons alors une version qui dégage une utilisation correcte de la valeur de ces
variables.

56
Exemple 2: Synchronisation de méthodes (2/5)

class Synchro {
int n, som;
public Synchro (int n,int som) { this.n =n; this.som =som;
}
void addition ( ){ // methode non synchronisée
System.out .print ("n++= "+(n++) +" suivi de ") ;
try { Thread.sleep (222) ;}
catch (InterruptedException t){ }
som += n; System.out .println(" et som="+som) ;
}
void affiche ( ){ // methode non synchronisée
System.out .print("affiche: n= " +(++n)+" et ");
try {Thread.sleep (222) ;}
catch (InterruptedException t){ }
System.out.println ("affiche :som= "+som);
}}

57
Exemple 2: Synchronisation de méthodes (3/5)

class TestAddition extends Thread {


Synchro syn;
public TestAddition (String t, Synchro syn) {super (t); this.syn =syn;}
public void run ( ){ System.out.print (this.getName ( )+" " ) ;
try { syn.addition ( ) ; Thread.sleep(522); }
catch (InterruptedException er){ }
System.out.println("FIN "+this.getName ( ) ) ;
}
} // fin de TestAddition
class TestAffiche extends Thread{
Synchro syn;
public TestAffiche (String t, Synchro syn){super(t); this.syn =syn;}
public void run ( ){ System.out.println("******"+this.getName ( )+"******" ) ;
try { syn.affiche ( ) ; Thread.sleep(52); }
catch (InterruptedException er) { }
System.out.println("fin "+this.getName ( ) ) ; }
} // fin de TestAffiche
58
Exemple 2: Synchronisation de méthodes (4/5)

public class TestSynchro {


public static void main (String [ ] args) {
Synchro sy = new Synchro (1,1);
TestAffiche taf = new TestAffiche(" ThreadAffiche",sy);
TestAddition tad1 = new TestAddition("ThreadAdd1",sy);
TestAddition tad2 = new TestAddition ("ThreadAdd2", sy);
TestAddition tad3 = new TestAddition ("ThreadAdd3", sy);
tad1.start ( );
tad2.start ( );
taf.start ( );
tad3.start ( ) ;

}
}

59
Exemple 2: Synchronisation de méthodes (5/5)
Sortie de l’exemple

Pour rectifier le problème encouru, il faudra synchroniser les méthodes addition( ) et


affiche( ) de la classe Synchro , en les déclarant avec le mot clé synchronized.

ThreadAdd1 n++ = 1 ThreadAdd1 n++= 1


suivi de ThreadAdd2 n++ = 2 suivi de ThreadAdd2
suivi de ****** ThreadAffiche****** ****** ThreadAffiche******
affiche: ++n= 4 et ThreadAdd3 n++= 4 suivi de ThreadAdd3
n++= 2 suivi de et som=6
et som = 6 affiche: ++n= 4 et affiche :som= 6
et som=11 n++= 4 suivi de
affiche :som= 11 Erronée: on fin ThreadAffiche
et som = 16 s’attendait à avoir 3 FIN ThreadAdd1
fin ThreadAffiche et som=11
FIN ThreadAdd1 FIN ThreadAdd2
FIN ThreadAdd2 FIN ThreadAdd3
FIN ThreadAdd3
60
Amélioration de l’exemple

class Synchro {
int n, som;
public Synchro (int n, int som) { this.n =n; this.som =som;
}
synchronized void addition ( ){ // methode synchronisée, donc bloquant
System.out .print ("n++= "+n++ +" suivi de ") ;
try { Thread.sleep(222) ;}
catch (InterruptedException t){ }
som+=n; System.out .println(" et som="+som) ;
}

synchronized void affiche ( ){ // methode synchronisée, donc bloquant


System.out .print("affiche: n= " +(++n)+" et ");
try {Thread.sleep (222) ;}
catch (InterruptedException t){ }
System.out.println ("affiche :som= "+som);
}}
61
Attente et notification:

les méthodes wait ( ) et notifyAll ( )


(ces méthodes doivent êtres lancées dans des blocs ou méthodes synchronisés)

Attention: c’est des méthodes de la super classe Object et non de la classe Thread.

Elles implémentent des mécanismes de demande de verrou et d’avertissement de libération


de ce verrou.
Une méthode synchronisée peut appeler la méthode wait( ) de l’objet dont elle possède
le verrou, pour:
- rendre le verrou à l’environnement qui peut alors le donner à une autre méthode
synchronisée,
- mettre en attente le thread correspondant.
Une méthode synchronisée peut appeler la méthode notifyAll ( ) d’un objet afin de
prévenir tous les threads en attente sur cet objet et de leur donner la possibilité de
s’exécuter.
NB: notifyAll( ) permet de débloquer un wait ( ) sur un objet où notify( ) a été lancé.
La méthode notify ( ) prévient un seul thread. Avant de faire un notify ( ) ou notifyAll()
il faut changer la condition de boucle qui mène au wait ( ).
62
Exemple: producteur - consommateur. (1/4)

Un producteur est un thread qui dépose des jetons numérotés dans un chapeau
qui ne peut contenir qu’un seul jeton.
Un consommateur prend ce jeton qui doit être présent dans le chapeau.
Donc:
- le producteur doit s’arrêter de déposer des jetons lorsqu’il y en a déjà un et doit
être informé qu’un jeton a été retiré.
- le consommateur ne peut pas prendre de jetons s’il n’y en a pas (arrêt du
consommateur) et doit être informé lorsqu’un jeton a été déposé.
L’objet le plus à même pour avertir le producteur et le consommateur est le
chapeau lui-même.

63
Exemple: producteur - consommateur. (2/4)

(fichier Producteur.java)

public class Producteur extends Thread{


private Chapeau chapeau;
private int number; // le numéro du jeton à déposer
public Producteur (Chapeau chapeau, int number) {
this.chapeau = chapeau;
this.number = number;
}
public void run ( ){
for (int i = 0;i < 5 ;i++) {
chapeau.put (i);
System.out .println ("le producteur N° "+this.number +" a mis "+i) ;
try { Thread.sleep(1000);}
catch (InterruptedException e){ }
}
}
}
64
Exemple: producteur - consommateur. (3/4)

(fichier Consommateur.java)

public class Consommateur extends Thread {


private Chapeau chapeau;
private int number;
public Consommateur (Chapeau chapeau, int number) {
this.chapeau = chapeau;
this.number = number;
}
public void run( ){
int value = 0;
for (int i = 0; i < 5 ; i++) {
value = chapeau.get ( );
System.out .println ("le consommateur N° "+this.number +" a pris "+value) ;
try {Thread.sleep (1000);}
catch (InterruptedException e){ }
}
}
} 65
Exemple: producteur - consommateur. (4/4)

(fichier Chapeau.java)
public class Chapeau {
private int contenu; /*une classe pour tester*/
private boolean permis = false; public class TestProductCons {
public synchronized int get ( ){ public static void main(String [ ] args) {
while (permis == false) Chapeau chap = new Chapeau ( );
{ try {wait ( ); // rendre le verrou } Producteur p = new Producteur(chap,1);
catch (InterruptedException e){ } Consommateur c=
} new Consommateur(chap,1);
permis = false; notifyAll ( ); p.start ( ) ;
return contenu; } c.start ( );
public synchronized void put (int value){ }
while (permis == true) }
{ try { wait ( );}
catch (InterruptedException er) { } }
contenu = value; permis = true;
notifyAll ( );// attribuer le verrou à un autre
// qui peut alors s’exécuter
66
Exemple: producteur – consommateur: sortie

Voici la sortie du programme précédent avec un seul producteur et un seul


consommateur.

le producteur N° 1 a mis 0
le consommateur N° 1 a pris 0
le producteur N° 1 a mis 1
le consommateur N° 1 a pris 1
le producteur N° 1 a mis 2
le consommateur N° 1 a pris 2
le producteur N° 1 a mis 3
le consommateur N° 1 a pris 3
le producteur N° 1 a mis 4
le consommateur N° 1 a pris 4

67
Exemple: producteur – consommateur: Explications

Avec ce même programme, il peut y avoir plusieurs


producteurs et plusieurs consommateurs (repérés par des
numéros) mais toujours un seul chapeau ayant un
emplacement pour un seul jeton.
Comme la notification est faite par un get() d'un
consommateur ou un put() d'un producteur, on doit vérifier
si c'est un producteur ou un consommateur qui a levé l'arrêt.
Ce qui est fait dans le test et qui doit être refait à chaque
déblocage du wait(), d'où la nécessité d'une boucle while et
non d’un test if

68
Priorité des Threads

Jusqu’à présent, nous n’avons manipulé que des threads de même priorité.
En théorie, il est permis d’attribuer une certaine priorité à un thread.
Pour cela, on utilise la méthode setPriority (int threadPriority) où le paramètre
transmis en argument est une valeur entière comprise entre MIN.PRIORITY
(correspondant à la valeur 1) et la valeur MAX.PRIORITY (correspondant à 10).

La priorité par défaut est la valeur NORM.PRIORITY ( valeur 5).


La priorité d’un thread est exploité par l’environnement de cette façon:
- lorsqu’il peut donner la main à un thread, l’environnement choisi celui de plus
haute priorité parmi ceux qui sont dans l’état prêt; s’il y a plusieurs candidats
le thread choisi dépendra de l’environnement;
- si un thread plus prioritaire que le thread en cours d’exécution devient prêt, on lui
donne la main (le thread courant passant alors à l’état prêt).

69
Priorité des Threads: Exemple (1/2)

public class ThreadPriority extends Thread{


public ThreadPriority (String name) {super (name); }
public void run ( ){
for (int i = 0; i < 5 ; i++)
{ System.out.println ( this.getName ( ) +" valeur de i = "+i);
try { Thread.sleep (1000) ;}
catch ( InterruptedException er ) { }
}
System.out.println (this.getName ( ) +" se termine ");
}
public static void main(String[] args) {
ThreadPriority t = new ThreadPriority ("thread # 1");
ThreadPriority p = new ThreadPriority ("thread # 2");
t.setPriority (7) ; p.setPriority (Thread.MAX_PRIORITY ) ;
t.start ( ) ;p.start ( ) ;
}
} 70
Priorité des Threads: Exemple (2/2)

thread # 1 valeur de i = 0 thread # 1 valeur de i = 0 Le thread thread# 2


thread # 2 valeur de i = 0 thread # 2 valeur de i = 0 étant de priorité
thread # 1 valeur de i = 1 thread # 2 valeur de i = 1 supérieure, son
thread # 2 valeur de i = 1 thread # 1 valeur de i = 1 exécution s’achève
thread # 1 valeur de i = 2 thread # 2 valeur de i = 2 avant celle du thread
thread # 2 valeur de i = 2 thread # 1 valeur de i = 2 thread # 1 lancé
thread # 1 valeur de i = 3 thread # 2 valeur de i = 3 en premier lieu.
thread # 2 valeur de i = 3 thread # 1 valeur de i = 3
thread # 1 valeur de i = 4 thread # 2 valeur de i = 4
thread # 2 valeur de i = 4 thread # 1 valeur de i = 4
thread # 1 se termine thread # 2 se termine
thread # 2 se termine thread # 1 se termine

Ce qu’on aurait si les deux threads étaient de même priorité (celle par défaut).

71
FIN DU MODULE
Chapitre 3: Les interfaces graphiques

72
Les interfaces graphiques
qDans cette partie, nous aborderons les interfaces
graphiques
qOn parle aussi d'IHM pour Interfaces Homme
Machine ou de GUI pour Graphical User Interfaces
qEt, par extension, la programmation événementielle.
§Par là, vous devez comprendre que votre
programme ne réagira plus à des saisies au clavier
mais à des événements provenant d'un composant
graphique : un bouton, une liste, un menu.

73
Les interfaces graphiques
qIl existe deux types de composants graphiques:
§ Composants AWT (Abstract Window Toolkit): composants qui font appel aux
composants graphiques de l’OS
§ Composants SWING: composants écrits complétement avec java et sont
indépendants avec de l’OS
§ Nous utiliserons essentiellement les packages javax.swing et java.awt présents dans
Java

74
Composants AWT
qNous avons à notre disposition principalement trois
types d’objets
§Les Components qui sont des des composants
graphiques. Exemple (Button, Label, TextField, etc.)
§Les Containers qui contiennent les Components.
Exemple (Frame, Panel, etc.)
§Les Layouts qui sont des stratégies de placement de
Components pour les Containers. Exemple
(FlowLayout, BorderLayout, GridLayout, etc.)
Les classes suivies d'un astérisque (*) sont abstraites.

75
java.lang.Object
|
+--java.awt.Component* composants
|
+--java.awt.Container* conteneurs
|
+--java.awt.Panel
|
+--java.awt.Applet
|
+--javax.swing.JApplet
|
+--java.awt.Window
|
+-- javax.swing.JWindow
|
+--java.awt.Frame
|
+--javax.swing.JFrame fenêtre graphique
|
+--java.awt.Dialog
|
+--javax.swing.JDialog boîte de dialogue
|
+--javax.swing.AbstractButton
|
+--javax.swing.JButton bouton
|
+--javax.swing.JToggleButton
|
+--javax.swing.JCheckBox case à cocher
|
+--javax.swing.JRadioButton bouton radio
|
+--javax.swing.JMenuItem option d'un menu
|
+--javax.swing.JCheckBoxMenuItem option d'un menu
|
+--javax.swing.JRadioButtonMenuItem option d'un menu
|
+--javax.swing.JMenu menu ou option d'un menu
|
+--javax.swing.JLabel étiquette
|
+--javax.swing.text.JTextComponent
|
+--javax.swing.JTextField champ de texte
|
+--javax.swing.text.JList boîte de liste
|
+--javax.swing.text.JComboBox boîte de liste combinée
|
+--javax.swing.JScrollPane panneau de défilement
|
+--javax.swing.JMenuBar barre de menu
|
+--javax.swing.JPopUpMenu menu surgissant
|
+--javax.swing.JToolBar barre d'outils
Premier exemple AWT et SWING
import javax.swing.*;
import java.awt.*; Import java.awt.FlowLayout;
public class AppAWT{ public class AppSWING{
public static void main(String[]args){ public static void main(String[]args){
Frame f=new Frame("Titre"); JFrame f=new JFrame("Titre");
TextField t=new TextField(12); JTextField t=new JTextField(12);
Button b=new Button("OK"); JButton b=new JButton("OK");
f.setLayout(new FlowLayout()); f.setLayout(new FlowLayout());
f.add(t); f.add(t); f.add(b);
f.add(b); f.setBounds(10,10,500,500); //dimension f
f.setBounds(10,10,500,500); //dimension f.setVisible(true); //Afficher la frame f
frame }
f.setVisible(true); //Afficher la frame }
}
}

79
Une autre manière plus pratique: hériter de la classe
Frame
import java.awt.*;
public class MaFenetreAWT extends Frame {
TextField t=new TextField(12);
Button b=new Button("OK");
public MaFenetreAWT(){
this.setLayout(new FlowLayout());
this.add(t);
this.add(b);
this.setBounds(10,10,500,500); //dimension frame
this.setVisible(true); //Afficher la frame
}
public static void main(String[]args){
MaFenetreAWT f=new MaFenetreAWT();
}
80
L'objet JFrame
import javax.swing.JFrame;
public class Test {
public static void main(String[] args){
JFrame fenetre = new JFrame();
//Définit un titre pour notre fenêtre
fenetre.setTitle("Ma première fenêtre Java");
//Définit sa taille : 400 pixels de large et 100 pixels de haut
fenetre.setSize(400, 100);
//Nous demandons maintenant à notre objet de se
positionner au centre
fenetre.setLocationRelativeTo(null);
//Termine le processus lorsqu'on clique sur la croix rouge
fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Et enfin, la rendre visible
fenetre.setVisible(true);
}
}
L'objet JFrame
L'objet JFrame
• Afin de ne pas avoir à redéfinir les attributs à chaque fois, il serait
utile que nous possédions notre propre objet. Comme ça, nous
aurons notre propre classe !
• Pour commencer, effaçons tout le code que nous avons écrit dans
notre méthode main.
• Créons ensuite une classe que nous allons appeler Fenetre et faisons-
la hériter de JFrame
• Nous allons maintenant créer notre constructeur, dans lequel nous
placerons nos instructions. Cela nous donne :
L'objet JFrame
import javax.swing.JFrame;
public class Fenetre extends JFrame {
public Fenetre(){
this.setTitle("Ma première fenêtre Java");
this.setSize(1000, 600);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}
§ Ensuite, vous avez le choix :
• soit vous conservez votre classe contenant la méthode main et
vous créez une instance de Fenetre,
• soit vous effacez cette classe et vous placez votre méthode main
dans votre classe Fenetre.
§ je préfère placer ma méthode main dans une classe à part
L'objet JFrame
• Quel que soit l'emplacement de votre main, la ligne de code suivante doit y
figurer :
Fenetre fen = new Fenetre();
• Après execution, vous obtenez exactement la même chose que
précédement
• C'est tout de même plus pratique de ne plus écrire les mêmes instructions
à chaque fois.
• Ainsi, vous possédez une classe qui va se charger de l'affichage de votre
futur programme
• Voici une petite liste de méthodes que vous serez susceptible d'utiliser.
Positionner la fenêtre à l'écran
• Nous avons déjà centré notre fenêtre, mais vous voudriez peut-être la
positionner ailleurs.
• Pour cela, vous pouvez utiliser la méthode setLocation(int x, int y).
• Grâce à cette méthode, vous pouvez spécifier où doit se situer votre
fenêtre sur l'écran.
• Les coordonnées, exprimées en pixels, sont basées sur un repère dont
l'origine est représentée par le coin supérieur gauche
Empêcher le redimensionnement de la fenêtre
• Pour cela, il suffit d'invoquer la méthode setResizable(boolean b) :
true empêche le redimensionnement tandis que false l'autorise.
Garder la fenêtre au premier plan
• Il s'agit là encore d'une méthode qui prend un booléen en paramètre.
• Passer true laissera la fenêtre au premier plan quoi qu'il advienne,
false annulera cela.
• Cette méthode est :
setAlwaysOnTop(boolean b).
La classe JFrame
• Une fenêtre est un conteneur destiné à contenir d'autres
composants.
• La méthode getContentPane de la classe JFrame fournit une
référence, de type Container, au contenu de la fenêtre.
• Les méthodes add et remove de la classe Container permettent
respectivement d'ajouter et de supprimer un composant d'une
fenêtre.
Component add(Component compo)
void remove(Component compo)
Des méthodes utiles de la classe Component
• La classe Component est une classe abstraite dérivée de la classe
Object qui encapsule les composants d'une interface graphique.
• Les méthodes suivantes de la classe Component permettent de
gérer l'aspect d'un composant et donc en particulier d'une fenêtre.
• Montrer et cacher un composant
void setVisible(boolean b)
Exemple: compo.setVisible(true) rend visible le composant compo
• Activer et désactiver un composant
void setEnabled(boolean b)
Exemple: compo.setEnabled(true) active le composant compo
• Connaître l’état (activé ou non) d’un composant
boolean isEnabled()
Exemple: compo.isEnabled() retourne true si le composant compo
est activé
Des méthodes utiles de la classe Component

• Modifier la couleur de fond d'un composant


void setBackground(Color c)
• Modifier la couleur du premier plan d'un composant
void setForeground(Color c)
• Modifier la taille d'un composant
void setSize(int largeur, int hauteur)
• Modifier la position et la taille d'un composant
void setBounds(int x, int y, int largeur, int hauteur)
• Gérer les dimensions d'un composant
Dimension getSize()
void setSize(Dimension dim)
//La classe Dimension du paquetage java.awt contient deux champs publics : un champ height
(hauteur) et un champ width (largeur).
Les composants atomiques

• La classe JComponent est une classe abstraite dérivée de la classe


Container qui encapsule les composants atomiques d'une interface
graphique
• Les principaux composants atomiques offerts par Java sont:
• les boutons,
• les cases à cocher,
• les boutons radio,
• les étiquettes,
• les champs de texte,
• les boîtes de liste
• et les boîtes de liste combinée.
java.lang.Object
|
+--java.awt.Component*
|
+--java.awt.Container*
|
+--javax.swing.JComponent*
|
+--javax.swing.AbstractButton
|
+--javax.swing.JButton bouton
|
+--javax.swing.JToggleButton
|
+--javax.swing.JCheckBox case à cocher
|
+--javax.swing.JRadioButton bouton radio
|
+--javax.swing.JLabel étiquette
|
+--javax.swing.text.JTextComponent
|
+--javax.swing.JTextField champ de texte
|
+--javax.swing.text.JList boîte de liste
|
+--javax.swing.text.JcomboBox boîte de liste combinée
|
+--javax.swing.JScrollPane panneau de défilement
Les composants atomiques

• La méthode setPreferredSize de la classe Jcomponent permet


d'imposer une taille à un composant. Elle prend en argument un objet
de type Dimension.
• Exemple:
JButton bouton = new JButton("Un bouton") ;
bouton.setPreferredSize(new Dimension(10, 20)) ;
//bouton de largeur 10 et de hauteur 20
Un premier exemple
import java.awt.* ;
import javax.swing.* ;
class MaFenetre extends JFrame {
private JButton MonBouton ;
public MaFenetre () {
super("Ma premiere fenetre avec un bouton") ;
setBounds(10,40,300,200) ;
//le coin supérieur gauche de la fenêtre est placé au pixel de coordonnées 10, 40 et ses
dimensions seront de 300 * 200 pixels
MonBouton = new JButton("Un bouton") ;
Container c=getContentPane()
c.add(MonBouton) ;
}
}
public class MonProg {
public static void main(String args[]) {
JFrame fen = new MaFenetre() ;
fen.setVisible(true) ;
//rend visible la fenêtre de référence fen
}
}
Un premier exemple
A l’affichage

• Contrairement à une fenêtre, un bouton est visible par


défaut.
• Les instructions
JFrame fen = new JFrame() ;
fen.setTitle("Une fenêtre") ;
et l'instruction
JFrame fen = new JFrame("Une fenêtre") ;
sont équivalentes.
Les étiquettes

• Une étiquette de type JLabel permet d’afficher dans un conteneur un texte (d’une seule ligne)
non modifiable
• Exemple
class MaFenetre extends JFrame {
private Jlabel MonLabel;
public MaFenetre () {
super("Une fenetre avec une etiquette") ;
setBounds(10,40,300,200) ;
MonLabel = new JLabel ("texte initial") ;
//création d’une étiquette de référence MonLabel
contenant le texte texte initial
getContentPane().add(MonLabel) ;
MonLabel.setText("nouveau texte") ;
//modification du texte de l’étiquette de référence MonLabel
}
}
Les champs de texte
• Un champ de texte (ou boîte de saisie) de type JTextField est une
zone rectangulaire dans laquelle l’utilisateur peut entrer ou modifier
un texte (d’une seule ligne).
• Exemple
class MaFenetre extends JFrame {
private JTextField MonChamp1 ;
private JTextField MonChamp2 ;
public MaFenetre () {
super("Une fenetre avec deux champs de texte") ;
setBounds(10,40,300,200) ;
MonChamp1 = new JTextField(20) ;
//champ de taille 20 (la taille est exprimée en nombre
de caractères standard affichés dans le champ)
Monchamp2 = new JTextField("texte initial", 10) ;
//champ de taille 10 contenant au départ le texte texte
initial
getContentPane().add(MonChamp1) ;
getContentPane().add(MonChamp2) ;
}
}
Les champs de texte

• La méthode getText permet de connaître à tout moment le contenu


d’un champ de texte.
• Exemple
String ch= Monchamp2.getText() ;
• La méthode setText() permet d’attribuer une valeur au champ de
texte.
• Exemple
Monchamp3.setText("Bonjour");
Les cases à cocher
• La case à cocher de type JCheckBox permet à l’utilisateur
d’effectuer un choix de type oui/non.
Exemple
class MaFenetre extends JFrame {
private JCheckBox MaCase;
public MaFenetre () {
super("Une fenetre avec une case") ;
setBounds(10,40,300,200) ;
MaCase = new JCheckBox("Une case") ;
//création d’une case à cocher de référence MaCase
portant l’étiquette Une case
getContentPane().add(MaCase) ;
}
}
• Par défaut, une case à cocher est construite dans l’état non
coché (false).
• La méthode setSelected de la classe AbstractButton permet
de modifier l’état d’une case à cocher.
Les boutons radio
• Le bouton radio de type JRadioButton permet à l’utilisateur
d’effectuer un choix de type oui/non.
• Mais sa vocation est de faire partie d’un groupe de boutons
dans lequel une seule option peut être sélectionnée à la fois.
• Exemple
class MaFenetre extends JFrame {
private JRadioButton bRouge;
private JRadioButton bVert;
public MaFenetre () {
super("Une fenetre avec des boutons radio") ;
setBounds(10,40,300,200) ;
bRouge = new JRadioButton("Rouge") ;
bVert = new JRadioButton("Vert") ;
ButtonGroup groupe = new ButtonGroup() ;
groupe.add(bRouge) ; groupe.add(bVert) ;
Container contenu = getContentPane() ;
contenu.setLayout(new FlowLayout()) ;
contenu.add(bRouge) ;
contenu.add(bVert) ;
}
}
Les boîtes de liste

• La boîte de liste de type JList permet de choisir une ou plusieurs valeurs dans une
liste prédéfinie
• Initialement, aucune valeur n’est sélectionnée dans la liste.
• Exemple
String[] couleurs = {"rouge", "bleu", "gris", "vert","jaune", "noir"};
JList MaListe = new JList(couleurs) ;
MaListe.setSelectedIndex(2) ; //sélection préalable de l’élément de rang 2

• Par défaut une boîte de liste ne possède pas de barre de defilement.


• On peut lui en ajouter une en l'introduisant dans un panneau de défilement de
type JScrollPane (classe dérivée de la classe JComponent).
• Dans ce cas, on n'ajoute pas au conteneur la boîte de liste, mais le panneau de
défilement.
Les boîtes de liste

• Exemple
JScrollPane defil = new JScrollPane(MaListe) ;
//la liste de référence MaListe affiche 8 valeurs. Si elle en
contient moins, la barre de défilement n'apparaît pas.
MaListe.setVisibleRowCount(4) ;
//seules 4 valeurs de la liste sont visibles à la fois
fen.getContentPane().add(defil) ;
//ajoute le panneau de défilement au contenu de la fenêtre
Les boîtes de liste combinée

• La boîte de liste combinée (boîte combo) de type JComboBox associe


un champ de texte et une boîte de liste à sélection simple
• Tant que le composant n'est pas sélectionné, seul le champ de texte
s'affiche
• Lorsque l'utilisateur sélectionne le champ de texte, la boîte de liste
s'affiche
• L'utilisateur peut choisir une valeur dans la boîte de liste qui s'affiche
alors dans le champ de texte.
• Initialement, aucune valeur n’est sélectionnée dans la liste.
Les boîtes de liste combinée
• Exemple
String[] couleurs = {"rouge", "bleu", "gris", "vert","jaune", "noir"};
JComboBox MaCombo = new JComboBox(couleurs);
MaCombo.setSelectedIndex(2) ; //sélection préalable de l’élément de rang
2
• La boîte combo est dotée d'une barre de défilement dès que son
nombre de valeurs est supérieur à 8
• On peut modifier le nombre de valeurs visibles avec la méthode
setMaximumRowCount.
• Exemple
MaCombo.setMaximumRowCount(4) ;
//au maximum 4 valeurs sont affichées
• Par défaut, le champ de texte associé à une boîte combo n'est pas
éditable, ce qui signifie qu'il sert seulement à présenter la sélection
courante de la liste.
• Mais il peut être rendu éditable par la méthode setEditable.
Exemple:
Les boîtes de liste combinée

MaCombo.setEditable(true) ;
• La méthode getSelectedItem fournit la valeur sélectionnée. Son résultat est
de type Object. Exemple:
String ch = (String) MaCombo.getSelectedItem();
• La méthode getSelectedIndex fournit le rang de la valeur sélectionnée.
• La boîte combo dispose de méthodes appropriées à sa modification.
MaCombo.addItem("orange") ;
//ajoute la valeur orange à la fin de la liste combo
MaCombo.addItemAt("orange", 2) ;
//ajoute la valeur orange à la positon 2 de la liste combo
MaCombo.removeItem("gris") ;
//supprime la valeur gris de la liste combo
Les menus déroulants

• Les menus déroulants usuels font intervenir trois sortes d'objets:


• un objet barre de menu de type JMenuBar ;
• différents objets menu, de type JMenu, visibles dans la barre de menu ;
• pour chaque menu, les différentes options, de type JMenuItem, qui le
constituent
• La méthode setEnabled de la classe Component permet d'activer ou
de désactiver un menu ou une option.
Un exemple:
Import java.awt.* ;
import javax.swing.* ;
class MaFenetre extends JFrame {
private JMenuBar barreMenus ;
private JMenu couleur, dimensions ;
private JMenuItem rouge, vert, hauteur, largeur ;
public MaFenetre () {
super("Une fenetre avec un menu") ;
setSize(300, 200) ;
//création d'une barre de menu
barreMenus = new JMenuBar() ;
//ajout de la barre de menu dans la fenêtre
setJMenuBar(barreMenus) ;
//création d'un menu Couleur et de ses options
Rouge et Vert
couleur = new JMenu("Couleur") ;
barreMenus.add(couleur) ;
rouge = new JMenuItem("Rouge") ;
couleur.add(rouge) ;
//ajout d'une barre séparatrice avant l'option suivante
couleur.addSeparator() ;
vert = new JMenuItem("Vert") ;
couleur.add(vert) ;
//création d'un menu Dimensions et de
ses options Hauteur et Largeur
dimensions = new JMenu("Dimensions");
barreMenus.add(dimensions) ;
hauteur = new JMenuItem("Hauteur") ;
dimensions.add(hauteur) ;
dimensions.addSeparator() ;
largeur = new JMenuItem("Largeur") ;
dimensions.add(largeur) ;
}
}
Les menus déroulants
public class MonMenu {
public static void main(String args[]) {
JFrame fen = new MaFenetre() ;
fen.setVisible(true) ;
}
}
TP à réaliser !!!

JList JComboBox

JMenu
JMenuItem

JMenu

JMenuItem

JTextArea

JCheckBox
JRadioButton
111
Les gestionnaires de mise en forme
• La disposition des composants dans un conteneur est
assurée par un gestionnaire de positionnement qui se
charge de les placer correctement.
• Cela permet de rester indépendant de la plate-forme et
d’éviter des calculs fastidieux
• Les gestionnaires de mise en forme proposés par Java
sont:
• FlowLayout
• BorderLayout
• GridLayout
• CardLayout
• BoxLayout
• Ce sont tous des classes du paquetage java.awt dérivées
de la classe Object et qui implémentent l'interface
LayoutManager.
Le gestionnaire FlowLayout
• La méthode setLayout de la classe Container permet
d'associer un gestionnaire de mise en forme à un
conteneur
• FlowLayout permet de disposer les composants les uns à
la suite des autres, de gauche à droite.
• Exemple
class MaFenetre extends JFrame {
public MaFenetre () {
super("Une fenetre") ; setSize(300, 200) ;
Container contenu = getContentPane() ;
contenu.setLayout(new FlowLayout()) ;
//changement de gestionnaire de mise en forme
contenu.add(new JButton("UN")) ;
contenu.add(new JButton("DEUX")) ;
}
}
Les gestionnaires de mise en forme
• Le gestionnaire BorderLayout est le gestionnaire par
défaut des fenêtres et des boîtes de dialogue.
• Exemple
import java.awt.* ;
import javax.swing.* ;
class MaFenetre extends JFrame {
public MaFenetre () {
super("Une fenetre") ;
setSize(300, 200) ;
Container c = getContentPane().
c.setLayout(new BorderLayout()) ;
//changement de gestionnaire de mise en forme
}
}
public class MonProgLayout {
public static void main(String args[]) {
JFrame fen = new MaFenetre() ;
fen.setVisible(true) ; }
}
Le gestionnaire BorderLayout

• Permet de placer chaque composant dans une zone géographique.


• L'emplacement d'un composant est choisi en fournissant en
argument de la méthode add de la classe Container l'une des
constantes entières suivantes
• BorderLayout.NORTH
• BorderLayout.SOUTH
• BorderLayout.EAST
• BorderLayout.WEST
• BorderLayout.CENTER
• Si aucune valeur n'est précisée à la méthode add, le composant est
placé au centre.
Le gestionnaire BorderLayout
• Exemple
import java.awt.* ;
import javax.swing.* ;
class MaFenetre extends JFrame {
public MaFenetre () {
super("Une fenetre") ; setSize(300, 200) ;
Container contenu = getContentPane() ;
contenu.setLayout(new BorderLayout()) ; //inutile
contenu.add(new JButton("UN")) ;
//bouton placé au centre par défaut
contenu.add(new JButton("DEUX"), "North") ;
contenu.add(new JButton("TROIS"), "South") ;
contenu.add(new JButton("QUATRE"), "West") ;
contenu.add(new JButton("CINQ"), "East") ;
}
}
public class MonProgBLayout {
public static void main(String args[]) {
JFrame fen = new MaFenetre() ;
fen.setVisible(true) ;
}
}
Le gestionnaire BorderLayout

• Le gestionnaire de mise en forme BorderLayout ne tient pas compte


de la taille souhaitée des composants, qui peut être imposée par la
méthode setPreferredSize de la classe JComponent
Le gestionnaire GridLayout

• Permet de disposer les composants les uns à la suite des autres sur
une grille régulière, chaque composant occupant une cellule de la
grille.
• La classe GridLayout dispose de deux constructeurs :
• public GridLayout(int rows, int cols) ;
//rows et cols définissent respectivement le nombre de lignes et de colonnes
de la grille.
• public GridLayout(int rows, int cols, int hgap, int vgap) ;
//hgap et vgap définissent les espaces entre les composants.
Le gestionnaire GridLayout

• Exemple
class MaFenetre2 extends JFrame {
public MaFenetre () {
super("Une fenetre") ; setSize(300, 200) ;
Container contenu = getContentPane() ;
contenu.setLayout(new GridLayout(2, 2)) ;
//changement de gestionnaire de mise en forme
contenu.add(new JButton("UN")) ;
contenu.add(new JButton("DEUX")) ;
contenu.add(new JButton("TROIS")) ;
contenu.add(new JButton("QUATRE")) ;
}
}
Le gestionnaire CardLayout
• Permet de disposer les composants suivant une pile, de telle
façon que seul le composant supérieur soit visible à un
moment donné.
• Exemple
class MaFenetre extends JFrame {
public MaFenetre () {
super("Une fenetre") ; setSize(300, 200) ;
Container contenu = getContentPane() ;
CardLayout pile = new CardLayout(30, 20) ;
//les arguments précisent les retraits entre le
composant et le conteneur : 30 pixels de part et d'autre et 20 pixels en
haut et en bas
contenu.setLayout(pile) ;
//changement de gestionnaire de mise en forme
contenu.add(new JButton("UN"), "bouton1") ;
//la chaîne "bouton1" permet d'identifier le composant au sein du
conteneur
contenu.add(new JButton("DEUX"), "bouton2") ;
contenu.add(new JButton("TROIS"), "bouton3") ;
} }
Le gestionnaire CardLayout

• Par défaut, le composant visible est le premier ajouté au conteneur


(dans l'exemple précédent, c'est le bouton UN). On peut faire
apparaître un autre composant de la pile de l'une des façons
suivantes :
pile.next(contenu) ; //affiche le composant suivant
pile.previous(contenu) ; //affiche le composant précédent
pile.first(contenu) ; //affiche le premier composant
pile.last(contenu) ; //affiche le dernier composant
pile.show(contenu,"bouton3") ;
//affiche le composant identifié par la chaîne "bouton3"
Une classe Insets pour gérer les marges

• La méthode getInsets de la classe Container permet de définir les


quatre marges (haut, gauche, bas et droite) d'un conteneur.
• Elle retourne un objet de type Insets (classe du paquetage java.awt
dérivée de la classe Object) défini par quatre champs publics de type
entier initialisés par le constructeur suivant :
public Insets(int top, int left, int bottom, int right)
Une classe Insets pour gérer les marges
Exemple
class MaFenetre extends JFrame {
public MaFenetre () {
super("Une fenetre") ; setSize(300, 200) ;
Container contenu = getContentPane() ;
contenu.setLayout(new BorderLayout(10, 10)) ;
contenu.add(new JButton("UN")) ;
contenu.add(new JButton("DEUX"), "North") ;
contenu.add(new JButton("TROIS"), "South") ;
contenu.add(new JButton("QUATRE"), "West") ;
contenu.add(new JButton("CINQ"), "East") ;
}
//redéfinition de la méthode getInsets afin de définir de nouvelles marges pour la
fenêtre
public Insets getInsets() {
Insets normal = super.getInsets() ;
//récupération des marges par défaut de la fenêtre
return new Insets(normal.top+10, normal.left+10, normal.bottom+10,
normal.right+10) ;
//création d'un nouvel objet de type Insets pour modifier les marges de la fenêtre
}
}
Une classe Insets pour gérer les marges
GridBagLayout
Des différents Layout Manager, Le gestionnaire GridBagLayout est le plus
difficile à manier.
Il permet de disposer les composants selon une grille, ceux-ci pouvant occupés
plusieurs cases.
Cette classe ne dispose que d’un seul constructeur sans paramètre:
GridBagLayout ( ).
Pour associer ce gestionnaire à un Container conteneur :
conteneur.setLayout (new GridBagLayout ( ) );

Mais cette instruction ne suffit pas pour placer les composants au conteneur.
Tout composant à ajouter doit disposer d’un objet GridBagConstraints lequel
spécifie comment faire le placement des différents composants:
GridBagConstraints objetPlaceur = new GridBagConstraints ( ) ;
Cet objet objetPlaceur dispose alors de variables et de méthodes permettant de
réaliser le placement des composants.

125
La gestion des événements
• Un clic souris, la frappe d’une touche au clavier ou le
changement de la taille d’une fenêtre sont des
exemples d’événements.
• Java classe les événements en deux niveaux :
• les événements de bas niveau (par exemple, un clic dans
une fenêtre)
• et les événements de haut niveau (par exemple, une action
sur un bouton qui peut provenir d’un clic souris ou d’une
frappe au clavier).
• En Java, les événements n’ont pas une valeur
physique, mais logique.
• Un événement dépend du composant qui l’a généré.
• On appelle source d’un événement l’objet qui l’a
généré.
Interfaces graphiques : événements

• Il faut ajouter des instructions spécifiques permettant de réagir lors


d’un événement (clic sur un bouton, frappe au clavier, déplacement
avec la souris, etc.).
• Un événement fait interagir trois objets :
• L’objet source de l’événement (bouton cliqué)
• Un objet (classe ActionEvent ou MouseEvent ou etc.) mémorisant
l’événement (date, source, …)
• Un écouteur d’événement (listener) capable de traiter l’événement
La gestion des événements

• Exemple
• L’événement émis suite à un clic souris dans une fenêtre est de type
MouseEvent.
• L’événement émis suite à un clic souris sur un bouton est de type
ActionEvent.
• Tout événement qui peut se produire dans une interface graphique
est de type XXXEvent, classe du paquetage java.awt.event ou du
paquetage javax.swing.event
La gestion des événements: Traiter un événement

• Un composant ne traite pas forcément lui même les événements qu’il


génère.
• Il délègue ce traitement à des objets particuliers appelés écouteurs
(un composant peut être son propre écouteur).
• En fonction des événements qu’ils traitent, un écouteur doit
implémenter une interface particulière, dérivée de l’interface
EventListener, qui correspond à une catégorie d’événements.
• Pour traiter un événement de type XXXEvent, un écouteur doit
implémenter l’interface XXXListener.
La gestion des événements: Traiter un événement
Exemple
• L’interface MouseListener correspond à une catégorie
d’événements souris de type MouseEvent.
• Elle comporte cinq méthodes correspondant chacune à un
événement souris particulier
public interface MouseListener extends EventListener {
public void mousePressed(MouseEvent e) ;
//appelé lorsqu’un bouton de la souris est pressé sur un composant
//l’argument e de type MouseEvent correspond à l’objet événement
généré
public void mouseReleased(MouseEvent e) ;
//appelé lorsqu’un bouton de la souris est relâché sur un composant
public void mouseClicked(MouseEvent e) ;
//appelé lors d’un clic souris sur un composant (la souris n’a pas été
déplacée entre l’appui et le relâchement du bouton)
public void mouseEntered(MouseEvent e) ;
//appelé lorsque la souris passe de l’extérieur à l’intérieur d’un
composant
public void mouseExited(MouseEvent e) ; }
//appelé lorsque la souris sort d’un composant (la souris passe de
l’intérieur à l’extérieur du composant)
La gestion des événements: Intercepter un événement

• Lorsqu’un composant veut intercepter un événement de type


XXXEvent, il doit le préciser dans son constructeur en appelant la
méthode addXXXListener(XXXListener objetEcouteur), où l’argument
objetEcouteur correspond à l’objet écouteur chargé de traiter
l’événement.
La gestion des événements: Première version

import java.awt.* ; import java.awt.event.* ;


import javax.swing.* ; import javax.swing.event.* ;
class MaFenetre extends JFrame {
public MaFenetre () {
super("Une fenetre qui traite les clics souris") ;
setSize(300, 200) ;
addMouseListener(new EcouteurSouris());
//la fenêtre fait appel à un écouteur d’événements souris
pour traiter les clics souris
}
}
La gestion des événements: Première version
L’écouteur d’événements souris doit implémenter l’interface MouseListener
qui correspond à une catégorie d’événements souris.

class EcouteurSouris implements MouseListener {


//redéfinition de la méthode appelée lors d’un clic souris
public void mouseClicked(MouseEvent e) {
System.out.println("clic dans la fenetre"); }
//la redéfinition des autres méthodes est "vide"
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
}
public class MonProgEvtClic1 {
public static void main(String args[]) {
JFrame fen = new MaFenetre() ;
fen.setVisible(true) ; }
}
La gestion des événements: Deuxième version
import java.awt.* ; import java.awt.event.* ;
import javax.swing.* ; import javax.swing.event.* ;
class MaFenetre extends JFrame implements MouseListener {
public MaFenetre () {
super("Une fenetre qui traite les clics souris") ;
setSize(300, 200) ;
addMouseListener(this);
//la fenêtre est son propre écouteur d’événements souris
}
//L’argument e de type MouseEvent correspond à l’objet événement généré
dans la fenêtre lors d’un clic souris. On peut utiliser les informations qui lui
sont associées.
public void mouseClicked(MouseEvent e) {
int x = e.getX() ;
int y = e.getY() ;
//coordonnées du curseur de la souris au moment du clic
System.out.println("clic dans la fenetre au point de coordonnees " + x + ", " +
y);
}
La gestion des événements: Deuxième version

public void mousePressed(MouseEvent e) { }


public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
}
public class MonProgEvtClic2 {
public static void main(String args[]) {
JFrame fen = new MaFenetre() ;
fen.setVisible(true) ;
}
}
Un exemple avec des boutons

• Un bouton ne peut déclencher qu’un seul événement de type


ActionEvent.
• L’interface ActionListener ne comporte qu’une seule méthode
actionPerformed.
Un exemple avec des boutons

class EcouteurFermer implements ActionListener {


public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
public class MonProgEvtBouton1 {
public static void main(String args[]) {
JFrame fen = new MaFenetre() ;
fen.setVisible(true) ; }
}
Un exemple avec des boutons

• La méthode getSource de la classe EventObject permet d’identifier la


source d’un événement.
• Elle s’applique à tous les événements générés par n’importe quel
composant.
• La méthode getActionCommand de la classe ActionEvent permet d’obtenir
la chaîne de commande associée à la source d’un événement.
• Les composants qui disposent d’une chaîne de commande sont les
boutons, les cases à cocher, les boutons radio et les options menu.
• Par défaut, la chaîne de commande associée à un bouton est son étiquette.
Un exemple avec des boutons

• Exemple
• La méthode actionPerformed de la classe MaFenetre peut s’écrire :
public void actionPerformed(ActionEvent e) {
String nom = e.getActionCommand() ;
System.out.println("action sur le " + nom) ;}
• La méthode setActionCommand de la classe JButton permet
d’associer une autre chaîne de commande à un bouton.
• Exemple
MonBouton1.setActionCommand ("premier bouton").
Interfaces graphiques Awt: Exemple

import java.awt.*; import java.awt.event.*;


public class Fenetre extends Frame implements ActionListener{
public Panel p; public TextField texte; public Button ...
public Fenetre() {
super(“exemple de fenetre”);
p = new Panel(); this.add(p);
p.add( new Label(“nbre a multplier par 2”) );
p.add( texte = new TextField(20) );
p.add( bouton1 = new Button(“doubler”) );
p.add( bouton2 = new Button(“fin”) );
this.pack();
Interfaces graphiques Awt: Exemple

bouton1.addActionListener(this); // la fenetre devient ecouteur


bouton2.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
if (e.getSource()==bouton1){
double x = Double.doubleValue(texte.getText());
x = 2*x; texte.setText(“”+x);
}
else if (e.getSource()==bouton2){
this.dispose(); System.exit(0); // destruction fenetre et arret progr.
}
}
Création de boîtes de dialogue

Utilisation de la classe JDialog

JFrame

clic

JDialog

142
Code de l’interface (1/2)

public class SwingDialog extends JFrame implements ActionListener{


JDialog dialog;
JButton lancer, ok;
public SwingDialog (String title) {
this.setTitle( title);
this.setSize(350,250);
Container c = this.getContentPane();
c.setLayout (null);
lancer = new JButton ("Lancement du dialog");
lancer.addActionListener (this);
lancer.setBounds (40,40,200,30);
c.add (lancer);
}

143
Code de l’interface (2/2)

public void actionPerformed(ActionEvent e)


{ if (e.getSource() = = lancer) lanceDialog ( );
if (e.getSource() = = ok) dialog.dispose ( );
}
public void lanceDialog( )
{ dialog = new JDialog( this,"Mon premier dialog",true);
dialog.setBounds (170,170,200,150);
dialog.getContentPane( ).setLayout (null);
JTextField text = new JTextField("Message à afficher") ;
dialog.getContentPane().add (text).setBounds (50,20,100,20);
ok = new JButton("OK");
ok.addActionListener (this);
ok.setBounds (60,60,60,20);
dialog.getContentPane().add (ok);
dialog.setVisible (true);
}
} 144
Commentaires sur le JDialog

Dans l’instruction :
dialog = new JDialog( this, "Mon premier dialog", true); on a trois arguments:
this désigne la fenêtre propriétaire (parent) c-à-d celle contenant le JDialog
"Mon premier dialog " désigne le titre de la boîte de dialogue
true la boîte de dialogue est modale c-à-d une fois lancée, l’utilisateur ne peut pas agir
sur d’autres que ceux intégrés dans la boîte de dialogue.

Remarque : il est possible (de la même façon qu’on utilise la classe JFrame) de créer
une classe qui dérive de JDialog et d’y ajouter toutes les fonctionnalités
dont on souhaite disposer.

Il est aussi possible de créer des boîtes de dialogue sans faire usage de la classe JDialog.
C’est que nous allons voir dans le paragraphe suivant avec la classe JOptionPane.

145
La classe: javax.swing.JOptionPane

Les boîtes de Message: JOptionPane.showMessageDialog

JFrame

JOptionPane

146
Exemple message: JOptionPane.showMessageDialog

public class SwingMessage extends JFrame implements ActionListener{


JButton ouvre;
public SwingMessage (String titre) {
super(); this.setTitle(titre); this.setSize(400,150);
this.getContentPane( ).setLayout( new FlowLayout());
ouvre = new JButton("OK");
ouvre.addActionListener (this); Fenêtre parent
this.getContentPane().add(ouvre);
Objet message
}
Titre boîte
public void actionPerformed(ActionEvent e)
{if (e.getSource() = = ouvre)
JOptionPane.showMessageDialog (this,"Message à envoyer","Exemple Message",
JOptionPane.INFORMATION_MESSAGE, null);
} Icon de la boîte
Type du message
147
La classe: javax.swing.JOptionPane

Les boîtes de Confirmation: JOptionPane.showConfirmDialog


Une vraie application nécessite toujours le stockage de données sur disque ou sur
tout autre média. Avant de faire des sauvegardes permanentes, il est aussi bon
de demander une confirmation de la part de l’utilisateur.
Pour ce faire, en Java, on peut utiliser les boîtes de confirmation .

message
Fenêtre parent
Type message titre

JOptionPane.showConfirmDialog( this,"Voulez-vous effectuer cette opération",


"Boîte de confirmation",
JOptionPane.QUESTION_MESSAGE ); 148
Remarques (1/2)

Les boîtes de confirmation apparaissent par défaut avec des boutons


Yes, No et Cancel.
On peut souhaiter n’afficher que les boutons Yes et Cancel; dans ce cas
utilisez la méthode showConfirmDialog (…) où le quatrième attribut permet
de déterminer les boutons qui apparaîtront. Pour le cas évoqué, on fera

JOptionPane.showConfirmDialog (this,"Voulez-vous effectuer cette opération",


"Boîte de confirmation",
JOptionPane.OK_CANCEL_OPTION ,JOptionPane.QUESTION_MESSAGE);

Il se peut aussi qu’on veuille effectuer un certain traitement si l’on clique sur
l’un des boutons Yes, No ou Cancel. Dans ce cas, récupérer la valeur renvoyée par
la méthode showConfirmDialog sous une valeur de type entière (int ).
La valeur 0 correspond au clic sur Yes, 1 au clic sur No et 2 au clic sur Cancel.

149
Remarques (2/2)

Il peut arriver qu’on veuille personnaliser le nom des boutons Yes, No et Cancel
selon la langue utilisée.
Comment ferais t-on par exemple pour remplacer ces boutons par Oui, Non et
Annuler?
Utilisez, pour ce faire la méthode showOptionDialog (…).

/* la methode showConfirmDialog utilise par defaut des boutons YES, NO et CANCEL;


pour les remplacer par OUI, NON et ANNULER, on fait une personnalisation
en utilisant showOptionDialog*/
static int openJOptionConfirmDialog (Component comp, String question,String titre)
{ Object options[ ] = {"OUI","NON"}; // on ne tient compte que de ces boutons
return JOptionPane. showOptionDialog (comp,question,titre,
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null, options, options[0]);
150
}
Chapitre 4: JDBC
JDBC
• Dans ce chapitre, nous ferons nos premiers pas avec Java
DataBase Connectivity , communément appelé JDBC.
• Il s'agit en fait de classes Java permettant de se connecter
et d'interagir avec des bases de données.
• API Java permettant l’accès aux BD (MS Access, SQL
Server, MySQL, PostgreSQL, Oracle)
• Fonctionne en mode client/serveur (appl. Java / SGBD)
• Les classes de l’API se trouvent dans java.sql
• Mais avant toute chose, il nous faut une base de données
!
• Nous allons donc nous pencher sur l'utilité d'une base de
données
Différences entre fichiers et BDD

• Les bases de données (BDD) permettent de stocker des


données.
• il s'agit d'un système de fichiers contenant les données de
votre application.
• La différence avec les fichiers classiques se trouve dans le
fait que ce n'est pas vous qui les gérez : c'est votre BDD
qui les organise, les range et, le cas échéant, vous
retourne les informations qui y sont stockées.
• De plus, plusieurs utilisateurs peuvent accéder
simultanément aux données dont ils ont besoin, sans
compter que de nos jours, les applications sont amenées à
traiter une grande quantité de données, le tout en réseau.
• Imaginez-vous gérer tout cela manuellement alors que les
BDD le font automatiquement.
BDD

• Les données sont ordonnées par tables , c'est-à-dire par


regroupements de plusieurs valeurs.
• C'est vous qui créerez vos propres tables, en spécifiant quelles
données vous souhaiterez y intégrer.
• Une base de données peut être vue comme une gigantesque armoire
à tiroirs dont vous spécifiez les noms et qui contiennent une
multitude de fiches dont vous spécifiez aussi le contenu
BDD
• Exemple d’une BDD contenant deux tables

• Dans cette base de données, nous trouvons deux


tables :
• une dont le rôle est de stocker des informations relatives à
des personnes (noms, prénoms et âges)
• ainsi qu'une autre qui s'occupe de stocker des pays, avec
leur nom et leur capitale.
BDD

• la BDD symbolise l'armoire


• chaque table représente un tiroir
• et chaque ligne de la table correspond à une fiche de ce tiroir !
• Vous pouvez les interroger en leur posant des questions via un
langage précis.
• « Donne-moi la fiche de la table Personne pour le nom Sall »
• « Donne-moi la fiche de la table Pays pour le pays Senegal »
• Le langage permettant d'interroger des bases de données est le
langage SQL
JDBC : architecture

Application Java programmeur

API
JDBC Gestionnaire
JDBC DriverManager de pilotes
JDBC JDBC
Driver
API JDBC-ODBC JDBC driver
JBDC driver

Pilote donné ou vendu


bridge driver pour MySQL pour Oracle

ODBC driver

MS SQL
MySQL Oracle
Access Server
JDBC : architecture
• JDBC Driver Manager : Gestionnaire de drivers permettant
à chaque application de charger le(s) driver(s) dont il a
besoin.
• Driver JDBC : gère les détails de communication avec un
type de SGBD.
• Un driver par SGBD (Oracle, MySQL, ...)
• JDBC-ODBC : driver générique pour toutes les sources
accessibles via ODBC (Open DataBase Connectivity. interface
Microsoft permettant la communication entre des clients bases
de données fonctionnant sous Windows et les SGBD du marché).
• Chaque BD utilise un pilote qui lui est propre et qui
permet de convertir les requêtes dans le langage natif du
SGBDR.
• Les drivers dépendent du SGBD auquel ils permettent
d’accéder.
• Pour travailler avec un SGBD, il faut disposer de classes
(driver) qui implémentent les interfaces de JDBC.
JDBC : fonctionnement

• JDBC fonctionne comme suit :


• Création d’une connexion à la BD
• Envoi de requêtes SQL (pour récupérer ou maj des données)
• Exploitation des résultats provenant de la base
• Fermeture de la connexion
Chargement du Driver

Chargement du driver (= chargement de la classe du driver dans la JVM)


Class.forName (String driverName);
Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver") ;
Class.forName ("oracle.jdbc.driver.OracleDriver") ;
Class.forName ("org.gjt.mm.mysql.Driver") ;
Quand une classe Driver est chargée, elle doit créer une instance d’elle
même et s’enregistrer auprès du DriverManager.
Certains compilateurs refusent la notation précédente et demandent :
Class.forName (" driver_name").newInstance ( ) ;
Cette étape 1 constitue l’enregistrement du driver JDBC.
Etablir une connexion à la base de données

Une fois le driver enregistré, une connexion peut être établie avec la BD.
Pour obtenir une connexion à un SGBD, il faut faire une demande à la classe
gestionnaire de drivers:
Demande permise par la méthode getConnection (… ) de la classe DriverManager
Cette méthode peut prendre 3 arguments au plus:
- l’URL vers la BD
- le nom de l’utilisateur de la base
- son mot de passe
cette méthode renvoie un objet de type Connection.

Connection co = DriverManager.getConnection("jdbc:mysql://serveur/MABD?user=root ");

Ou

Connection co = DriverManager.getConnection ("jdbc:odbc:employe", "login", "passwd");


JDBC : exemple de connexion
import java.sql.*;
public class TestJDBC {
public static void main(String[] args) {
// TODO Auto-generated method stub
//Connection co = null;
String user="root";
String passwd="root";
String url = "jdbc:mysql://localhost:3306/srt2021";
try { Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("Chargement pilote réussi");
Connection co = DriverManager.getConnection(url, user,passwd);
System.out.println("Connexion à la base de données réussie");

} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Création de requêtes SQL en utilisant l’objet de
type Connection
• Pour envoyer une requête SQL “normale”, il faut
initialement créer un objet Statement à partir de
l’objet Connection:
• Statement st = co.createStatement();

• La fermeture d’un Statement engendre la fermeture


automatique de tous les ResultSet associés
• Deux types de Statement:
• Statement: requêtes statiques simples,
• PreparedStatement: requêtes dynamiques pré compilées
(avec paramètres d’ I/O),
Envoi et exécution de requêtes

Il existe trois types d’exécution de requêtes:


Ø executeQuery (…): pour les requêtes SELECT qui retournent un
ResultSet (tuples),
Ø executeUpdate (…): pour les requêtes INSERT, UPDATE, DELETE,
CREATE TABLE, DROP TABLE qui retournent un entier (int) désignant le
nombre de tuples traités.
Ø execute ( ): pour les procédures stockées (cas rares).

ØLes méthodes executeQuery ( ) et executeUpdate( ) de la classe


Statement prennent comme argument une chaîne (String) indiquant la
requête SQL à exécuter.
JDBC : Requêtes SQL

• JDBC permet divers types de requêtes SQL : interrogation, maj,


création de tables.
ØLes objets qui peuvent être utilisés pour obtenir des
informations sur la base de données sont:

• ResultSet : Cette classe symbolise un ensemble de résultats dans la


base de donnéeset autorise l’accès au résultats d’une requête rangée
par rangée. Elle contient des informations sur une table (noms des
colonnes) ou le résultat d’une requête SQL.
• ResultSet rs = (ResultSet)st.executeQuery(“Select …)”;

• ResultSetMetaData : contient des informations sur le nom et le type


des colonnes d’une table
• ResultSetMetaData rsmd = rs.getMetaData();
• int nbre_Colonnes = rsmd.getColumnCount();

• DataBaseMetaData : contient les informations sur la BD (noms des


tables, index, etc.)
Exécution des requêtes
ResultSet resultats = null;
String requete = "SELECT * FROM client";
try {
Statement st = con.createStatement();
resultats = st.executeQuery(requete);
} catch (SQLException e) {
//traitement de l'exception
}

• Un objet de la classe Statement permet d'envoyer des requêtes SQL


à la base.
• La création d'un objet Statement s'effectue à partir d'une instance
de la classe Connection
• Pour une requete de type interrogation (SELECT), la méthode à
utiliser de la classe Statement est executeQuery
• Pour des traitements de mise à jour, il faut utiliser la méthode
executeUpdate
• Lors de l'appel à la méthode d'exécution, il est nécessaire de lui
fournir en paramètre la requete SQL sous forme de chaine.
Exécution des requêtes

• La méthode executeUpdate() retourne le nombre d'enregistrement


qui ont été mis à jour
//insertion d'un enregistrement dans la table client
String req1="INSERT INTO etudiant Values('3000','Adrien','Basse','M2')"; try {
Statement stmt = con.createStatement();
int nbMaj = stmt.executeUpdate(req1);
affiche("nb mise a jour = "+nbMaj);
} catch (SQLException e) {
e.printStackTrace();
}
Exécution des requêtes

try{
Statement st1=co.createStatement();

int nb1=st1.executeUpdate(req1);
}catch(Exception e){}
Exécution des requêtes

String req2="CREATE TABLE enseignant("


+"code_enseignant VARCHAR(20),"
+"Prenom VARCHAR(20),"
+"Nom VARCHAR(20),"
+"Grade VARCHAR(20))";

try{
Statement st1=co.createStatement();
int nb2=st1.executeUpdate(req2);
}catch(Exception e){}
La classe ResultSet
• C'est une classe qui représente une abstraction d'une table qui
se compose de plusieurs enregistrements constitués de
colonnes qui contiennent les données.
• Les principales méthodes pour obtenir des données sont :
• getInt(int): retourne le contenu de la colonne dont le numéro est passé
en paramètre sous forme d'entier.
• getInt(String): retourne le contenu de la colonne dont le nom est passé
en paramètre sous forme d'entier.
• getFloat(int): retourne le contenu de la colonne dont le numéro est
passé en paramètre sous forme de nombre flottant.
• next(): se déplace sur le prochain enregistrement : retourne false si la
fin est atteinte
• getMetaData(): retourne un objet ResultSetMetaData qui permet
d'obtenir des informations sur le résultat de la requète.
• Ainsi, le nombre de colonne peut être obtenu grâce à la méthode
getColumnCount de cet objet.
ResultSetMetaData rsmd;
rsmd = results.getMetaData();
nbCols = rsmd.getColumnCount();
La classe ResultSet: methode next()

• La méthode next() déplace le curseur sur le prochain enregistrement


• Le curseur pointe initialement juste avant le premier enregistrement :
il est nécessaire de faire un premier appel à la méthode next() pour ce
placer sur le premier enregistrement.
• Des appels successifs à next permettent de parcourir l'ensemble des
enregistrements.
• Elle retourne false lorsqu'il n'y a plus d'enregistrement
• Il faut toujours protéger le parcours d'une table dans un bloc de
capture d'exception
La classe ResultSet: methode getXXX()

• Les méthodes getXXX() permettent d'extraire les données selon leur


type spécifiée par XXX tel que getString(), getDouble(), getInteger(),
etc.
• Il existe deux formes de ces méthodes :
• indiquer le numéro la colonne en paramètre (en commençant par 1)
• ou indiquer le nom de la colonne en paramètre.
Traitement des données retournées

Les colonnes d’une table de la BD sont référencées par leur numéro (commençant par 1)
ou par leur nom.
L’accès aux valeurs des colonnes se fait par des méthodes de la forme getXXX (…)
permettant la lecture de données du type XXX dans chaque colonne du tuple courant.

int val = rs.getInt (3) ; // acces à la 3e colonne

String prod = rs.getString ("Produit") ;// acces à la colonne de nom Produit


JDBC : exemple de Requête SQL
1. public test_jdbc {
2. public static void main (String[] args) {
3. Connection maCo = initConnection();
4. if (maCo == null) return;
5. try{
6. Statement st=co.createStatement();
7. ResultSet rs=st.executeQuery("select*from etudiant");
8. while(rs.next()){
9. System.out.print(rs.getInt(1)+" ");
10. System.out.print(rs.getString(2)+" ");
11. System.out.print(rs.getString(3)+" ");
12. System.out.println(rs.getString(4));
13. }
14. rs.close(); st.close(); maCo.close();
15. }catch(Exception e){}
16. }
17.}
La classe ResultSet: methode next()

//parcours des données retournées


try {
ResultSetMetaData rsmd = résultats.getMetaData();
int nbCols = rsmd.getColumnCount();
boolean encore = résultats.next();
while (encore) {
for (int i = 1; i <= nbCols; i++)
System.out.print(résultats.getString(i) + " ");
System.out.println();
encore = résultats.next();
}
résultats.close();
} catch (SQLException e) {
//traitement de l'exception
}
Correspondance Types données SQL/Java

Si vous écrivez une instruction telle que String prenom = rs.getString ("nom") ;
cela signifie que vous êtes convaincu que la colonne nom a été créée sous
SQL avec le type VARCHAR. Autrement cette instruction causerait une erreur de
runtime.
Donc il est bon de savoir la correspondance entre types SQL et types Java pour pouvoir
manipuler convenablement les données lues.

Types SQL Types Java Méthodes


CHAR/ VARCHAR String getString ( )
INTEGER int getInt ( )
TINYINT byte getByte ( )

SMALLINT short getShort ( )


Correspondance Types données SQL/Java

Types SQL Types Java Méthodes


BIGINT long getLong ( )
bit boolean getBoolean ( )
REAL float getFloat ( )
NUMERIC DECIMAL java.math.BigDecimal getBigDecimal ( )
DATE java.sql.Date getDate ( )
TIME java.sql.Time getTime ( )
TIMESTAMP java.sql.TimeStamp getTimeStamp ( )
FLOAT DOUBLE double getDouble ( )
Langage SQL

• «Structured Query langage» i.e «langage d’interrogation structuré».


• SQL est présent dans principaux SGBDR et chacun de ces derniers a sa
propre variante
• Il est à la fois:
• Un langage de définition de données( LDD: ordre CREATE, ALTER, DROP)
• Un langage d’interrogation de la base de données( ordre SELECT)
• Un langage de manipulation de données (LMD: ordres UPDATE, INSERT,
DELETE)
• Un langage de contrôle de l’accès aux données (LCD: ordres GRANT, REVOKE)
Nous prendrons comme exemple le schéma relationnel suivant:

Clients(cod_client, nom_client, prenom_client, ville)


Produits(cod_prod, designation, prix_unitaire, taux_tva, stock)
Commandes(num_com, date_com, commande_reglee)
Lignes_commandes(num_com, cod_prod, quantite)
Fournisseurs(cod_fournisseur, nom_fournisseur, ville, teleph)
Fournisseurs_produits(cod_fournisseur, cod_client)
Commandes de définition de données(1)
1. Création d’une table
La clause CREATE TABLE permet de créer une table en définissant le nom et le type de
chacune des colonnes de la table.
Syntaxe:
CREATE TABLE nomTable
(colonne1 type1,
colonne2 type2,

colonnen typen);
Exemple:
CREATE TABLE Clients
( cod_client COUNTER,
nom_client CHAR(15),
prenom_client VARCHAR(20),
ville char(16));
Commandes de définition de données(2)

2. Suppression d’une table


Syntaxe: DROP TABLE nom_table;

Exemple:
DROP TABLE Clients;
Commandes de définition de données(3)

3. Modification d’une table


Clause ALTER TABLE
• Ajout d’une colonne
ALTER TABLE nom_table
ADD nouveau_champ type_nouveau_champ;
Exemple:
ALTER TABLE Clients
ADD date _naiss DATE;
ou
ALTER TABLE Clients
ADD COLUMN date_naiss DATE;
Commandes de définition de données(4)

• Suppression d’une colonne


Syntaxe:
ALTER TABLE nom_table
DROP colonne_a_supprimer;
Exemple
ALTER TABLE Clients
DROP date_naiss;
ou
DROP COLOMN date_naiss;
Commandes de définition de données(5)

4. Définition de contraintes d’intégrité


• Clause NOT NULL
CREATE TABLE Clients
( cod_client COUNTER,
nom_client CHAR(15) NOT NULL,
prenom_client VARCHAR(20),
ville char(16));
NULL sera interdit dans le champ nom_client.
• Clause CHECK
On restreint les valeurs possibles de l’attribut commande_reglee dans la table Commandes
CREATE TABLE Commandes
(num_commande COUNTER,
date_commande CHAR(20),
commande_reglee CHAR(5) CHECK(commande_reglee IN (‘oui’, ‘non’));
Commandes de définition de données(6)
4. Définition de contraintes d’intégrité
• Index sans doublon: clause UNIQUE
CREATE TABLE Clients
( cod_client COUNTER,
nom_client CHAR(15) UNIQUE,
prenom_client VARCHAR(20),
ville char(16));
• Clause PRIMARY KEY
CREATE TABLE Clients
( cod_client COUNTER PRIMARY KEY,
nom_client CHAR(15) NOT NULL,
prenom_client VARCHAR(20),
ville char(16));
Commandes de définition de données(7)
5. Création et suppression des relations
Soit les tables Clients et Commandes créées respectivement à partir des commandes suivantes:
CREATE TABLE Clients
( cod_client COUNTER,
nom_client CHAR(15),
prenom_client VARCHAR(20),
ville char(16));
Et
CREATE TABLE Commandes
(num_commande COUNTER,
date_commande CHAR(20),
commande_reglee CHAR(20),
cod_client INTEGER);

Modifions la table Clients et choisissons le champ cod_client comme clé primaire


ALTER TABLE Clients
ADD PRIMARY KEY(Cod_client);

Le champ code_client de Clients étant clé étangère dans Commandes, nous créons la relation 1-n entre Clients et Commandes comme suit:
ALTER TABLE Commandes
ADD FOREIGN KEY (cod_client) REFERENCES Clients (cod_client);
Les commandes de Manipulation (1)

On distingue les trois types de requêtes suivants:


• L’ajout
• La suppression
• La mise à jour
Les commandes de Manipulation (2)
1. Ajout d’un enregistrement
commande INSERT
INSERT INTO ligne_de_commande(num_commande, cod_prosuit, quantite) VALUES (1, ‘p1’, 40)
Si dans la table Clients num_client est de type COUNTER, nus insérons une nouvelle valeur comme suit:
INSERT INTO (nom_client, prenom_client, ville)VALUES (‘Modou’, ‘Pouye’, ‘Banjul’)
2. Suppression d’un enregistrement
Commande DELETE
DELETE FROM Clients
WHERE nom_client=‘Modou’;
Supprime le client de nom Modou

DELETE*FROM Clients;
Supprime toutes les lignes de la table «Clients»
3. Mise à jour d’un enregistrement:
Commande UPDATE
UPDATE<nom de la table>
SET <nom colonne1> = <nouvelle valeur1>

<nom colonnen> = <nouvelle valeur n>
[WHERE <condition>]
Les commandes de recherche (1)

• L’ordre SELECT possède six clauses différentes dont seules les deux premières sont obligatoires
SELECT [predicat] <description de colonnes>: renvoie une description de colonnes résultat
FROM <nom d’une relation ou de plusieurs relations>
[WHERE <condition logique qui définit les tuples du résultat>]
[GROUP BY <critere>]
[ORDER BY <critere>]
[HAVING <critere>
• Le prédicat est utilisé pour décrire le traitement des lignes doublons en retour. Il peut prendre les
valeurs:
ALL,
DISTINCT,
DISTINCT ROW,
TOP [nombre ou pourcentage]
Les commandes de recherche (2)

• La condition logique qui définit les tuples du résultat peut être une expression simple ou plus au
moyen d’un opérateur logique:
WHERE exp1=exp2
WHERE exp1!=exp2
WHERE exp1<exp2
WHERE exp2>exp2
WHERE exp1 BETWEEN exp2 AND exp3
WHERE exp1 LIKE exp2
WHERE exp1 NOT LIKE exp2
WHERE exp1 IN (exp2, exp3,…)
WHERE exp1 NOT IN (exp2, exp3,…)
WHERE exp IS NULL
WHERE exp IS NOT NULL
Les commandes de recherche (3)
1. La sélection simple
Quelles sont les coordonnées des clients de la ville de Dakar?
SELECT * // * signifie tous les attributs
FROM Clients
WHERE ville =‘dakar’;

Quelles sont les commandes pour lesquelles les quantités commandées du produit
‘P01’ sont supérieures à 15?
SELECT num_commande
FROM ligne_de_commande
WHERE code_produit= ‘P01’
AND quantite > 15;
2. Le tri
Donner par ordre alphabétique croissant les noms et villes des clients du magasin
SELECT nom_client, ville
FROM Clients
ORDER BY nom_client ASC, ville ASC

Vous aimerez peut-être aussi