Java Av Cour
Java Av Cour
Les applications ont très souvent besoin d’accéder à des ressources externes, qui
fournissent ou reçoivent des données de l’application (donc transite ou transfert de
données), comme :
– fichiers, mémoire, les pipes.
Introduction et principe de E /S
Introduction et principe de E /S
Les fichiers:
Java fournit des classes qui représentent les flux et permettent leur manipulation, l’ensemble
– se sont des fichiers localisés sur disque dure de ses classes constitue le package java.io (la bibliothèque des E/S).
La mémoire: – Certains types de flux agissent sur la façon dont sont traitées les données qui transitent
par leur intermédiaire :
– se sont des variables représentant: E/S bufférisées, traduction de données (d’un codage à autre par exemple), …
des caractères,
des tableaux de caractères, – Pour réaliser la gestion souhaitée pour les E / S, on peut combiner différents types de
flux.
des bytes ou tableaux de bytes,
des String – Généralement,
des StringBuffer
Si le flux provient d’une source extérieure (clavier, fichier...) vers le programme: on
parle alors de flux en lecture.
Les pipes:
– se sont des canaux qui permettent de : Si le flux vient du programme et écrit dans un fichier, à l’écran ou autre... : on parle
communiquer des informations entre deux programmes (ou deux alors de flux en écriture.
«threads») qui s’exécutent concurremment (notion de synchronisation)
le package java.io prend en charge de nombreux type de sources de données et d’opérations
sur ces données.
transiter des données à travers le réseau
M.AFILAL 3 M.AFILAL 4
Introduction et principe de E /S Introduction et principe de E /S
L’information lue ou écrite est représentée par un flux de données, deux types d’objets sont
utilisés dans ce but : Application
– Un flux physique,
il prend en charge le type de la source de données.
– Il sait, par exemple, comment lire le contenu d’un fichier.
Filtre de lecture Filtre d’écriture
– Un filtre,
il prend en charge la manière de gérer le flux:
Transmet le flux Retransmet le flux
– la manière de lire ou d’écrire les données.
Par exemple, pour optimiser la lecture.
Flux physique Flux physique
Remarque:
– Un filtre ne sait pas accéder à une source physique (fichier, mémoire, pipe), Lecture du flux Écriture du flux
il s’appuie sur un objet de type flux physique.
Source de données Destination de
données
M.AFILAL 5 M.AFILAL 6
La bibliothèque des E\S propose quatre hiérarchies ou catégories de classes (des classes de
flux) qui permettent où qui dérivent des postulas suivants :
Des accès en mode binaire (lecture ou écriture octet par octet : 8 bits)
Des accès en mode texte (ou mode caractère, un caractère unicode: 16 bits en java).
Remarque: Les flux de lecture et des flux d’écriture sont différenciés (les classes de
lecture sont différents de celles de d’écriture).
M.AFILAL 7 M.AFILAL 8
Introduction et principe de E /S Règles pour les flux des E /S
InputStream :
Pour accéder à une source de données, il faut déterminer :
– Classe qui gère le flux d’entrée « accès séquentiel en mode binaire en lecture (mode
octet) ». Le type de gestion :
– accès directe, lecture séquentielle ou écriture séquentielle,
OutputStream :
– Classe qui gère le flux de sortie « accès séquentiel en mode binaire en écriture (mode
octet) ». Le type d’accès :
– mode binaire ou mode caractère.
Reader :
– Classe qui permet un accès en lecture « accès séquentiel en lecture en mode caractère ». Le type de la source de données :
– fichier, mémoire, pipe:
Writer :
– Classe qui permet un accès en écriture « accès séquentiel en écriture en mode caractère ». disque dure, console, écran, etc.….,
M.AFILAL 9 M.AFILAL 10
import java.io.File;
public class GestionFile {
– public GestionFile() { }
– // Méthode permettant l'affichage des caractéristiques d'un fichier s’il existe.
if (f.exists()) {
– System.out.println(f.getName() + " : " + (f.canRead() ? "r" : "-")
+(f.canWrite() ? "w" : "-") + " :: " + f.length());
– f.delete(); // attention
}
else {
– System.out.println("fichier non existant ");
}
M.AFILAL 13 – } M.AFILAL 14
– Pour la lecture :
Création de l’objet d’un type héritant d’InputStream
Invocation de la méthode read
Fermeture par la méthode close « si pas d’utilisation de try with resource »
– Pour l’écriture :
Création de l’objet d’un type héritant d’OutputStream
Invocation de la méthode write
Fermeture par la méthode close « si pas d’utilisation de try with resource »
M.AFILAL 19 M.AFILAL 20
Les flux physiques
ByteArrayInputStream :
Les filtres pour accès séquentiel binaire en lecture
– Permet de lire une zone mémoire (un tableau d’octets).
FileInputStream :
– Permet la lecture des données contenues dans un fichier byte par byte.
ObjectInputStream :
– Elle possède différentes méthodes pour lire tout type de données (primitifs ou objets).
PipedInputStream :
– Lecture de bytes dans un canal de communication entre deux applications:
une application va lire ce qui est écrit par l’autre application.
– Utilisée dans la communications via les réseaux et les gestions des processus légers (les
threads).
Permet de faire communiquer deux thread (processus légers)
Tout ce qui est écrit dans un tube par un thread est lu dans l’ordre par l’autre thread
SequenceInputStream :
– Représente la concaténation de plusieurs flux de lecture en un seul.
– Lorsqu’on atteint la fin d’un flux, la lecture continue sur le flux suivant.
StringBufferInputStream :
– Lecture de bytes depuis un string (la source est traitée comme un string, une chaîne de
caractères).
M.AFILAL 21 M.AFILAL 22
– Cette classe et l’ensemble de ses méthodes sont dépréciées car convertissent mal les
caractères en octets (bytes).
FileInputStream (elle ne sait lire que des octets se trouvant dans un fichier) et – ZipInputStream zin = new ZipInputStream ( new FileInputStream ("monfichier.zip"));
DataInputStream (elle ne sait pas lire depuis un fichier mais elle sait lire les types – DataInputStream din = new DataInputStream (zin);
primitifs de java)
– double b = din.readDouble ( );
– permet de combiner leurs caractéristiques :
Remarque
FileInputStream fic = new FileInputStream ("fichier"); – ZipInputStream est un filtre qui est une sous classe de FilterInputStream
DataInputStream din = new DataInputStream (fic);
double d = din.readDouble
M.AFILAL( ); 25 M.AFILAL 26
Exemple _2 Exemple _3
public void lectureParBloc(int dimBloc) { public void lectureParBlocBuffered(int dimBloc) {
– FileInputStream fis = null; – byte[ ] buffer = new byte[dimBloc];
– byte[ ] buffer = new byte[dimBloc]; – BufferedInputStream fis = null;
– int i = 0; // compteur de nombre byte lus depuis le flux – int i = 0; // affichage de nombre total de byte lu dans le flux
– try { – try {
File fichier = new File("E:/Documents and Settings/Administrateur/Bureau/Dossier1mm.mp3"); – // accès au fichier via un Buffer donc lecture plus rapide
fis = new FileInputStream(fichier);
fis = new BufferedInputStream(new FileInputStream("C:/Documents and
Calendar calDeb = Calendar.getInstance(); Settings/Administrateur/Bureau/dossier1/chanson.mp3"));
// création d'un objet de type Calendar avec des valeurs de date et heures système Calendar calDeb = Calendar.getInstance();
avant début de la lecture
for (int j = 0; j < 3000; j++) { for (int j = 0; j < 3000; j++) {
// création d'un objet de type string avec le tableau de byte buffer – String s = new String(buffer);
– String s = new String(buffer); – System.out.println(s);
// affichage de la chaîne de caractère lu dans le tableau buffer – i += fis.read(buffer);
– System.out.println("chaîne de caractère lu dans l'itération " + j + " est: " + s); }
– i += fis.read(buffer); Calendar calFin = Calendar.getInstance();
} System.out.println( i );
Calendar calFin = Calendar.getInstance(); // temps après fin de la lecture System.out.println("temps de lecture en ms = " + (calFin.getTimeInMillis() -
System.out.println( i ); calDeb.getTimeInMillis()));
System.out.println("temps de lecture en ms = " + (calFin.getTimeInMillis() - – }catch (FileNotFoundException e) { System.out.println("Fichier non trouvé.");
calDeb.getTimeInMillis( ) ) ); – }catch (IOException e) { System.out.println("Impossible de lire");
– }catch (FileNotFoundException e) { System.out.println("Fichier non trouvé1");
– } finally {
– }catch (IOException e) { System.out.println("Impossible de lire");
if ( fis != null ) {
– } finally {
if (fis != null) { – try { fis.close(); // fermeture du flux }
– try { fis.close(); // fermeture du flux } – catch (IOException e) { System.out.println("problème dans la fermeture du flux"); }
– catch (IOException e) { System.err.println("problème dans la fermeture du flux"); } }
} M.AFILAL 27 – } M.AFILAL 28
– }catch (NullPointerException e) {
System.err.println("Fichier non trouvé");
– }catch (FileNotFoundException e) {
System.err.println("Fichier non trouvé");
– }catch (IOException e) {
System.err.println("Impossible de lire4");
– }finally{
if (dis != null) dis.close( );
– } M.AFILAL 29 M.AFILAL 30
}
– flush( ) :
Cette méthode permet de vider le buffer et force l’écriture des données dans le flux.
(Demande d'écrire dans le flux ce qu'il y a dans le buffer).
M.AFILAL 33 M.AFILAL 34
FileOutputStream :
– Permet l’écriture de données dans un fichier dont le nom est donné dans le constructeur.
ByteArrayOutputStream :
– Implémente un flux de sortie dans lequel les données sont écrites dans un tableau de
byte. Le buffer augmente au fur et à mesure que des données sont écrites.
M.AFILAL 35 M.AFILAL 36
Les filtres pour accès séquentiel binaire en écriture Les filtres pour accès séquentiel binaire en écriture
Un filtre pour les accès en écriture s’appuie sur un objet de type OutputStream qui récupère le
contenu du flux :
Le filtre traite les données du flux puis les retransmets à l’objet flux associé.
– La classe BufferedOutputStream:
Permet d’utiliser un buffer pour accélérer l’écriture.
– La classe DataOutputStream:
Exemple : lecture et écriture par bloc Exemple _1: lecture et écriture byte par byte
– int c;
– os.close();
– is.close();
}
Méthode permettant de copier, avec format lecture binaire, le contenu d'un fichier et le mettre,
avec format d'écriture binaire, dans un autre fichier.
M.AFILAL 39 M.AFILAL 40
Exemple _2 Exemple _3
Méthode permettant d'écrire, sous format binaire, un texte à la fin d'un fichier, jusqu'a entrée , Méthode permettant d'écrire dans un fichier en utilisant la classe PrintStream avec association
via le clavier, d’un string de taille nulle. Elle retourne une exception de type IOException d'un buffer, ce qui permet une conversion des types primitif en format string.
public void copieEcriture1(String dest) throws IOException {//* public void ecritureAvecPrintStream(String nomFichier) {
– FileOutputStream os = null; – File fich = new File(nomFichier);
– try { – int a = 10;
os = new FileOutputStream(dest, true); – char s = 'y';
while (true) { – boolean b = true;
– String str = (new DataInputStream(System.in)).readLine(); – try {
– if(str.equals("")) break; FileOutputStream fos = new FileOutputStream(fich, true);
– os.write(str.getBytes( )); // écriture de bloc de byte BufferedOutputStream bos = new BufferedOutputStream(fos);
} PrintStream dos = new PrintStream(bos);
– }catch (NullPointerException e) { dos.println(a);
System.out.println("Fichier introuvable."); dos.println(s);
– } dos.println(b);
– finally { dos.println("le code est simple avec printStream");
if (os != null) os.close( );
dos.close( );
– }
– }catch (FileNotFoundException e) {
}
System.out.println("Fichier non trouvé");
– }catch (IOException e) {
Remarque:
System.out.println("Impossible d’écrire dans le fichier");
– System.in est un objet de type inputStream, permet de lire les entrées clavier sous format
binaire – }
M.AFILAL 41 } M.AFILAL 42
– Premier cas de figure: Cette interface définit deux méthodes publiques : readExternal() et writeExternal().
lorsqu'une classe hérite d'une classe sérialisable, elle se comporte comme si elle – Utiliser ces méthodes pour contrôler la façon d’enregistrer ou de lire des objets à stocker
avait implémenté elle-même l'interface Serializable. via un flux de données.
Les attributs de la classe mère sont sérialisés selon l'implémentation de celle-ci. private void writeExternal (java.io.ObjectOutputStream out) throws IOException;
private void readExternal (java.io.ObjectInputStream in) throws IOException,
– Deuxième cas de figure: ClassNotFoundException;
une classe implémente l'interface Serializable et hérite d'une classe non sérialisable.
– Il y a ici deux points fondamentaux à savoir : Par défaut
les attributs hérités ne sont pas sérialisés. – la sérialisation d'un objet qui implémente cette interface ne prend en compte aucun
il est nécessaire que la classe étendue (la classe mère) possède un attribut de l'objet (pas de sérialisation par défaut).
constructeur par défaut accessible ; dans le cas contraire, une
InvalidClassException est levée à l'exécution. Remarque :
– le mot clé transient est donc inutile avec une classe qui implémente l'interface
Externalisable
– Une classe implémentant l'interface Externalizeable doit posséder un constructeur par
défaut public:
M.AFILAL 49 qui sera utilisé dans la déserialisation afin d’initialiser les champs sans valeur des
M.AFILAL 50
objets stockés (surtout si cette classe hérite d’une classe non sérialisable)
Exemple
}
Remarques importantes pour la sérialisation Liste des différents flux primaires, classés par catégorie
Remarque dans le cas de champ statique
Lors de la sérialisation, on aura seulement la valeur nulle qui sera affectée au champ statique.
– Pour remédier à cela, on utilisera, par exemple, le code suivant qui permet la sérialisation
pour le champ statique : champStatique ou transient .
class newSerialisation implements Serializable {
– private static final long serialVersionUID = 4L;
– private static int champStatique = 0;
// Autres champs: non-transient , non-statique champs.
– /*Ceci impose que l’écriture et la lecture du champ statique doivent être
traitées à part*/
– private void writeObject(ObjectOutputStream oos) throws IOException {
// appel des mécanismes de sérialisation automatique par défaut (via le
mot Serializable définissant la classe)
– oos.defaultWriteObject( );
– oos.writeObject(new Integer(champStatique));
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, bytes
IOException {
– ois.defaultReadObject();
– champStatique = (Integer)M.AFILAL
ois.readObject(); 53 M.AFILAL 54
}
}
La question qu'on pourrait se poser est: pourquoi des flux spéciaux pour les caractères alors
que ce sont des données binaires ?
– La réponse est que Java, contrairement à beaucoup d'autres langages, utilise Unicode.
Ces flux servent donc à gérer les jeux de caractères (conversion possible d'un jeu à
l'autre: choix d’encodage approprié).
Il faut privilégier ces classes pour être compatible avec les alphabets internationaux.
M.AFILAL 55 M.AFILAL 56
Accès séquentiel en mode texte Accès séquentiel en mode caractère en lecture
Les classes de flux gérant ce type d’accès sont les sous-classes des classes Reader et Writer. La classe Reader fournit:
– Attention: – Des méthodes permettant la lecture de caractères.
Par défaut les objets, des classes Writer ou Reader, utilisent l’encodage privilégié par – Ses méthodes read( ) sont similaires à celle avec les flux de binaires.
le système (réellement ses classes utilisent l’encodage par défaut de la JVM qui est – La seule méthode abstraite qu’elle implémente est la méthode :
dépendant du système). int read(char[ ] cbuff, int off, int len).
– Cela signifie que l’écriture dans un fichier, par exemple, peut aboutir à la perte – Elle permet de lire un caractère ou un tableau de caractères
des informations, due à un encodage incapable de prendre en compte certain Elle stocke les len caractères lus dans le tableau de char à partir de la
caractère. position off.
– Remarque:
les classes InputStream / OutputStream manipule des octets (byte en Java) donc Autre méthodes de lecture
dépendant de la plateforme
– int read( ) :
Lit le prochain caractère sur le flux et le retourne sous forme d’int.
Les concepts et méthodes utilisés pour les flux binaires ont été adaptés aux flux de caractères.
Il y a donc de fortes similitudes avec ce qui a été vu dans le cours de flux binaire. Pour l’utiliser réellement sous forme de caractère (char), il sera nécessaire de faire
une conversion explicite (cast).
– int read(char[] cbuff) :
Pour accéder à une source de données, il faut déterminer :
Elle stocke les caractères lus dans le tableau de char.
L’accès en lecture ou en écriture
Le type de la source de données : fichier, mémoire, etc.….
Cette classe possède également les méthodes
La manière de gérer le flux : choisir le filtre adéquat (peut être aucun).
– close( ), mark(int readlimit), markSupported( ), reset( ), skip(long n).
– Elle possède aussi une méthode boolean ready( ) qui teste s’il est possible de lire sans
bloquer le flux.
M.AFILAL 57 M.AFILAL 58
PushBackReader:
– permet de revenir en arrière dans un flux,
Elle est dotée d’une méthode unRead() qui permet de remettre du texte dans le flot
d’entrée, comme s’il n’avait pas déjà été lu. « pas ou jamais utilisée »
PipedReader :
– classes utilisée pour les communications via les réseaux et les gestions des processus.
InputStreamReader :
– Cette classe va permettre la communication entre les flux d’entrée d’octets et les flux d’entrée
de caractères.
– En effet,
il va lire les octets pour ensuite les transformer en caractères en utilisant un jeu de
caractères spécifique (Charset). «elle lit les octets et les décodes en caractères en utilisant
un encodage »
– Ce jeu de caractères sera celui de la plateforme par défaut, mais peut être spécifié
par l’utilisateur lors de l’instanciation :
InputStreamReader(InputStream in, Charset cs).
Permet la conversion octets vers caractères.
– Objectif :
choisir un encodage adapté aux type de données a lire.
construire un Reader à partir d’un InputStream. C’est particulièrement utile avec
System.in.
M.AFILAL 59 M.AFILAL 60
FileReader:
– cette classe (qui hérite de InputStreamReader) décrit tout flux texte entrant attaché à un fichier.
Accès séquentiel caractère en lecture Exemple pour lecture de caractère
StringReader :
– Cette classe permet la lecture d’une chaîne de caractères fournie dans le constructeur Remarque
StringReader(String s).
– boolean markSupported( ): indique si le flux supporte la possibilité de marquer des
CharArrayReader : positions
– Cette classe permet la lecture d’un tableau de caractères « flux de caractères d’entrée ». – boolean ready( ): indique si le flux est prêt à être lu
BufferedReader :
– Cette classe va permettre Exemple
une lecture bufférisée des flux de caractères d’entrée,
– public static void testLectureTexte (InputStream input) throws IOException {
la possibilité de fixer la taille du buffer dans le constructeur.
la possibilité de revenir en arrière dans la lecture, à l’aide des méthodes mark et reset try (InputStreamReader f lux= new InputStreamReader(input)){
– void mark (int _limite) throws IOException // Le résultat de read doit être un entier (à cause du -1 qui est renvoyé en
place une marque à la position courante de lecture. l’argument limite permet de fixer fin de fichier)
le nombre maximum de caractères qui pourront être lus en préservant la marque.
– void reset ( ) throws IOException int cc;
remet la tête de lecture à la position de la dernière marque posée. – while ( (cc = f lux.read()) != -1){
– public long skip(long n) throws IOException
Permet de sauter n caractères dans le flux // Pour ranger cc dans un char, il faut un cast :
Un autre intérêt du BufferedReader est la disponibilité de la méthode readLine : char c= (char)cc;
– String readLine ( ) throws IOException
– }
renvoie la ligne suivante sous forme de String, ou null si on est à la fin du fichier.
ce sont des caractères Unicode qui sont lus, représentés par 2 octets consecutives. }
LineNumberReader: – }
– C’est une sous classe de BufferedReader, elle est dotée d’une méthode getLineNumber qui permet de
connaître le numéro de la ligne courante.
M.AFILAL 61 M.AFILAL 62
import java.io.*;
Pour l’écriture en mode texte:
public class LectureTextFichier { – on utilise la classe Writer (classe abstraite) et ces classes dérivées.
elle permet l’écriture de flux de caractères.
– void lectureSimple(String nomFile) { elle impose l’implémentation des méthodes suivantes :
try(LineNumberReader in = new LineNumberReader(new FileReader(nomFile))) { – close( ):
/* lecture d'un fichier avec FileReader puis bufferisé avec affichage de Elle permet la fermeture d’un flux (il faudra tout d’abord vider les
ligne par la classe LineNumberReader */ ressources utilisées par le flux avec la méthode flush( )).
– String ligne; – flush( ):
/* lecture ligne par ligne*/
Elle permet de vider les ressources utilisées par le flux courant.
– while((ligne = in.readLine( )) != null) // fin de fichier si null
System.out.println(in.getLineNumber( ) + " : " + ligne) ; – write(char[] cbuf, int off, int len):
}catch (IOException e) { Elle permet l’écriture d’intervalle de tableau de caractères
– System.out.println(e); Elle permet d’écrire un caractère ou un tableau de caractères
– System.exit(0);
}
– }
} // voir la classe LectureTextFichier
M.AFILAL 63 M.AFILAL 64
Accès séquentiel caractère en écriture Accès séquentiel caractère en écriture
PipedWriter :
– classe utilisée pour les communications via les réseaux et les gestions des processus.
Cette classe va être connectée à un PipedReader.
PrintWriter :
– Cette classe implémente toutes les méthodes de la classe PrintStream, elle produira une
sortie formatée en string comme printf en C++.
– Cette classe peut utiliser un encodage différent du celui du système hôte
– Les méthodes de la classe PrintWriter
ne déclenchant pas d’exception, ce sera à l’utilisateur de gérer cela en utilisant la
méthode checkError( ), qui existe aussi dans PrintStream
– public boolean checkError ():
Appelle la méthode flush () et renvoie true si une erreur ou exception est
survenue pendant un appel aux autres méthodes de cette classe.
OutputStreamWriter :
– Cette classe va permettre
la communication entre les flux d’entrée de caractères et les flux d’entrée d’octets.
– Elle permet la conversion d’un flux de caractères en un flux de données
binaires.
– En fait,
L’encodage à utiliser (différent de celui du système utilisé), il peut être spécifié par
l’utilisateur lors de l’instanciation, avec
– OutputStreamWriter (OutputStream out, Charset cs).
M.AFILAL 67 M.AFILAL 68
Accès séquentiel caractère en écriture Exemple _1
FilterWriter : On utilise un objet adapté (ici un Writer pour l’écriture et un reader pour la lecture).
– Permettre d’écrire des flux de données filtrées.
– public static void testEcritureTexte(String fname) throws IOException {
BufferedWriter : – // On crée un objet Writer, ce qui ouvre le fichier fname
– Permet l’écriture Bufférisée de texte vers un flux de sortie de caractères FileWriter f= new FileWriter(fname);// On utilise cet objet pour écrire
f.write("Bonjours ");
FileWriter: f.write(" à tous.");
– écriture dans un fichier. f.write(" Java c’est facile !");
f. flush( ); // on vide les ressources utilisées par le flux f
CharArrayWriter : f.close( ); // On ferme le flux
– Cette classe implémente une mémoire tampon de caractères qui peut être utilisée comme – }
un objet Writer.
– On peut spécifier sa taille à l’aide du constructeur CharArrayWriter. – public static void testLectureTexte (String fname) throws IOException {
FileReader f = new FileReader(fname);
StringWriter : int cc = f.read();
– Cette classe représente un flux de caractères qui recueille sa sortie dans un objet while (cc != -1){
StringBuffer // Pour ranger cc dans un char, il faut un cast :
«ceci en utilisant la méthode getBuffer() de la classe StringWriter qui retourne un – System.out.println((char) cc);
objet de type StringBuffer)», – cc = f.read(); // Lecture du suivant.
lequel peut alors être utilisé pour construire une chaîne de caractères }
f.close();
69
– } 70
M.AFILAL M.AFILAL
Exemple _2: écriture bufférisée dans un fichier Exemple _3: lecture bufférisée dans un fichier
Ecriture de caractères dans un fichier, en utilisant BufferedWriter Lecture de caractères depuis le fichier de l’exemple précédant, en utilisant BufferedReader
– import java.io.*; – import java.io.*;
– public class Ecrire{
public static void main(String[] args){ – public class LireLigne{
– Try(FileWriter fw =new FileWriter(“C:\\temp\\essai.txt"); – public static void main(String[ ] args){
BufferedWriter bw= new BufferedWriter(fw)){ try(FileReader fr = new FileReader(“C:\\temp\\essai.txt ");
bw.write("Ceci est mon fichier"); BufferedReader br = new BufferedReader(fr)){
bw.newLine(); // saut de ligne
bw.write("Il est à moi...");
– }catch (Exception e){ while (br.ready()) System.out.println(br.readLine());
System.out.println("Erreur "+ e);
– } }catch (Exception e){
} System.out.println("Erreur "+e);
– } }
– }
}
M.AFILAL 71 M.AFILAL 72
Remarque: conversion d’information Exemple avec modification d’encodage
Ecriture de caractère sur un fichier sous format binaire avec un encodage spécifique UTF-8,
ceci en utilisant OutputStreamWriter
Conversion des caractères d ’un fichier avec un codage explicitement indiqué. – public void writeOutput(String str) {
– InputStreamReader in = new InputStreamReader ( new FileInputStream try (FileOutputStream fos = new FileOutputStream("C:/dossier1/output.doc");
("C:\\dossier1\\chinoix.doc"), "ISO2022CN");
Writer out = new OutputStreamWriter(fos, "UTF-8") ){
– out.write(str);
}catch (IOException e) {
– e.printStackTrace();
}
– }
M.AFILAL 73 M.AFILAL 74
M.AFILAL 77 M.AFILAL 78
Exemple_3 Exemple _4
M.AFILAL 79 M.AFILAL 80
Fichier En accès directe Fichier En accès directe
Contrairement aux flux séquentielle, il existe un mécanisme qui permet d’accéder directement Les méthodes de lecture permettent de lire des données binaires.
à toute information présente dans un fichier sans obligation de lire le début du fichier.
– int read ( ) throws IOException
La classe RandomAccessFile gère: lit un octet non signé.
– L’accès directe aux données dans un fichier. On a de même que pour les Reader, des méthodes read à un et trois arguments, qui
– L’accès en lecture ou lecture/écriture en mode binaire. permettent de remplir des tableaux.
– La lecture et l’écriture des types primitifs java et des chaînes de caractères. – Des méthodes pour lire une valeur d’un type de base:
readBoolean, readByte, readChar, readDouble, readFloat, readInt, readLong,
Cette classe implémente les interfaces DataOutput et DataInput readShort, readUnsignedByte, readUnsignedShort.
– boolean readBoolean () throws IOException
Les fonctions importantes: lit un booléen.
– RandomAccessFile (String nomFile, String mode) throws FileNotFoundException – readByte lit un octet signé (entre -127 et 128.)
Crée un RandomAccessFile ouvert sur le fichier nommé nomFile. – readUTF: permette de lire sous format unicode UTF8
Le mode peut être
– r pour un fichier ouvert en lecture seule Les méthodes d’écriture qui permettent d’écrire des données binaires:
– rw pour un fichier ouvert en lecture/écriture. – on a d’une part trois méthodes write :
– void close () throws IOException : elle ferme le fichier void write (byte [ ] b, int dep, int longueur) throws IOException
– écrit les octets du tableau b, de l’indice dep à l’indice (longueur -1),
une méthode writeXXX par type de base, comme par exemple
– writeChar.
– writeUTF: permette d’écrire sous format unicode UTF8
M.AFILAL 81 M.AFILAL 82
M.AFILAL 83 M.AFILAL 84
Interfaces graphiques
Interface Graphique
La conception d’interfaces graphiques étant loin d’être triviale, et les packages proposés pour
cela par le JDK étant parmi les plus « complexes ».
Le but de ce chapitre est de donner les éléments de bases qui permettent la construction et la
création d’interfaces utilisateur.
M.AFILAL 85 M.AFILAL 86
Ceci nécessité une API pour les interfaces graphiques indépendantes des – Les concepteurs de machines virtuelles JAVA étaient contraints de fournir
plateformes
un package AWT différent pour chaque système d’exploitation.
Ensemble de classes et interfaces java
Ainsi qu’un modèle de gestion des événements
– Ce package AWT chargé de faire le lien
entre le langage java et les serveurs graphiques des différents systèmes
– Exemple : une classe TextField pour définir un champ de saisie de texte d’exploitation dans lesquels la machine virtuelle de JAVA est implantée :
TextField(String content); TextField()
void setText(String content); String getText() – Exemple de serveur graphique
X Window + motif, X Window + gtk
MacOS X, MS Windows
– On général, on a deux stratégies sont possibles pour construire des interfaces graphiques
Faire une utilisation maximale du système graphique cible (qui sera utilisé)
Faire une utilisation minimale du système graphique cible (qui sera utilisé)
M.AFILAL 87 M.AFILAL 88
Interface Graphique Interface Graphique
Utilisation minimale du système graphique sous-jacent
Utilisation maximale du système graphique sous-jacent
– Utiliser des éléments natifs ou des adaptateurs uniquement pour des opérations de base
– Exemple: L'objet TextField délègue la plupart de ses tâches à un composant natif (un Ouvrir une fenêtre, dessiner des lignes/du texte, gestion primitive des événements.
composant du serveur graphique du système d’exploitation utilisé). C.à.d.
Si le programmeur java utilise un objet TextField
– Réaliser tout le reste en Java
Objet TextField délègue la plupart de ses tâches à une classe adaptatrice(un fichier)
propre au système d’exploitation utilisé, qui peut être: L'objet TextField s'affiche en dessinant des lignes,...
– MotifTextField, GTKTextField, WindowsTextField, MacOSTextField .... – pas d’utilisation de classes adaptatrices propres au système.
Donc, le système graphique natif réalise le plus gros du travail
– Avantages / désavantages
– Avantages / désavantages (+) facilité d'éviter les différences entre plateformes
(+) apparence et le comportement (look and feel) des interfaces Java identique à (+) n'importe quel nouveau composant d'interface est immédiatement disponible sur
celui d'applications "ordinaires du système utilisé" toutes les plateformes
(+) pas besoin de ré-implémenter des composants existants (-) besoin de ré-implémenter tous les composants d'interface
(-) ne fournit que les composants disponibles sur la plateforme utilisatrice (-) les applications java n'ont pas le même look and feel que les applications
"ordinaires"
(-) difficile de garantir un comportement identique sur toutes les plateformes
(-) lenteur.
– Choix adopté, dans ce cas, est java.awt
Le choix adopté, dans ce cas est, SWING
AWT Abstract Window Toolkit
– Le package est javax.swing. dans JDK depuis version 1.2
Le package java.awt.* présent dans Java depuis la version 1.0.
– Swing s'intègre aux JFC (Java Fundation Classes lancés par SUN en 97 pour la création
Palette de composants fournies par AWT ne contient que des composants simples, d’interfaces graphiques plus élaborées que AWT et intégré depuis version 2 de Java(1.2))
seuls les composants standard existants dans tous les systèmes d’exploitation
peuvent être présents dans AWT. JFC = Java 2D API + copier coller inter-applications + Swing + Accessibilité.
M.AFILAL 89 M.AFILAL 90
M.AFILAL 93 M.AFILAL 94
Les conteneurs
Containers de haut niveau
Containers génériques
– JPanel :
Object Il s’agit d’un conteneur rectangulaire opaque et invisible, qui est destiné à contenir
d’autres composants.
Contient un FlowLayout par défaut. (gestionnaire de disposition ou placement)
Les attributs généralement modifiés sont la couleur du fond, les bords, ainsi que
ObjectComponent l’appel à la méthode
– void setLayout(LayoutManager mgr):
pour gérer la manière dont ses composants sont placés.
– JScrollPane :
Container Permet de visualiser un objet trop grand.
– Au lieu d’écrire directement dans un JPanel :
textArea = new JTextArea(5, 30);
UnFrame.add(textArea, BorderLayout.CENTER);
JComponent Window Panel – On peut le mettre préalablement dans un JScrollPane :
textArea = new JTextArea(5, 30);
JScrollPane scrollPane = new JScrollPane(textArea);
JWindow Frame Dialog Applet unFrame.add(scrollPane, BorderLayout.CENTER);
M.AFILAL M.AFILAL 98
JMenuItem JMenu
Pour construire une application autonome graphique, il faut dériver de javax.swing.JFrame JComboBox
– On utilisera: JRadioButtonMenuItem
Des JFrames pour construire des applications. JLabel JToggleButton
JCheckBox
Des boites de dialogues afin d’afficher des messages d’avertissement ou autres.
JList
JRadioButton
Ci-dessous, on retrouve l’arborescence, qui dérive de JComponent, dont:
– Les containers: génériques, spécifiques.
JMenuBar
– Les composants de base.
JComponent
JPanel
JPopupMenu
JScroolPane JTextArea
JFileChooser
JInternalFrame Pour utiliser un composant, il faut créer un nouvel objet représentant le composant et l'ajouter
JDesktopPane
à un conteneur qui existe avec la méthode add( ).
JLayeredPane
JTabbedPane
JTable
JToolBar
JToolTip
JTree
JViewport
JInternalFrame.JDesktopPane
M.AFILAL 101 M.AFILAL 102
– L'espace entre l'image et le texte est déterminé par la propriété iconTextGap (utilisation
105 de la méthode setIconTextGap(int)). 106
Un JCheckbox est un composant graphique pouvant être soit dans l’état « on » (true) ou dans
l’état « off » (false).
– C’est en cliquant sur la boite à cocher que son état passe de la valeur « on » à la valeur « Constructeur Rôle
off » et vice-et-versa.
JCheckbox() Créer une boite à cocher sans libellé «une
Il est possible de spécifier deux icônes qui seront utilisés pour afficher les états «on» et «off» étiquette ou texte associé a la boite à cocher»
d’un JChekBox « en construisant une classe personnalisée qui implémente l’interface Icone.
JCheckbox (String label) Créer une boite à cocher avec un libellé.
Les états des JChekbox sont indépendants les uns des autres. JCheckbox (String label, boolean state) Créer une boite à cocher avec un libellé et
indication de l’état :
Cette classe possède plusieurs constructeurs false = désactivée, true = activée.
JCheckbox (Icon icon) Créer une boite à cocher en spécifiant une
image.
JCheckbox (Icon icon, boolean state) Créer une boite à cocher spécifiant une image
et un état initial.
JCheckbox (String label, con icon, boolean state) Créer une boite à cocher spécifiant un libellé,
une image et un état initial.
void addActionListener(ActionListener L)
– Pour enregistrer un écouteur d’événement ActionEvent auprès de la boite à cocher. public void setText(String text)
L’écouteur recevra le message actionPerformed(ActionEvent) à chaque fois que – Pour spécifier le libellé de la boite à cocher
l’état de la boite à cocher aura été modifié
public void setSelected(boolean b)
void removeActionListener(ActionLitener L)
– Pour spécifier l’état de la boite à cocher.
– Pour désinscrire un écouteur d’événement.
Exemple Exemple
class AfficheIcon implements Icon {
public class TesteJCheckBox extends JFrame {
– boolean etat;
– public TesteJCheckBox() { – public AfficheIcon(boolean etat) {
setTitle("Teste boite à cocher"); this.etat = etat;
getContentPane().setLayout(new FlowLayout()); – }
JCheckBox ch1 = new JCheckBox("option1"); – public void paintIcon(Component c, Graphics g, int x, int y) {
getContentPane().add(ch1); g.setColor(Color.red);
JCheckBox ch2 = new JCheckBox("option2"); if (etat) {
– g.fillOval(x, y, getIconWidth(), getIconHeight());
getContentPane().add(ch2);
}
getContentPane().add(new JCheckBox("option3", true)); else {
– // associé un Icon à un JChekBox – g.draw3DRect(x, y, getIconWidth(), getIconHeight(), true);
Icon imageIconTrue = new AfficheIcon(true); }
Icon imageIconFalse = new AfficheIcon(false); – }
JCheckBox ch4 = new JCheckBox("option4"); – public int getIconWidth() {
ch4.setIcon(imageIconFalse);// CheckBox non sélectionné return 10;
– }
ch4.setSelectedIcon(imageIconTrue); );// CheckBox sélectionné
– public int getIconHeight() {
getContentPane().add(ch4); return 10;
this.pack(); – }
//this.setSize(150, 150); }
– } public class testeMain {
} – public testeMain() { }
– public static void main(String[ ] args) {
(new TesteJCheckBox()).setVisible(true);
M.AFILAL 111
– } M.AFILAL 112
}
JRadioButton(boutons radio) et GroupButton Exemple *
Il est possible d’insérer une image à l’intérieur d’un bouton, l’image devant être manipuler au
Un JButton est un composant graphique, susceptible d’être « cliqué » par l’utilisateur, travers d’un objet de type icon.
– et qui répondra à cet événement en envoyant le message actionPerformed(…) à tous les – L’image peut être spécifiée dans le constructeur lui-même, ou en utilisant la méthode
objets qui seront inscrit auprès de lui en tant qu’écouteur. setIcon(uneIcone)
Exemple: Exemple
– public class TesteJButton extends JFrame{ – public class TesteJButton extends JFrame{
public TesteJButton() { public TesteJButton() {
– setTitle("Teste de Jbutton"); – setTitle("Teste de Jbutton");
– JButton bouton = new JButton("mon bouton"); – getContentPane( ).setLayout(new GridLayout(2, 1));
– getContentPane().add(bouton); – JButton bouton = new JButton("premier bouton");
– pack(); – getContentPane( ).add(bouton);
} //ajout d'une image dans un bouton
– } – Icon image = new ImageIcon("C:\\ImageTeste.gif");
– JButton boutonImage = new JButton("deuxieme bouton", image);
– getContentPane().add(boutonImage);
– pack();
}
– }
void addActionListener(ActionListener L)
– Pour enregistrer un écouteur d’événement ActionEvent auprès d’un bouton.
JButton() Créer un bouton, sans labelle ni image – L’écouteur recevra le message actionPerformed(ActionEvent) à chaque fois que le
bouton aura été cliqué
JButton(Icon icon) Créer un bouton avec une image void removeActionListener(ActionListener L)
– Pour désinscrire un écouteur d’événement
JButton(String text) Créer un bouton avec un labelle
Autres méthodes (héritées de AbstractButton)
– void setIcon(Icon defaultIcon)
JButton(String text, Icon icon) Créer un bouton avec un labelle et une image
Pour spécifier l’image du bouton
– void setText(String text)
Pour spécifier le labelle du bouton
– void doClick(int pressTime)
Pour donner l’impression que le bouton est pressé pour un temps pressTime en
millisecondes.
JList Exemple
C’est une classe qui représente une liste déroulante dans laquelle l'utilisateur peut choisir un Exemple
item – JList liste = new JList();
– à préférer à une comboBox lorsque le nombre d'éléments de la liste est grand
– liste.setListData(choix);
– Permet une sélection multiple.
– liste.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
Les méthodes remarquables – liste.setLayoutOrientation(liste.HORIZONTAL_WRAP);
– setSelectionMode(int) – JScrollPane scrollPane = new JScrollPane(liste);
définir le mode de sélection: – add(scrollPane );
– ListSelectionModel.SINGLE_SELECTION
Remarque pour la méthode setLayoutOrientation:
– ListSelectionModel.SINGLE_INTERVAL_SELECTION
– ListSelectionModel.MULTIPLE_INTERVAL_SELECTION – Cette méthode permet de demander le JList.VERTICAL si la couche est une simple
– setLayoutOrientation(int) colonne de cellule,
définir l'arrangement des éléments – le JList.VERTICAL_WRAP si la couche est un style de journal avec du contenu
– VERTICAL circulant vertical puis horizontalement
– HORIZONTAL_WRAP – le JList.HORIZONTAL_WRAP si le couche est un style de journal avec contenu
– VERTICAL_WRAP circulant horizontal puis verticalement.
JTextComponent est une classe générique (abstraite) qui contient toutes les caractéristiques JTextField tf = new JTextField();
qui pourraient être utiles à la création d’un petit éditeur simplifié. – Instancier un champ de saisie (limité à une ligne de texte)
Un tooltip est un texte fugitif, dépendant du contexte, qui s’affiche dans une petite fenêtre Le composant JToolBar
quand la souris s’attarde sur un objet spécifique de l’écran. – est une espèce de conteneur qui affiche ses composants à la manière d’une barre d’outils,
verticalement ou horizontalement, en s’adaptant à la surface de l’écran dans laquelle il se
trouve placé.
La classe JToolTip, elle-même sera rarement utilisée directement.
Une barre d’outil peut être flottante:
Il suffit en effet d’utiliser la méthode setToolTipText() héritée de la classe JComponent.
– l’utilisateur pouvant la déplacer et la placer où bon lui semble
en draguant la barre d’outil dans une autre région de l’écran,
Exemple:
ou même en déplaçant cette dernière dans une fenêtre externe au conteneur
– JButton bouton = new JButton("Bonjour"); d’origine.
– Bouton.setToolTipText(“tout le monde");
– add(bouton); Pour que cette fonctionnalité fonctionne correctement:
– Il est recommandé d’ajouter la barre d’outils à l’un ou l’autre des 4 cotés d’un conteneur
dont le gestionnaire de disposition est de type BorderLayout et de ne rien placer dans les
3 côtés restants.
Par défaut, une barre d’outils à la faculté d’être flottante, pour supprimer la faculté
‘flottabilité’ d’une barre d’outils:
– unToolBar.setFlotable(false).
Donc, la manière de positionner les composants dans une interface est contrôlée par: – Un conteneur d’interface utilisateur Java (java.awt.Container) utilise un objet spécial,
appelé gestionnaire de disposition afin de:
– Des gestionnaires de disposition (LayoutManagers).
Contrôler l’emplacement et la taille des composants chaque fois qu’ils sont affichés
M.AFILAL 135
D’arranger automatiquement lesM.AFILAL
composants dans un conteneur, selon un ensemble
136
de règles propre à chaque gestionnaire de disposition
Gestionnaire par défaut des conteneurs Taille et emplacement de l’interface utilisateur
Pour toute interface utilisateur qui dérive de java.awt.Window (comme la classe JFrame), on
Certains types de conteneurs utilisent par défaut des gestionnaires de disposition spécifiques: peut contrôler sa taille et son emplacement à l’exécution
– Tous les panneaux (Les JPanel) utilisent par défaut le gestionnaire FlowLayout
La taille de la fenêtre utilisateur, telle qu’elle est définie par l’application et avant toute
– Toutes les fenêtres (y compris les cadres et les dialogues) utilisent BorderLayout intervention de l’utilisateur, est déterminée par la méthode qui est appelée en dernier dans le
code, parmi les deux suivantes:
On peut modifier le gestionnaire par défaut d’un conteneur, au moyen de la méthode
– pack( ).
setLayout(…),
Donne à la fenêtre, automatiquement, la taille minimale en respectant la taille
– Exemple: preferredSize des composants contenus dans cette fenêtre.
leContainer.setLayout(null);
leContainer.setLayout(new BorderLayout()); – setSize(largeur, hauteur).
La taille du conteneur est définie explicitement, en pixels.
– setLocation(int x, int y)
L’emplacement de l’interface utilisateur à l’exécution sera 0,0
– jusqu’à ce que l’application donne une valeur à la propriété location du
conteneur (par exemple setLocation(..) avant que l’interface ne soit affichée)
Exemple BorderLayout
Constructeur
– BorderLayout();
– BorderLayout(hgap, vgap);
Hgap(espace horizontal) et vgap(espace vertical) déterminent la distance entre les
composants (entre les zones)
M.AFILAL 143 M.AFILAL 144
Exemple *
Remarque:
– On peut utiliser la surcharge de la méthode add afin d’ajouter les composants dans le
panneau, comme ceci:
add("Center", new JButton(tab[4]));
GridLayout GridLayout
Remarque:
Le gestionnaire GridLayout place les composants sur une grille de cellule dont on spécifie:
– L’espace horizontal et l’espace vertical sont nuls par défaut
– le nombre de ligne ou le nombre de colonne et l’espace (en pixels) entre les cellules lors
de la création du GridLayout.
– Pour créer un GridLayout de 5 lignes, 8 colonnes, des espacements horizontaux et
verticaux de valeurs respectives 10 et 20 puis de l’associé à un conteneur, on fait:
Toutes les cellules ont obligatoirement la même hauteur (celle du composant le plus haut) et
même largeur(celle du composant le plus large) unConteneur.setLayout(new GridLayout(5, 8, 10, 20));
Chaque cellule contient un seul composant (simple ou conteneur) – Pour ajouter des composants dans un GridLayout, on utilise la méthode add. Les
composants sont placés dans l’ordre, ligne par ligne, en remplissant chaque ligne.
– qui occupe toute la place disponible dans la cellule
– Lorsque le nombre de ligne et de colonne est spécifié alors le nombre de colonne est
Outre le nombre de lignes et de colonnes qu’on peut spécifier, ignoré.
– on peut spécifier le nombre de pixels entre les cellules en utilisant les paramètres Ainsi par Exemple GridLayout(5,4) est équivalent à GridLayout(5,0). On aura 5
d’espace horizontal (hgap) et d’espace vertical (vgap) lignes (avec des lignes vides possibles, en fonction du nombre des composants à
insérer)
Constructeurs:
– GridLayout(lignes, colonnes); – GridLayout(0,4): on aura 4 colonnes (avec des colonnes vides possibles ou des cases
– GridLayout(lignes, colonnes, hgap, vgap); vides, en fonction du nombre des composants à insérer)
CardLayout CardLayout
BoxLayout BoxLayout
Ce gestionnaire de disposition permet d’aligner les composants selon un axe horizontal (une
seule ligne) ou un axe vertical (une seule une colonne).
– Les axes sont définis par les constantes : Avec BoxLayout:
X_AXIS (horizontale) et Y_AXIS (verticale), – chacun des composants utilise une place variable en fonction de ses dimensions
LINE_AXIS et PAGE_AXIS (dépendent de l'orientation: propriétés de l’objet PreferredSize et MaximalSize
ComponentOrientation)
– les composants sont alignés en fonction de leur paramètre alignementX et alignementY
Ce gestionnaire de disposition organise les composants, en respectant l’ordre d’addition, sur
une seule ligne (axe vertical ) ou une seule colonne(axe horizontal) Arrangement selon l’axe primaire:
Les composants sont ajoutés – Ce gestionnaire permet à chaque composant d’occuper un espace spécifique selon l’axe
– de gauche à droite pour une ligne, primaire.
– de haut en bas pour une colonne (depuis la gauche par défaut).
– Si on choisit l’axe vertical comme axe primaire,
Lorsque la ligne ou la colonne est pleine, on ne déborde pas, mais il y a réduction ou un JTextField occupera moins de place verticalement qu’un JTextArea.
masquage.
En utilisant
– composant. setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT), dans
le cas d’alignement LINE_AXIS et PAGE_AXIS, l’ajout sera
de droite vers la gauche pour une ligne
de haut vers le bas mais depuis la droite pour une colonne
– S’il s’agit d’un BoxLayout vertical (l’axe primaire = BoxLayout.Y_AXIS ou Pour améliorer la disposition des éléments on peut :
BoxLayout.PAGE_AXIS), – régler les espaces entre les éléments en ajoutant des composants invisibles:
le gestionnaire tentera de rendre chaque composant aussi large que le plus large composants Strut et Glue (pour placer un menu Aide à droite dans une barre de
parmi tous les composants. menus par exemple), Filler et Rigid Area.
– Si le composant ne peut s’accroître de cette manière (sachant que la size max est donné Pour enjoliver les cadres : utiliser des JPanel pour contenir les Box, et leur mettre des bords
par getMaximumSize()), (avec titres ou autres).
le gestionnaire appliquera les propriétés Y-Alignement ou X-Alignement du
composant afin de déterminer comment placer le composant au sein de l’espace
disponible.
Constructeur:
– Un strut, est un composant réduit à un espacement rigide « de taille fixe » qui Tout espace supplémentaire est absorbé par la glue.
représentent:
soit un séparateur horizontal avec une largeur fixée: Plusieurs glues peuvent se partager l’espace libre.
– Box.createHorizontalStrut(5)
soit un séparateur verticale avec une hauteur fixée: Remarque :
– Box.createVerticalStrut(5)
– On centre les composants en mettant une glue des deux côtés
– Un area (un aire) est une zone rigide avec une dimension fixée en largeur et en hauteur:
Box.createRigidArea(new Dimension(50, 20)))). – On maintient les composants aux bords en insérant une glue au milieu
– Un Filler (un remplisseur), il défini un espacement non rigide avec une dimension
minimale, une dimension préférée et une dimension maximale:
new Box.Filler(new Dimension(5,100), new Dimension(50,150), new
Dimension(Short.MAX_VALUE,200))
La politique de disposition des onglets peut prendre l’une ou l’autre des valeurs – addTab(String title, Icon icon, Composant component, String tip)
suivantes: Permet en plus de spécifier un tooltip (texte d’aide fugitif) qui serait associé à
– JTabbedPane.WRAP_TAB_LAYOUT l’onglets
ou
– JTabbedPane.SCROLL_TAB_LAYOUT. – insertTab(String title, Icon icon, Composant component, String tip, int index)
Pour insérer une carte, qui occupera la position indiquée par l’index, passé en
paramètre.
– Par défaut, on a WRAP_TAB_LAYOUT
Remarque
– La politique de disposition est mise en œuvre dès l’instant qu’il n’y a pas assez de place
pour afficher les onglets sur une seule ligne ou une seule verticale.
M.AFILAL
– Par défaut (dans les deux premiers constructeurs): TOP et WRAP_TAB_LAYOUT 163 M.AFILAL 164
JTabbedPane (panneaux à onglets)
JTabbedPane (panneaux à onglets)
Pour retirer des cartes:
– Remove(int index)
Pour supprimer l’onglet correspond à l’indice passé en paramètre
– removeAll( )
Pour supprimer tous les onglets.
Événements spécifiques:
– addChangeListener(ChangeListener L)
Pour s’inscrire un écouteur de changement
– removeChangeListener(ChangeListener L)
Pour retirer un écouteur de changement.
Exemple * GridBagLayout
public class TesteTabbedPane extends JFrame{ GridBagLayout est une disposition extrêmement souple et puissante
– String tab[ ] = { "un", "deux", "trois", "quatre", "cinq", "six"}; – Elle permet un meilleur contrôle du positionnement des composants sur la grille
– public TesteTabbedPane() { (matrice) que celui fourni par Gridlayout.
super("Teste TabbedPane");
getContentPane().setLayout(new BorderLayout()); GridBagLayout positionne les composants horizontalement et verticalement sur une grille
JTabbedPane centre = new JTabbedPane(JTabbedPane.BOTTOM, rectangulaire.
JTabbedPane.SCROLL_TAB_LAYOUT); – il n’est pas nécessaire que les composants soient de même taille, chacun pouvant remplir
for (int i = 0; i < tab.length; i++) { plusieurs cellules.
– centre.addTab(tab[i], new JButton("ONGLET " + tab[i])); – il place les composants sur une grille, mais la hauteur des lignes et la largeur des
colonnes peut varier.
}
– un composant est placé sur une cellule dans la grille (sa position) mais il peut occuper
getContentPane().add(centre, BorderLayout.CENTER); plusieurs cellules en hauteur ou en largeur
pack();
– } GridBagLayout détermine l’emplacement des composants qu’il contient en se basant sur:
} – les contraintes et la taille minimum et préférée de chaque composant,
– La taille préférée (preferredSize) du composant est utilisée si la taille du conteneur le
permet si non, la taille minimale est utilisée.
– gridy:
– Ces panneaux imbriqués peuvent utiliser d’autres dispositions, et contenir d’autres
Ligne où sera placé le composant (par défaut = RELATIVE)
panneaux de composants si nécessaires.
– gridwidht:
La première étape lors de l’utilisation d’un GridBaglayout est de schématiser l’apparence de Nombre de colonnes couverte par le composant (par défaut = 1)
l’interface utilisateur.
– gridheight:
– Tracer une grille sur l’interface afin de décomposer ses éléments en lignes et colonnes. Nombre de lignes couverte par le composant (par défaut = 1)
GridBagLayout GridBagLayout
fill:
Les lignes ci-dessous décrivent plusieurs champs de la classe GridBagConstraints
– Indique dans quelle direction doit éventuellement augmenter le sous-composant dans le cas de
redimensionnement
– Les deux champs weightx et weighty permettent de définir comment l'espace Elle est caractérisée par l’une des constantes suivantes de GridBagConstraints:
supplémentaire, existant sur une ligne ou colonne sera distribué parmi les composants – NONE: signifie pas de changement dans la dimension horizontale et dans la dimension
horizontalement (weightx) et verticalement (weighty). verticale du composant (valeur par défaut).
– VERTICALE: signifie que la dimension verticale du composant sera modifiée.
weightx: « le poids horizontale associé à un composant » – HORIZONTAL: signifie que la dimension horizontal du composant sera modifiée.
– Partie de l’espace supplémentaire horizontale à attribuer à un composant(cas – BOTH: signifie que la taille du composant pourra changer dans les deux dimensions
de redimensionnement).. Les composants peuvent s’élargir si on leur attribue anchor:
de l’espace supplémentaire – Définie l’emplacement du composant quand ce dernier est plus petit que son espace réservé:
si weightx = 0 le composant garde sa taille horizontale dans le cas de Elle est associée aux constantes suivantes:
redimensionnement à condition que tous les autres composants se – NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST,
trouvant dans la même colonne ne s’agrandit pas. NORTHWEST ou CENTER (par défaut centre)
REMAINDER:
weighty: « le poids verticale associé à un composant »
– Spécifie qu’un composant est le dernier composant dans sa ligne ou sa colonne.
– Partie de l’espace supplémentaire vertical à attribuer(cas de RELATIVE:
redimensionnement. . Les composants peuvent s’agrandir si on leur attribue de – Dans le cas gridx ou gridy:
l’espace supplémentaire.
spécifie qu’un composant est placé juste après le précédant composant placé.
si weighty = 0 le composant garde sa taille verticale dans le cas de – gbc.gridy = GridBagConstraints.RELATIVE;
redimensionnement à condition que tous les autres composants se – Dans le cas gridwidth, gridheight:
trouvant dans la même ligne ne s’agrandit pas).
spécifie qu’un composant est l’avant dernier composant dans sa ligne ou sa colonne
INSET
La somme des poids horizontaux d’une même ligne doit être 1. – spécifie le remplissage externe du composant, spécifie l’espace minimum entre le composant et la
La somme des poids verticaux d’une même colonne doit être 1. frontière de sa zone d’affichage (donnant les marges en haut, à gauche, à droite et en bas ).
M.AFILAL 171 M.AFILAL 172
Exemple Aucun gestionnaire de placement
ipadx:
– ajoute des pixels « ipadx » à la taille minimum du composant en largeur Il suffit de spécifier la valeur null lors de l’appel a setLayout.
– Espacement à gauche et à droite autour du composant
largeurNew = largeurOld+2*ipadx.
Il faut alors spécifier les coordonnées des composants dans un repère dont
ipady:
– ajoute des pixels « ipady » à la taille minimum du composant en hauteur – l’origine est le coin en haut à gauche conteneur,
– Espacement au dessus et au dessous du composant. – l’axe des X dirigé vers la droite
– l’axe des Y vers le bas.
Voir la classe: – On utilise pour cela la méthode
– ProjetInterfaceGraphSwing.TesteGridBagLayout
setBounds (int x, int y, int w, int h) définie dans la classe Component.
A faire
– ProjetInterfaceGraphSwing. ExoAvecGridBagLayout
– ProjetInterfaceGraphSwing. Exo1AvecGridBagLayout
Remarque:
– La valeur par défaut de JDialog est non modal
M.AFILAL 175 – La valeur par défaut de JOptionPane est modal, si son parent est non null. 176
Boite de dialogues: JDialog Boite de dialogues: JDialog
un Jdialog est une fenêtre secondaire permettant à l'utilisateur:
– d’afficher des messages informatifs ou d’avertissements,
– de demander certaines informations à l’utilisateur, Constructeur (exemple) Barre de titre Parent Mode
– de répondre à une question, etc….
Une fois les actions terminées, la boite de dialogue se referme. JDialog( ) vide hidden frame non modal
Un JDialog dépend toujours d'une fenêtre (frame ou Dialog ou Window ) qu'on appelle son JDialog(Frame parent, String title) title parent non modal
propriétaire (owner).
– Le JDialog subira les mêmes actions que sa fenêtre propriétaire, JDialog(Frame parent, boolean modal) vide parent modal (si true)
par exemple,
JDialog(Frame parent, String title,
– si le propriétaire est iconisé, le JDialog disparaîtra pour réapparaître dés que title parent modal (si true)
boolean modal)
son propriétaire sera agrandi.
Pour construire un JDialog, on peut utiliser, comme pour les JFrame: JDialog(Frame parent) Vide Parent non modal
– sa méthode getContentPane( ) qui renvoie son panel racine, on peut ensuite y mettre ce
que l'on veut comme composant.
– sa méthode setContentPane() pour fixer brutalement son panel racine.
Exemple:
– Un JFileChooser est un JDialog tout prêt pour sélectionner un fichier.
M.AFILAL 177 M.AFILAL 178
Exemple *
Boite de dialogues: JDialog
public class TesteJDialog extends JFrame {
– JDialog boitDia;
– public TesteJDialog() {
setTitle("Teste JDialog");
boitDia = new JDialog(this, "Avertissement !!!. ", true);
getContentPane().setLayout(new FlowLayout());
setLocation(350, 350);
setSize(250, 250);
boitDia.setSize(150, 150);
/*boitDia.setLocation( (int) (getLocation().getX() + (getWidth() -
boitDia.getWidth()) / 2), (int) (getLocation().getY() + (getHeight() -
boitDia.getHeight()) / 2));*/
boitDia.setLocationRelativeTo(this);
setVisible(true);
boitDia.setVisible(true);
– }
}
Les prototypes des méthodes, dans le cas le plus générale, sont donnés par:
Un JOptionPane permet d’afficher des boîtes de dialogue simples sans avoir à gérer d’objet,
c’est une fenêtres modales: elle bloque l’exécution. – static int showConfirmDialog(Component parentComponent, Object message,
String title, int optionType, int messageType, Icon icon)
La classe JOptionPane définit un certain nombre de méthodes statiques, de la forme
showXxxDialog afin de créer et d’afficher des boîtes de dialogue modales standards. – static Object showInputDialog(Component parentComponent, Object message,
String title, int messageType, Icon icon, Object[ ] selectionValues,
Object initialSelectionValue)
– static Object showInternalInputDialog(Component parentComponent, Object message, Pour afficher un message en offrant des boutons comme options de réponse.
String title, int messageType, Icon icon, Object[] selectionValues, – int rep = JOptionPane.showConfirmDialog(null,"Ça va bien?", "Bonjour",
Object initialSelectionValue) JOptionPane.YES_NO_OPTION);
if(rep == JOptionPane.YES_OPTION) //traitement si l’utilisateur a appuyé sur oui.
– static int showInternalConfirmDialog(Component parentComponent, Object message, else //traitement si l’usager a appuyé sur non.
String title, int optionType, int messageType, Icon icon) – Le nombre de boutons et le texte qui y est inscrit dépend du paramètre optionType, la
langue du texte des boutons dépend de la configuration du système.
– FocusEvent : – ItemEvent :
Se produit s’il y a changement de place du curseur déclenché quand un item d'un objet (implémentant ItemAdjustable) a changé d'état
– InputEvent : « classe abstraite » (sélection ou désélection d’un item d'une liste, cochage d'une case …)
Se produit lorsque l’événement provient du clavier (KeyEvent) ou souris – AdjustmentEvent :
(MouseEvent) déclenché quand une valeur a été modifiée dans un objet implémentant Adjustable
– KeyEvent : (barre de défilement, JScrollBar,…)
Se produit lorsque un événement provient du clavier. Exp : pression d'une touche. – TextEvent :
– MouseEvent : déclenché si la valeur d'un objet texte a changé.
Se produit lorsque un événement provient de la souris. Exp : déplacement de la
souris. Remarque:
– ContainerEvent : – Des méthodes sont attachées à chacune de ces classes pour avoir accès à plus de détails
Lors d'ajout ou de suppression d'un composant dans un conteneur sur l'événement.
– WindowEvent : Exemple:
Lors d’ouverture, fermeture, redimensionnement et mouvement de la fenêtre – récupérer le composant source de l'événement,
– ActionEvent : – la position de la souris lors du click,
Lors des actions effectuées sur des objets de l'interface (click sur un bouton, – Etc.….
double-click dans une liste, …)
Les événements : une hiérarchie de classes structurées Les événements : une hiérarchie de classes structurées: non
Tout événement a: Le message envoyé par l’écouteur, en réponse de l’événement xxxEvent déclenchée par le
– une source composant graphique (la source de l’événement), correspondra:
– une destination qui va subir les conséquences de cet événement.
au résultat de l’appel d’une méthode, définie dans la classe de l’écouteur, qui prend
en argument l’événement reçu ( xxxEvent).
Exemple d’événement:
– Ceci entraîne une action sur la destination via le code de cette méthode.
– Clique sur un bouton,
– déplacement de la souris sur une zone,
Pour lier et associer, l’objet écouteur à l’objet écouté qui peut déclencher un événement
– pression sur un bouton du clavier ou autre. xxxEvent,
– le composant écouté (la source) doit appeler la méthode addXXXListener() en passant en
Exemple de classes événement: paramètre l’objet Ecouteur qui se chargera de traiter l’événement.
– ActionEvent, ItemEvent, KeyEvent, MouseEvent, … objetEcouté.addxxxListener(ObjetEcouteur)
– Donc, Ces écouteurs doivent être explicitement affectés aux composants concernés
Un composant graphique peut déclencher un événement xxxEvent, qui doit être capturé par
un écouteur (un observateur) capable de le traiter. Remarque
– Un composant peut déclencher plusieurs types d’événements.
– xxx est la catégorie d’événement déclenchée par le composant graphique. – Il faut alors un écouteur pour chaque type d’événement afin de le gérer
Exemple de catégorie
– key, mouse, window, …
– L’écouteur est un objet d’une classe
implémentant l’interface xxxListener
ou extends une classe xxxAdapter.
M.AFILAL 195 M.AFILAL 196
Principe de délégation: non Principe de gestion des événements**
Pour chaque composant pouvant déclencher un événement, donc nécessitant une gestion
Les composants stimulés(clique sur un composant par exemple), délèguent la gestion des d’événement, on doit:
événements utilisateur à un objet d’une classe (externe, interne ou anonyme) – spécifier le type ou la catégorie d’événement pour lequel il doit réagir (exemple de catégorie:
Mouse, Key, Action …, )
Principe de délégation Pour gérer ce type d’événement (xxxEvent: xxx est la catégorie de l’événement)
– on doit spécifier un objet observateur d’événement (cad un écouteur ou un Listener),
– Une source d'événement (un composant graphique dérivant de Component) qui est C’est un objet d’une classe (interne ou externe ou anonyme) qui gèrera l’événement.
l’objet observé: – L’écouteur est un objet d’une classe
Émet un événement vers un observateur (délégué ou écouteur ou un listener) implémentant l’interface xxxListener
capable de le traiter. ou extends une classe xxxAdapter
Pour cela:
– L’observateur (objet d’une classe implémentant les interfaces Listener ou extends des – L’observateur doit s’abonner ou être relié aux événements du composant.
classes Adapter) – Car la gestion de l'évènement est déléguée « ou transmise » à un écouteur d'évènements qui
active le traitement associé selon le type d’évènement (Action, Key, Mouse listener)
Indique qu'il est intéressé par l’événement envoyé par la source, en implémentant
une (ou plusieurs) interface graphique spécifique dérivant de java.util.EventListener Pour s’abonner:
ou extends une classe adaptatrice. – Un observateur s’abonnera à une catégorie d’événements déclenchée par l’objetObservé, en
faisant appel à la méthode addXXXListener(.):
– Pour relier effectivement la source et l’observateur, ce dernier doit préalablement
s'enregistrer auprès de la source (l’objet observé) via la méthode addxxxListener(.); objetObservé.addXXXListener(objetObservateur) ;
Exemple: – car l’observateur est susceptible de recevoir un message de l’un ou l’autre des
événements pour des catégories d’événements différents.
– un observateur s’abonnant aux événements d’un bouton, clique sur le bouton, donc
l’événement est de catégorie « Action »
Une ou plusieurs méthodes doivent être prévue pour chacun d’entre eux
leBouton.addActionListener(this) ; Exemple:
– Cas de clique de boutons ou déplacement de souris dans une fenêtre qui est définie (c.a.d
La JFrame contenant le bouton est l’observateur, elle doit: la fenetre) comme observateur des deux événements
Liste des catégories d’événements Autres infos concernant les interfaces Listener ou les gestionnaires d’événements
Le tableau présenté ci-dessous dresse la liste de certaines catégories d’événement qu’un
composant graphique est susceptibles de générer
Méthodes pour enregistrer un observateur à un composant émetteur: AWT 1.1 fournit pour chaque interface Listener une classe adaptatrice
– Javax.swing.JComponent
addComponentListener(ComponentListener) – qui définit toutes les méthodes, de l’interface Listener, avec un corps vide.
addFocusListener(FocusListener)
addKeyListener(KeyListener) – leurs noms correspondent à ceux des interfaces, à ceci près que ‘Listener’ est remplacé
addMouseListener(MouseListener) par ‘Adapter’.
addMouseMotionListener(MouseMotionListener) Ainsi, il suffit de sous-classer cette classe adaptatrice et de redéfinir simplement la
méthode qui nous intéresse : les autres sont héritées de la classe adaptatrice
– Javax.swing.JDialog – (création de classe qui extends la classe adaptatrice puis de l’utiliser comme
observateur dans le code principale).
addWindowListener(WindowListener)
– Attention :
– Javax.swing.JFrame
Java ne fournit pas d’héritage multiple,
addWindowListener(WindowListener)
il est impossible de dériver une classe de plusieurs classes adaptatrices, il faut alors
implémenter les interfaces correspondantes ou des sous classes internes, externes ou
– Javax.swing.JButton anonymes.
addActionListener(ActionListener)
– Javax.swing.JComboBox
addItemListener(ItemListener)
– Javax.swing.JScrollbar
addAdjustmentListener(AdjustmentListener)
M.AFILAL 207 M.AFILAL 208
Listes des interfaces « Listener »
Remarque
L’une des grandes innovations de Java 1.1 est l’apparition des classes internes :
Le tableau ci-dessus décrit la liste de ces interfaces
– celles-ci sont des classes définies à l’intérieur d’autres classes. – La première colonne indique la catégorie d’événements
– La seconde colonne indique le nom de l’interface
– Une classe interne peut accéder à tous les membres définis dans la classe englobante. – La troisième colonne indique le nom de la classe d’adaptatrice correspondante (si elle
existe)
– On utilisera très souvent de telles classes pour la gestion des évènements : – La quatrième, enfin, donne la liste des méthodes contenues dans l’interface
on définit pour chaque type d’évènement que l’on veut traiter une classe interne, qui
implémente l’interface correspondante ou dérive d’une classe adaptatrice.
On peut aller encore plus loin, et ne même pas nommer la classe destinée à traiter un
évènement, en la définissant directement dans l’appel à son constructeur:
– Se sont les classes anonymes
Les bases de données fournissent un mécanisme de stockage persistant pour les données
Remarque
d’application et dans bien des cas,
– l'API analogue au JDBC en langage C est ODBC.
– elles sont essentielles au fonctionnement des applications.
– Les paquetages java.sql et javax.sql (JDBC 2.0) regroupent la plupart des interfaces et les
classes de l'API JDBC et les autres peuvent venir du paquetage du Driver utilisé
Java propose une API pour l’accès aux bases de données relationnelles
« dont la plupart de ses classes et interfaces dérivent de java.sql et javax.sql ».
– JDBC (Java DataBase Connectivity).
– La plupart des méthodes se trouvant dans les classes du paquetage java.sql ou javax.sql
ou du paquetage du Driver utilisé
JDBC: lèvent l'exception java.sql.SQLException.
– c'est une API (Application Programming Interface) constituée d’un ensemble de classes
et d’interfaces permettant de développer des applications capables de se connecter à des
Les principales étapes pour manipuler une base de données sont:
serveurs de bases de données (SGBD)
– Charger et installer un pilote (un driver) JDBC approprié à la BD.
Donc, cette API permet l'accès à des données de type table de bases de données
SGBD relationnelles : – Se connecter à une base de données.
– ouvrir une connexion avec le SGBD – Envoyer une requête SQL.
– envoyer des requêtes SQL au SGBD – Manipuler (récupérer et parcourir) le résultat.
– récupérer des données retournées par des requêtes SQL
– traiter ces données "table"
– gérer les erreurs retournées par des requêtes au SGBD
M.AFILAL 213 M.AFILAL 214
Remarque
– Il existe différents drivers JDBC pour différentes bases de données (les drivers
M.AFILAL 215 M.AFILAL 216
dépendent du SGBD utilisé)
Étape 1: charger le pilote Étape 1: charger le pilote
Ce qui se passe réellement
– La méthode Class.forName charge ou inscrit le driver, dans la liste des driver ,donné comme
paramètre
ceci via la création d’une instance de type de la classe donné comme paramètre.
– Exemple: Class.forName("com.mysql.cj.jdbc.Driver“);
Retourne la classe com.mysql.cj.jdbc.Driver.class
Puis, cette classe créer une instance:
(com.mysql.cj.jdbc.Driver.class).newInstance()
Class.forName("com.mysql.cj.jdbc.Driver“).newInstance()
– Cette instance exécute dynamiquement la méthode DriverManager.registerDriver(pilote), ceci
permet
d’enregistrer le driver ou le pilote donné comme paramètre de la méthode registerDriver
et de l’ajouter dans la liste des driver
– Exemple: DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver( ) );
On ouvre une connexion avec une des méthodes La syntaxe d'une URL JDBC est:
– DriverManager.getConnection( URLjdbc ); – jdbc:<sous-protocole>:<baseID>
– DriverManager.getConnection( URLjdbc, "dbUser1", "pwuser1" ); « la plus générale »
Exemples d’URL
Qui retourne un objet d'une classe qui implémente l'interface Connection.
– jdbc:odbc:DsnName
DSN (Data Source Name)
Ces méthodes contiennent: – jdbc:odbc:test1
– Le premier argument est une "URL JDBC". – jdbc:odbc:@orsay:1751:test1
– Puis, un nom d’utilisateur et un mot de passe (pour la plus part des pilotes) pour valider la – jdbc:oracle:thin:@orsay:1751:test1
connexion à la base de données . – jdbc:mysql://db.myhost.com:3306/mydatabase
Ces méthodes recherchent le pilote adapté pour gérer la connexion avec la base repérée par Remarque
cette URL.
– La classe DriverManager:
– Une URL JDBC
Cette classe est une classe qui ne contient que des méthodes statiques.
Doit commencer par le protocole qui est toujours égal au préfix jdbc.
Elle fournit des méthodes qui sont des utilitaires pour gérer l'accès aux bases de
Le second argument est le sous protocole: il donne le driver utilisé. données par Java et les différents drivers JDBC à l'intérieur d'un programme Java.
– Il définit le mécanisme de connexion pour un type de base de données – baseID peut contenir
Le troisième argument est un identificateur de base de données. le nom de la machine hôte ou son adresse IP,
le port du sous protocole utilisé ou le port par défaut ou port de connexion
M.AFILAL 219 M.AFILAL 220
le nom de la base de données à laquelle on doit se connecter
Étape 2: établir une connexion Étape 2: établir une connexion
Pour établir la connexion avec SQL Server, il faut préciser Pour établir la connexion avec MySQL, il faut préciser
– le nom de la machine (ou son numéro IP), – le nom de la machine (ou son numéro IP),
– le port où le service SQL est démarré (quasiment toujours 1433), – le port où le service SQL est démarré (quasiment toujours 3306),
– le nom de la base de données, – le nom de la base de données,
– le login utilisé ainsi que son mot de passe. – le login utilisé ainsi que son mot de passe.
La syntaxe utilisée pour spécifier la base de données à laquelle nous souhaitons nous La syntaxe utilisée est:
connecter prend la forme d’une URL – Connection conn = null;
try {
try { – Class.forName("com.mysql.cj.jdbc.Driver");
– String strClassName = "com.microsoft.jdbc.sqlserver.SQLServerDriver"; – conn =
– String strUrl = "jdbc:microsoft:sqlserver://hostname:1433; databaseName = DriverManager.getConnection("jdbc:mysql://db.myhost.com:3306/mydatabase");
databaseName; user = sa; password = passWord";
Charger le pilote – /* conn =
– Class.forName(strClassName); DriverManager.getConnection("jdbc:mysql://localhost:3306/database", "user",
– Connection conn = DriverManager.getConnection(strUrl); "password"); */ // avec trois paramètres
– // un seul parametre dans getConnection. . . . .
Ouvrir une connexion – // . . .
– conn.close(); – conn.close();
Autres opérations } catch(ClassNotFoundException e) {
} catch(ClassNotFoundException e) { – System.err.println("Driver non chargé !");
– System.err.println("Driver non chargé !"); – e.printStackTrace();
– e.printStackTrace(); } catch(SQLException e) {
} catch(SQLException e) { // . . . } M.AFILAL 221
– // . . . M.AFILAL 222
}
Requête SQL avec statement: Exemple Requête SQL avec statement: exemple avec SELECT
On utilisera dans ce cas les méthodes getXXX( ) de la classe ResultSet où XXX est
M.AFILAL 229 M.AFILAL 230
un type java,
Les getXXX( ) permettent de convertir les types sql en type Java
public class TestJDBC { Lors de l'envoi d'une requête pour exécution par le SGBD, 4 étapes doivent être faites
– public static void main(String[] args) throws SQLException { – analyse de la requête (recherche d’une stratégie d’exécution adéquate, type requête ),
try { – compilation de la requête,
– Class.forName("com.mysql.cj.jdbc.Driver"); – optimisation de la requête,
– Connection connection = – exécution de la requête.
DriverManager.getConnection("jdbc:mysql://localhost:3306/afilaldb", "root",
"mouni"); Ceci est le cas, même si cette requête est la même que la précédente !!
– Personne p1 = new Personne(1,"Alaoui", "Ahmed", 1983); – Or les 3 premières étapes ont déjà été effectuées dans ce cas, d’où perte de performances.
– p1.writeObjectInBD(connection);
– Personne p2 = new Personne(2,"Acharki", "Rachida", 1960); Les bases de données définissent la notion de requête préparée,
– p2.writeObjectInBD(connection); – requête où les 3 premières étapes ne sont effectuées qu'une seule fois.
– Personne p3 = new Personne(1, connection); // construc p3 via infos p1
– System.out.println(p3); JDBC propose l'interface PreparedStatement pour modéliser cette notion de requête préparée
– connection.close(); – Cette interface dérive de l'interface Statement.
} catch (ClassNotFoundException e) {
– System.err.println("Le driver n’est pas accessible"); D’autre part, avec un Statement, on ne peut pas construire des requêtes où un des arguments
– e.printStackTrace(System.err); est une variable (i.e. requêtes paramétrées).
} Pour remédier à cela, il faut pour cela utiliser un PreparedStatement.
– } M.AFILAL 235 M.AFILAL 236
}
Requête SQL avec PreparedStatement Requête SQL avec PreparedStatement: requêtes paramétrées
Requête SQL avec PreparedStatement: requêtes paramétrées Requête SQL avec PreparedStatement: requêtes paramétrées
Avec un PreparedStatement:
– On est plus rapide qu’un statement lors d’envoi de requêtes . Exemple avec une boucle (mise à jour de la colonne Vents pour tous les cafés de la table
– On peut utiliser des requêtes paramétrées. CAFE : c’est une requête qui se répète dans la boucle):
– On envoi une requête sans paramètre à la base de données pour compilation
Et puis spécification, le moment voulu, de la valeur des paramètres afin d’éxécuter la – PreparedStatement updateVentes;
requête.
– String updateString = "update CAFE SET Ventes = ? WHERE Nom_Cafe LIKE ?";
On utilise un PreparedStatement dans le cas de requêtes paramétrées et on les écrits sous la forme
suivante:
– updateVentes = conn.prepareStatement(updateString);
– SELECT nom FROM Personnes WHERE age > ? AND adresse = ?
– int [ ] VentesDeLaSemaine = {175 , 150, 60, 155};
Puis, si on veut exécuter la requête, on appel avant cela des méthodes qui permettent de donner des – String [ ] cafes = {"Colombian","FrenchRoast","Espresso","ColombianDecaf"};
valeurs à la place des points d'interrogation, données par: – int len = cafes.length;
– setType(numéroDeLArgument, valeur);
Pour positionner chacun des arguments et leur donner une valeur – for(int i = 0 ; i < len ; i ++){
– Les numéros commencent à 1 dans l'ordre d'apparition dans la requête. updateVentes.setInt(1, VentesDeLaSemaine[i]);
updateVentes.setString(2, cafes[i]);
On a donc un code comme:
updateVentes.executeUpdate();// exécution à chaque boucle
– PreparedStatement pSmt = conX.prepareStatement("SELECT nom FROM Personnes WHERE
age > ? AND adresse = ?" );
– }
– pSmt .setInt(1, 22); // pour le premier paramètre
– pSmt .setString(2, "Turin"); // pour le deuxième paramètre
M.AFILAL 239 M.AFILAL 240
Un objet PreparedStatement peut être aussi utilisé dans une instruction SQL sans paramètre, Un batch (JDBC 2.0) permet de réaliser des mises à jour de masse (insert, update, delete, ..) en
– mais peut être aussi utiliser pour des instructions SQL avec paramètre. regroupant plusieurs traitements (requêtes) pour les envoyer en une seule fois au SGBD.
– Ceci permet d'améliorer les performances surtout si le nombre de traitements (requêtes)
L'avantage de ceci est qu’on peut utiliser une instruction SQL requérant des paramètres: est important.
– On peut alors utiliser la même instruction en fournissant différentes valeurs à chaque fois
qu’on l'exécute. Attention: Cette fonctionnalité n'est pas obligatoirement supportée par le pilote.
– La méthode supportsBatchUpdates( ) de la classe DatabaseMetaData permet de savoir si
IL faut donner des valeurs « à la place des points d'interrogation » Avant qu’on puisse exécuter elle est utilisable avec le pilote.
un objet PreparedStatement
Plusieurs méthodes ont été ajoutées à l'interface Statement pour pouvoir utiliser les mises à
– Pour faire ça, il faudra utiliser l'une des méthodes setXXX définies dans la classe jour de masse :
PreparedStatement.
Si la valeur qu’on veut substituer au point d'interrogation est un int Java, on doit Méthode Rôle
appeler la méthode setInt. permet d'ajouter une chaîne
void addBatch(String)
contenant une requête SQL
Si la valeur est un String Java, on doit appeler la méthode setString, et ainsi de suite.
En général, il y a un setXXX pour chaque type Java. permet d'exécuter toutes les
requêtes. Elle renvoie un tableau
int[] executeBatch() d'entiers qui contient pour chaque
requête, le nombre de mises à jour
Voir exemple main_3 effectuées.
M.AFILAL 241 M.AFILAL 242
supprime toutes les requêtes
void clearBatch()
stockées
Requête SQL: Les mises à jour de masse (Batch Updates) Requête SQL: Les mises à jour de masse (Batch Updates)
Remarque
L'exécution de commandes SQL en batch n'est possible que pour des requêtes de modification
de la base « donc pas de select », celles que l'on exécute avec la méthode – Lors de l'utilisation de batchUpdate, il est préférable de positionner l'attribut autocommit
executeUpdate(String). à false afin de faciliter
la gestion des transactions,
Toute requête SQL qui peut être exécutée de la sorte, peut également être passée en paramètre le traitement d'une erreur dans l'exécution d'un ou plusieurs traitements.
de la méthode addBatch(String).
– Une exception particulière peut être levée en plus de l'exception SQLException lors de
L'appel de cette méthode ne fait que stocker la requête SQL, sans l'exécuter. C'est l'appel à la l'exécution d'une mise à jour de masse.
méthode executeBatch( ) qui déclenche l'exécution. L'exception SQLException est levée si une requête SQL d'interrogation doit être
exécutée (requête de type SELECT).
L'exception BatchUpdateException est levée si une des requêtes de mise à jour
échoue.
– con.setAutoCommit(true);
Méthode d’utilisation
– connection.setAutoCommit(false);
– try {
// instructions SQL de la transaction
connection.commit(); // validation de la transaction
– }
– catch (SQLException e) {
connection.rollback(); // annulation de la transaction
– }
– connection.setAutoCommit(true);
Requête SQL avec CallableStatement: Exécuter une procédure Requête SQL avec CallableStatement: Exemple
JDBC permet d'appeler une procédure stockée sur la base de données depuis une application Exemple avec le sens de paramètre est IN
écrite en Java. Connection connection = DriverManager.getConnection(
– CallableStatement cs = conn.prepareCall("{call SHOW_FOURNISSEURS}"); "jdbc:mysql://localhost:3306/afilaldb", "root", "mounir");
ResultSet rs = cs.executeQuery(); Statement statement = connection.createStatement( );
– CallableStatement callableStatement = connection.prepareCall("{call statement.executeUpdate("DROP PROCEDURE IF EXISTS rechercherParPrenom");
calculateStatistics(?, ?)}", ResultSet.TYPE_FORWARD_ONLY, statement.executeUpdate( //***Création de la procédure***//
ResultSet.CONCUR_READ_ONLY ); – "CREATE PROCEDURE rechercherParPrenom(IN lePrenom VARCHAR(50))\n"
– + "BEGIN\n"
Remarque: – + " SELECT * FROM Personnes WHERE prenom = lePrenom;\n"
– Quand le driver rencontre "{call SHOW_FOURNISSEURS}", – + "END\n");
il traduira cette syntaxe en SQL natif utilisé par la base de données pour appeler la String sql = "{call rechercherParPrenom(?)}";
procédure stockée nommée SHOW_FOURNISSEURS CallableStatement calls = connection.prepareCall(sql); //Appel de la procédure
– La méthode pour exécuter cs est executeQuery calls.setString(1, "Nada"); //passage de la chaîne "Nada" comme valeur du premier paramètre
car cs appel une procédure stockée qui contient une requête et produit un resultset. if (calls.execute()) { // teste s’il y a des résultats ou pas
– Si la procédure avait contenue une mise à jour ou une des instructions DDL, – ResultSet resultat = calls.getResultSet( ); //Récupération du ResultSet
la méthode executeUpdate aurait été utilisée. – int nbColones = resultat.getMetaData().getColumnCount( );
– Parfois, une procédure stockée contient plus d'une instruction SQL, qui pourrait produire – while (resultat.next( )) {
plus d'un résultset, plus d'une mise à jour, ou une combinaison de resultSet et de mise à
jour. for (int i = 0; i < nbColones; i++) { System.out.print(resultat.getObject(i +1) +", "); }
Dans ce cas, lorsqu'il y a de multiples résultats, la méthode execute devra être 259
} 260
M.AFILAL M.AFILAL
utilisée pour exécuter CallableStatement. resultat.close( ); calls.close( ); connection.close( );
Requête SQL avec CallableStatement: Exemple Requête SQL avec CallableStatement: Exemple
Exemple avec le sens de paramètre est OUT Exemple avec le sens de paramètre est INOUT
Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/afilaldb", Statement statement = connection.createStatement();
"root", "mounir"); statement.executeUpdate("DROP PROCEDURE IF EXISTS hello");
Statement statement = connection.createStatement();
statement.executeUpdate("DROP PROCEDURE IF EXISTS nombrePersonneEnregistres");
String procedureReq = "CREATE PROCEDURE hello(INOUT param VARCHAR(100))\n"
statement.executeUpdate(
– + "BEGIN\n"
– "CREATE PROCEDURE nombrePersonneEnregistres(OUT nbPersonne INTEGER)\n"
– + " SELECT CONCAT('Hello ', param, ' est ce que tu vas bien? ') INTO param\n;"
– + "BEGIN\n"
– + " SELECT COUNT(*) INTO nbPersonne FROM Personnes;\n" – + "END\n";
– + "END\n");
String sql = "{call nombrePersonneEnregistres(?)}"; statement.executeUpdate(procedureReq);
CallableStatement call = connection.prepareCall(sql); String sql = "{call hello(?)}";
– //enregistrement du paramètre de sortie en fonction de son type et de son nom CallableStatement call = connection.prepareCall(sql);
call.registerOutParameter("nbPersonne", java.sql.Types.INTEGER);
– /*//enregistrement du paramètre de sortie en fonction de son index et de son type call.setString(1, "AFILAL"); //passage de la valeur du paramètre
– statement.registerOutParameter(1, java.sql.Types.INTEGER);*/ – //enregistrement du paramètre en tant que paramètre OUT
call.execute( ); call.registerOutParameter(1, Types.VARCHAR);
int resultat = call.getInt(1); //récupération du résultat en fonction de l'index
– /*int resultat = statement.getInt("nb"); //récupération du résultat en fonction du nom du call.execute(); //exécution et récupération du résultat
paramètre*/
261 System.out.println(call.getString(1)); 262
System.out.println("Nombre d'abonnés = " + M.AFILAL
resultat); M.AFILAL
Les possibilités de l'objet ResultSet dans la version 1.0 de JDBC sont très limitées : Il est aussi possible de préciser les modes pour ResultSet, s’il peut être mis à jour ou non :
– parcours séquentiel de chaque occurrence de la table retournée. – ResultSet.CONCUR_READ_ONLY : lecture seule
– resultSet.CONCUR_UPDATABLE : mise à jour possible (updeter, insérer, détruire
certaines de ses lignes. )
La version 2.0 apporte de nombreuses améliorations à cet objet :
– le parcours des occurrences dans les deux sens,
C'est à la création d'un objet de type Statement qu'il faut préciser le type et le mode à utiliser.
– la possibilité de faire des mises à jour sur une occurrence.
Statement st = conn.createStatement(type, mode);
– Par défaut (se sont les caractéristiques de la version 1.0) on a:
Concernant le parcours, il est possible de préciser trois types de fonctionnement :
le type est: TYPE_FORWARD_ONLY
– forward-only : parcours séquentiel de chaque occurrence
(ResultSet.TYPE_FORWARD_ONLY) Le mode est: CONCUR_READ_ONLY
Remarque
– scroll-insensitive : Vision figée du résultat de la requête au moment de son évaluation – Les modifications d’un ResultSet updatable (de type CONCUR_UPDATABLE) sont
«les occurrences ne reflètent pas les mises à jour qui peuvent intervenir durant le faites sur le ResultSet pas dans la base.
parcours» (ResultSet.TYPE_SCROLL_INSENSITIVE) – Elles seront faites dans la base à l'aide de la méthode updateRow()
– Exemple :
– scroll-sensitive : les occurrences reflètent les mises à jour (modifiées/détruites) qui rs.first();
peuvent intervenir durant le parcours (ResultSet.TYPE_SCROLL_SENSITIVE) rs.updateString(1, "100020");
rs.updateFloat("salary", 10000.0f);
M.AFILAL 265 266
rs.updateRow(); // Pour appliquerM.AFILAL
les modifications dans la base de données
Traitement avancé des ResultSet: parcourt dans un resultSet Traitement avancé des ResultSet: parcourt dans un resultSet
A la création du ResultSet, le curseur est positionné avant la première occurrence à traiter.
Durant le parcours d'un ResultSet, il est possible d'effectuer des mises à jour sur la ligne
Pour se déplacer dans l'ensemble des occurrences, courante du curseur.
– il y a toujours la méthode next() pour se déplacer sur le suivant Pour cela, il faut déclarer l'objet ResultSet comme acceptant les mises à jour.
– mais aussi plusieurs autres méthodes pour permettre le parcours des occurrences en – Avec les versions précédentes de JDBC, il fallait utiliser la méthode executeUpdate()
fonctions du mode utilisé dont les principales sont : avec une requête SQL.
Méthode Rôle Maintenant pour réaliser ces mises à jour, JDBC 2.0 propose de les réaliser via des appels de
boolean isBeforeFirst()
Renvoyer un booléen qui indique si la position courante du curseur se trouve avant la méthodes plutôt que d'utiliser des requêtes SQL.
première ligne
Renvoyer un booléen qui indique si la position courante du curseur se trouve après la
boolean isAfterLast() Méthode Rôle
dernière ligne
boolean isFirst() Renvoyer un booléen qui indique si le curseur est positionné sur la première ligne permet de mettre à jour la colonne dont le nom est fourni en paramètre. Le
updateXXX(String, XXX)
type Java de cette colonne est XXX
boolean isLast() Renvoyer un booléen qui indique si le curseur est positionné sur la dernière ligne
boolean first() Déplacer le curseur sur la première ligne permet de mettre à jour la colonne dont l'index est fourni en paramètre. Le
updateXXX(int, XXX)
boolean last() Déplacer le curseur sur la dernière ligne type Java de cette colonne est XXX
Déplacer le curseur sur la ligne dont le numéro est fourni en paramètre à partir du permet d'actualiser les modifications réalisées avec des appels à
updateRow()
boolean absolute(int) début si il est positif et à partir de la fin si il est négatif. 1 déplace sur la première ligne, updateXXX()
-1 sur la dernière, -2 sur l'avant dernière ...
boolean rowsUpdated() indique si la ligne courante a été modifiée
Déplacer le curseur du nombre de lignes fourni en paramètre par rapport à la position
courante du curseur. Le paramètre doit être négatif pour se déplacer vers le début et deleteRow() supprime la ligne courante
boolean relative(int)
positif pour se déplacer vers la fin. Avant l'appel de cette méthode, il faut
obligatoirement que le curseur soit positionné sur une ligne. rowDeleted() indique si la ligne courante est supprimée
Déplacer le curseur sur la ligne précédente. Le booléen indique si la première
boolean previous()
occurrence est dépassée. moveToInsertRow() permet de créer une nouvelle ligne dans l'ensemble de résultat
void afterLast() Déplacer le curseur après la dernière ligne
void beforeFirst() M.AFILAL
Déplacer le curseur avant la première ligne 267 insertRow() permet de valider la M.AFILAL
création de la ligne 268
Remarque
Remarque
– Pour insérer une nouvelle ligne dans le jeu de résultat, il faut tout d'abord appeler la
– Pour réaliser une mise à jour dans la ligne courante désignée par le curseur, il faut utiliser méthode moveToInsertRow().
une des méthodes updateXXX() sur chacun des champs à modifier.
– Cette méthode déplace le curseur vers un buffer dédié à la création d'une nouvelle ligne.
– Une fois toutes les modifications faites dans une ligne, il faut appeler la méthode
updateRow() pour reporter ces modifications dans la base de données Il faut alimenter chacun des champs nécessaires dans cette nouvelle ligne.
car les méthodes updateXXX() ne font des mises à jour que dans le jeu de résultats. Pour valider la création de cette nouvelle ligne, il faut appeler la méthode
insertRow().
– Les mises à jour (vers la base de données) sont perdues si un changement de ligne
intervient avant l'appel à la méthode updateRow(). – Pour supprimer la ligne courante, il faut appeler la méthode deleteRow().
Cette méthode agit sur le jeu de résultats et sur la base de données.
– La méthode cancelRowUpdates( ) permet d'annuler toutes les modifications faites dans la
ligne.
L'appel à cette méthode doit être effectué avant l'appel à la méthode updateRow().
Traitement avancé des ResultSet: Exemples Traitement avancé des ResultSet: Exemples
Exemple (mise à jour d’enregistrement depuis java)
– Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, Exemple (Insertion et suppression depuis java)
ResultSet.CONCUR_UPDATABLE); – Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
– stmt.setFetchSize(25); ResultSEt.CONCUR_UPDATEABLE);
– ResultSet resultat = stmt.executeQuery(" SELECT * FROM Employe WHERE NumEmp – ResultSet resultat = stmt.executeQuery(" SELECT * From Employe" );
< 6 " ); – Resultat.moveToInsertRow(); //autres méthodes : first, relative, ….
– Resultat.last( ); – Resultat.updateString("Name", " Joseph ");
– Resultat.updateFloat("Salary", 20) – Resultat.updateInt(1, 100);
– Resultat.cancelRowUpdates() – Resultat.updateFloat("Salary", 1200);
– Resultat.updateFloat("Salary", 50) – Resultat.insertRow(); // ajout d’une nouvelle ligne dans le ResultatSet et dans la base
– Resultat.updateRow (); – Resultat.last();
– Resultat.deleteRow();// suppression de la dernière ligne dans ResultatSet et dans la base
Remarque
– Pour les requêtes qui retournent plusieurs milliers de lignes, ce comportement n'est pas du
tout souhaité.
Car le chargement de plusieurs Mo d'un coup en mémoire peut entrainer un
ralentissement de toute l'application.
– Dans ces cas, il est préférable de ne charger les lignes en mémoires qu'au fur et à mesure
qu'on en a besoin dans notre code.
Ceci est possible via l’utilisationM.AFILAL
de la méthode setFetchSize «définie le nombre de271 M.AFILAL 272
lignes à charger en mémoire »
Autres remarques Conseilles pour une bonne utilisation du JDBC
Remarques Remarques
– L'obtention des valeurs de clé générées automatiquement lors d'une insertion, on fait par – Lorsque vous travaillez avec des instructions et des résultats, veillez toujours à bien
exemple (avec idPersonne est la clé primaire auto incrémente): fermer les objets Connection, Statement et ResultSet lorsque vous avez terminé ceci via
leur méthode close();
stmt.executeUpdate( "INSERT INTO personne (nom, prenom, taille) " + "values – Ne retourner que les données utiles lors de l'utilisation de requêtes SQL
('nom1', 'prenom1', 174)", Statement.RETURN_GENERATED_KEYS); – Toujours assurer un traitement des warnings et des exceptions
– La qualité du pilote JDBC est importante notamment en termes de rapidité, type de pilote,
version de JDBC supportée, ...
– Le type du pilote influe grandement sur les performances :
Le type 1 (pont JDBC/ODBC) : les pilotes de ce type sont à éviter car les différentes
couches mises en œuvre (JDBC, pilote JDBC, ODBC, pilote ODBC, base de
données) dégradent les performances
Le type 2 (utilise une API native de la base de données ) : les pilotes de ce type ont
généralement des performances moyennes
Le type 3 (JDBC, pilote JDBC, middleware, DB) : les pilotes de type 3
communiquent avec un middleware généralement sur le serveur. Ils sont le plus
souvent plus performants que ceux de type 1 et 2
Le type 4 (JDBC, pilote JDBC, DB) les pilotes de type 4 offre en général les
meilleures performances car ils sont écrits en Java et communiquent directement
avec la base de données
M.AFILAL 273 M.AFILAL 274
– Il est donc préférable d'utiliser des pilotes de type 4 ou 3.
L’objectif est de dessiner dans un composant graphique en utilisant un outil de dessin: le L’API Java 2D étend, les mécanismes de dessin Java.AWT précédents, pour dessiner des
graphiques 2D, afin de:
contexte graphique.
– manipuler du texte et des polices, charger et utiliser des images,
– Le contexte graphique est une instance de java.awt.Graphics ou java.awt.Graphics.2D.
– définir et gérer les couleurs et les espaces colorimétriques.
Ce contexte graphique permet de dessiner des formes, du textes et des images dans la
zone de dessin d’un composant.
Java 2D est une API qui permet de dessiner des graphiques en deux dimensions.
– C’est une technologie puissante qu’on peut utiliser pour créer
Donc, dans cette partie, on va voir comment des interfaces utilisateur riches,
– réaliser des tracés de formes, du textes et des images en deux dimensions des jeux, des animations,
des applications multimédias
Les classes qu’on va utiliser , entre autres, pour dessiner appartiennent aux paquetages : ou divers effets spéciaux.
– java.awt, java.awt.color, java.awt.font,
– java.awt.geom, java.awt.image et java.awt.print. L’outil de dessin sur un composant ou Le contexte graphique d’un composant fournit des
méthodes afin de réaliser trois sortes d'objets graphiques :
L’ensemble de ces classes constituent l'essentiel de l'API 2D, destinée au tracé: Les formes,
– de formes, de texte et d'images. Les textes,
Les images.
275 276
Graphisme 2D et les images Graphisme 2D et les images
Remarque
– Pour dessiner dans un composant graphique, on passe nécessairement par une instance de Cas de rafraichissement pour un affichage
Graphics – Il existe une méthode qui est automatiquement sollicitée pour afficher ou réafficher un
– Le JDK 1.2 a introduit la bibliothèque Java 2D , qui contient composant.
la classe Graphics2D, qui dérive de Graphics, afin de dessiner par exemple
– des lignes avec des épaisseur ou pas, paintComponent( ) « pour les composants javax.swing ».
– des rectangles, des ellipses,
– de faire pivoter ou translater des formes, etc... paint( ) « pour les composants java.awt »
– Chaque composant peut accéder implicitement ou explicitement à son contexte graphique. On doit passer par cette méthode pour être sûr que notre tracé spécifique ou
personnalisé soit réaffiché au moment du rafraîchissement.
Implicitement, comme paramètre de la méthode, dans,
– Ceci impose, de redéfinir cette méthode.
– la méthode paint( Graphics g ) « pour des composant AWT »
Avec utilisation d’un héritage par rapport à un composant graphique
– et paintComponent (Graphics Graphics2D g) «pour des composants swing» existant
Explicitement dans «appel à super.paintComponent(Graphics g) ».
– un composant ou dans une image, par getGraphics( ),
Remarque Exemple de fenêtre avec paintComponent personnalisée et qui est utilisée lors d’un
rafraichissement « Voir code en bas »
– Une fenêtre doit se réafficher (donc, rafraichissement de la fenêtre), dans le cas de
redimensionnant ou de translation.
d’ajout de composant ou de suppression de composant.
quand elle se situait en dessous d'une autre fenêtre et qu’elle obtient le focus,
etc…
– Lors du rafraichissement,
279 280
Graphisme 2D et les images Graphisme 2D et les images
public class Fenêtre extends JFrame {
– public Fenêtre( ) {
setSize(300, 250); Rôle de la fonction paintComponent
setTitle("Test dessins");
getContentPane().setBackground(Color.ORANGE); – Pour dessiner des formes avec la bibliothèque Java 2D, on doit utiliser un objet de la
classe Graphics2D (Graphics2D une classe fille de la classe Graphics).
getContentPane().add(new Zone( ) , BorderLayout.CENTER);
– }
– La méthode paintComponent() reçoit automatiquement en argument un objet de la classe
}
Graphics2D.
class Zone extends JPanel {
– protected void paintComponent(Graphics g1) {
Malgré que le paramètre de cette méthode est lui de type Graphics.
super.paintComponent(g1);
Graphics2D g = (Graphics2D) g1; //g.setColor(Color.BLUE);
On doit effectuer un transtypage dans le cas où on désire utiliser la technologie 2D.
g.drawArc(-40, 10, 100, 100, 0, 90);
– public void paintComponent(Graphics g) {
g.drawLine(10, 10, 10, 60);
Graphics2D zone = (Graphics2D) g;
g.drawLine(10, 60, 60, 60);
...
g.drawOval(10, 80, 120, 120);
– }
g.drawPolygon(new int[ ] {110, 170, 170}, new int[ ] {60, 60, 10}, 3);
g.drawPolyline(new int[ ] {210, 270, 270}, new int[ ] {60, 60, 10}, 3);
g.drawRect(10, 80, 120, 120);
g.drawRoundRect(150, 80, 120, 120, 10, 10);
– } 281 282
}
Remarque « rôle de la fonction repaint() dans le rafraichissement » Le rendu est le résultat final qui est retourné à la fin de la manipulation des formes, des textes
« cette méthode force le rafraichissement dans une situation donnée » et des images après utilisations de certaines règles et technologies sur leur manipulation.
– repaint ( ) en Swing est la méthode par excellence pour rafraîchir un affichage ! Le rendu (ce qui est présenté et comment: ce qui est livré ou renvoyé avec les règles
utilisées)
– est un processus qui consiste
– repaint( ) poste un appel à update(). Plusieurs appels peuvent être groupés.
à prendre un ensemble de formes, textes et images
et à définir une façon de les représenter, de les manipuler et d’agir sur eux:
– update( ) appelle paint( ).
– Les colorer sur un écran
– De les faire translater ou de leur faire des rotations (Transformations,
– paint( ) appelle successivement Clipping, Composition, …)
paintComponent( ) pour le dessin ( le paint( ) en AWT) – ou autre.
paintBorder()
paintChildren(). Le rendu Spécifie ou donne comment un objet sera dessiné dans la surface d’affichage.
– paintComponent( ) par défaut appelle ComponentUI.update() qui efface et redessine le Graphics2D gère quatre opérations pour un rendu :
fond si le composant est opaque (JPanel l’est par défaut). – Dessiner un contour d'une forme, avec la méthode draw( ).
– Remplir une forme, avec la méthode fill( ).
– Pour dessiner dans un composant, on redéfinit paintComponent( ) et – Dessiner du texte, avec la méthode drawString( ).
il est utile d’appeler super.paintComponent() dans paintComponent( ) . 283
– Dessiner une image, avec l'une des nombreuses formes de la méthode drawImage( ).
284
Graphisme 2D et les images: le rendu Graphisme 2D et les images: Attributs du contexte graphique
Par rapport aux méthodes proposées par la classe java.awt.Graphics, l'API Java 2D supporte
plusieurs options supplémentaires : donc avec l'API Java 2D
Le contexte graphique instancié par un objet Graphics2D possède les attributs ci-dessous
«couleur, trait, police, transformation,….», qui sont gérer par diverses méthodes d'accès :
– On peut facilement produire une grande quantité de formes différentes(exp: concaténation
des formes). – paint (= couleur):
Le paint en cours (un objet de type java.awt.Paint) définit les couleurs de
– L'outil de dessin peut être contrôlé (exp: changement de taille des lignes). remplissage (unies ou dégradées) d'une forme.
– Cela concerne également les contours et le texte.
– Les formes peuvent être remplies aves des couleurs uniformes, des dégradés ou des – il est possible de passer des Color à setPaint( ) lorsque nous désirons utiliser
des couleurs unies.
motifs répétés.
– stroke (= trait):
– Des transformations permettent de déplacer, d'agrandir, de rétrécir, de faire pivoter ou de
Graphics2D utilise le stroke pour déterminer comment dessiner le contour des
déformer des formes. formes qui sont passées à la méthode draw( ).
Il est possible de fixer le trait courant en utilisant setStroke( ).
– Les formes peuvent être coupées automatiquement pour ne pas déborder d'une zone L'API 2D fournie une classe très pratique, java.awt.BasicStrocke, qui permet
donnée. d'implémenter différentes épaisseurs, extrémités, jointures et pointillés de ligne.
– On peut sélectionner des règles de composition pour décrire la manière dont les pixels – font (= police):
d'une nouvelle forme doivent être combinées avec les pixels existants. Le texte est rendu « présenté » par une forme représentant des caractères à dessiner.
La police courante est définie à l'aide de setFont( ).
– Des conseils d'affichage peuvent être fournis pour choisir un compromis entre la vitesse285 286
et la qualité de l'affichage.
Graphisme 2D et les images: Attributs du contexte graphique Graphisme 2D et les images: Attributs du contexte graphique
289 290
Graphisme 2D et les images: Méthodes de la classe Graphics Graphisme 2D et les images: Méthodes de la classe Graphics
Méthode Description
drawArc(int x, int y, int largeur, int hauteur, int angledébut, int
Dessine un arc de cercle (angle en degré) Remarque
angleDeplacement)
– Pour chacune des méthodes fill ( ) du tableau, il existe une méthode draw()
drawLine(int xdébut, int ydébut, int xfin, int yfin) Dessine une ligne
correspondante créant la forme selon un dessin non plein.
drawOval(int x, int y, int largeur, int hauteur) Dessine un ovale
Dessine un polygone fermé en joignant les – La méthode de dessin d’un polygone est définie par deux tableaux de coordonnées des
drawPolygon(int[ ] lesX, int[ ] lesY, int nombrePoint)
extrémités sommets, d'une part le tableau des X, et d'autre part le tableau des Y suivi ensuite du
Dessine une ligne en reliant une série de nombre de point.
drawPolyline(int[] lesX, int[] lesY, int nombrePoint)
points, sans la fermer Des méthodes de la classe Graphics lisent ces tableaux et dessinent le contour du
drawRect(int x, int y, int largeur, int hauteur) Dessine un rectangle polygone ou remplissent celui-ci.
drawRoundRect(int x, int y, int largeur, int hauteur, int
Dessine un rectangle à coins arrondis
largeurArc, int hauteurArc)
– La méthode fillArc() requiert six arguments entiers.
Les quatre premiers définissent le rectangle englobant un ovale - comme la méthode
fillArc(int x, int y, int largeur, int hauteur, int angledébut, int fillOval( ).
Dessine un arc de cercle plein
angleDeplacement)
Les deux derniers définissent la portion de l'ovale à dessiner, sous forme de position
fillOval(int x, int y, int largeur, int hauteur) Dessine un ovale plein angulaire de départ et de déplacement (tous deux en degrés).
fillPolygon(int[] lesX, int[] lesY, int nombrePoint) Dessine un polygone plein La position zéro degré se trouve à trois heures, l'angle croît (angle positif) dans le
fillRect(int x, int y, int largeur, int hauteur) Dessine un rectangle plein sens inverse des aiguilles d'une montre.
fillRoundRect(int x, int y, int largeur, int hauteur, int largeurArc,
Dessine un rectangle plein à coins arrondis
int hauteurArc) 291 292
Graphisme 2D et les images: Exemple * Graphisme 2D et les images
public class Fenêtre extends JFrame {
– public Fenêtre() {
setSize(300, 250); Les méthodes données dans le dernier exemple font parties de la classe Graphics.
setTitle("Test dessins");
getContentPane().setBackground(Color.ORANGE);
L'API 2D se sert d'une approche, entièrement différente, orientée objet.
getContentPane().add(new Zone() );
– Au lieu de méthodes, il existe les classes correspondantes suivantes :
– }
Line2D; Rectangle2D; RoundRectangle2D; Ellipse2D;
}
class Zone extends JPanel { Arcs2D; QuadCurve2D; CubicCurve2D; GeneralPath
– protected void paintComponent(Graphics g1) { – Ces classes implémentent toutes l'interface Shape.
super.paintComponent(g1);
Graphics2D g = (Graphics2D) g1; Les classes Line2D, Rectangle2D, RoundRectangle2D, Ellipse2D et Arc2D
g.drawArc(-40, 10, 100, 100, 0, 90); – correspondent respectivement aux méthodes drawLine(), drawRect(), drawRoundRect(),
g.drawLine(10, 10, 10, 60); drawOval() et drawArc() de la classe Graphics.
g.drawLine(10, 60, 60, 60);
g.drawOval(10, 80, 120, 120); L'API 2D rajoute deux classes supplémentaires :
g.drawPolygon(new int[ ] {110, 170, 170}, new int[ ] {60, 60, 10}, 3); – les courbes quadratiques et cubiques.
g.drawPolyline(new int[ ] {210, 270, 270}, new int[ ] {60, 60, 10}, 3);
g.drawRect(10, 80, 120, 120);
g.drawRoundRect(150, 80, 120, 120, 10, 10);
– }
293 294
}
Autre exemple: voir fenetre_2
Graphisme 2D et les images Diagramme UML des classes implémentant l'interface Shape
Remarque:
– Il n'existe aucune classe Polygone2D.
Remarque
– il existe une classe abstract Point2D (utilisez ses clases dérivées: Point, Point2D.Double,
Point2D.Float) qui décrit un point avec des coordonnées x et y.
Les points sont utilisés pour définir des formes « bien qu'ils n'en soient pas eux-
mêmes ».
295 296
Graphisme 2D et les images: dessin d’objet 2D Graphisme 2D et les images: dessin d’objet 2D
Remarque
Pour dessiner une forme – On peut utiliser la méthode draw3DRect() de la classe Graphics pour dessiner un
rectangle.
– il faut commencer par créer un objet d'une classe qui implémente l'interface Shape, – Avec java 2D, on peut améliorer nos dessins avec les nombreux outils que fournit la
bibliothèque (transformation, dégradés, transparence, composition entre les formes et les
images, etc…
– ensuite dans la classe Graphics2D, faire appel uniquement à l'une des deux méthodes
– Les classes Xxx2D.Float et Xxx2D.Double constituent des sous-classes des classes
spécifiques,
abstraites Xxx2D.
Graphisme 2D et les images: dessin d’objet 2D Graphisme 2D et les images: dessin d’objet 2D
Construction des objets Rectangle2D et Ellipse2D. Lors de la construction d'une ellipse, on connait généralement
– le centre, la largeur et la hauteur, mais pas les points des angles du rectangle englobant.
On doit spécifier :
Il existe une méthode setFrameFromeCenter( ) qui utilise le point central mais elle
– Les coordonnées x et y du coin supérieur gauche ; requiert toujours l'un des quatre points d'angle.
– La largeur et la hauteur. – Pour tracer une ellipse en utilisant le centre comme critère, on fait:
Rectangle2D rectangle = new Rectangle2D.Double(x, y, largeur, hauteur);
Ellipse2D ellipse = new Ellipse2D.Double();
Ellipse2D ellipse = new Ellipse2D.Double(x, y, largeur, hauteur); ellipse.setFrameFromCenter(Xcentre, Ycentre, Xangle, Yangle);
– Pour les ellipses, ces valeurs font référence au rectangle englobant ellipse.setFrameFromCenter(PointCentre, PointAngle);
301 302
Graphisme 2D et les images: dessin d’objet 2D Graphisme 2D et les images: dessin d’objet 2D
Arc de cercle Remarque
– La classe qui implémente l'arc de cercle est la classe Arc2D. – Attention: les angles s'expriment en degré.
– Pour construire un arc, il faut fournir un rectangle englobant cet arc, suivi de l'angle de Exemple
départ et de l'angle d'ouverture, ainsi que le type de fermeture, qui peut être:
– class Zone extends JPanel{
Arc2D.OPEN, Arc2D.PIE ou Arc2D.CHORD.
protected void paintComponent(Graphics g) {
– super.paintComponent(g);
– Arc2D arc = new Arc2D.Double(x, y, largeur, hauteur, angleDépart, angleArc,
– Graphics2D surface = (Graphics2D) g;
typeFermetureArc) ;
– Arc2D arc = new Arc2D.Double(10, 10, 200, 200, 60, 180, Arc2D.PIE);
– surface.draw(arc);
}
– }
303 304
Graphisme 2D et les images: dessin courbes 2D Graphisme 2D et les images: dessin courbes 2D
Dans cette partie, on va voir comment tracer Tracé de courbes
– des lignes, La bibliothèque Java 2D fournit
– des courbes quadratiques, – des courbes quadratiques représentées par la classe QuadCurve2D et
– des courbes cubiques, – des courbes cubiques représentées par la classe CubicCurve2D (courbes de Bézier).
– ainsi qu'un assemblage de ces différents types de tracé.
Les courbes quadratiques et cubiques sont spécifiées par deux points de terminaison, et un ou
deux points de contrôle.
Tracé de segments de lignes
– C'est le nombre de point de contrôle qui détermine le type de courbe.
– Le tracé des segments de lignes s'obtient au moyen de la classe Ligne2D.
Ainsi, la forme des courbes peut être modifié en changeant les points de contrôle.
– Pour construire une ligne, on donne les points de départ et d'arrivé, sous la forme
d'objets Point2D ou de paires de nombres. – QuadCurve2D qq = new QuadCurve2D.Double(xdébut, ydébut, contrôleX, contrôleY,
xfin, yfin);
Point2D début = new Point2D.Double(xdébut, ydébut);
– CubicCurve2D cc = new CubicCurve2D.Double(xdébut, ydébut, contrôleDébutX,
Point2D fin = new Point2D.Double(xfin, yfin);
contrôleDébutY, contrôleFinX, contrôleFinY, xfin, yfin);
– Ligne2D ligne _1 = new Ligne2D.Double(début, fin);
– Ligne2D ligne_2 = new Ligne2D.Double(xdébut, ydébut, xfin, yfin);
305 306
Graphisme 2D et les images: dessin courbes 2D Graphisme 2D et les images: dessin courbes 2D
Zone (Area)
– On a vu comment générer des formes complexes en construisant des tracés généraux composés de
lignes et de courbes. Remarque
En utilisant un nombre suffisant de lignes et de courbes, on peut représenter quasiment – Pour construire une zone complexe, il faut commencer, en général, avec un objet de
n'importe quelle forme. zone par défaut (vierge).
Par exemple, les formes des caractères des polices visibles sur un écran ou sur un papier – Puis, on combine cette zone avec n'importe quelle autre forme.
imprimé sont toutes composées de lignes et de courbes cubiques: « D ».
Cependant, et de manière occasionnelle, il est plus simple de construire une courbe en utilisant des zones,
comme des zones formées par : des rectangles, des polygones ou des ellipses. – class Zone extends JComponent { //ok
protected void paintComponent(Graphics g) {
L'API Java 2D dispose d'un objet de zone représenté par la classe Area. – Graphics2D surface = (Graphics2D) g;
– Cette classe supporte quatre opérations de combinaisons de zones géométriques, qui mélangent les – GeneralPath dessin = new GeneralPath();
pixels de deux zones pour former une nouvelle zone:
– dessin.moveTo(150, 140);
add( ) : la zone résultat contient tous les points qui se trouvent dans la première zone ou dans la
seconde. – dessin.curveTo(10, 0, 290, 0, 150, 140);
substract( ) : la zone résultat contient tous les points de la première zone qui ne sont pas dans la – dessin.append(new Ellipse2D.Double(120, 140, 60, 60), false);
seconde zone. – Area zone = new Area();
intersect( ) : la zone résultat contient tous les points qui se trouvent dans la première zone et – zone.add(new Area(new Rectangle2D.Double(70, 20, 160, 190)));
dans la seconde.
exclusiveOr( ) : la zone résultat contient tous les points qui se trouvent dans la première zone ou
– zone.subtract(new Area(dessin));
dans la seconde, mais pas dans les deux. – surface.fill(zone);
}
– }
311
Graphisme 2D et les images: dessin courbes 2D Graphisme 2D et les images: outils de dessin
L'opération draw( ) de la classe Graphics2D dessine le contour d'une forme en utilisant l'outil de dessin
courant.
Exemple
– Par défaut, cet outil est une ligne pleine d'un seul pixel d'épaisseur.
– public void paintComponent(Graphics g) {
On peut sélectionner un autre outil de dessin de ligne en appelant la méthode setStroke( ). « setLigne »
Graphics2D g2 = (Graphics2D)g; – Il suffit de fournir à cette méthode en paramètre un objet d'une classe qui implémente l'interface
Ellipse2D ellipse = new Ellipse2D.Double(20, 20, 80, 80); Stroke.
Rectangle2D rectangle = new Rectangle2D.Double(60, 60, 100, 100); En fait, l'API Java 2D définit une seule classe adaptée, il s'agit de BasicStroke.
........... Epaisseur du trait
– On peut construire des outils de dessin de n'importe quel épaisseur :
Area areaOne = new Area(ellipse);
– Exemple
Area areaTwo = new Area(rectangle);
class Zone extends JComponent {
if (option.equals("add")) areaOne.add(areaTwo); – protected void paintComponent(Graphics g) {
else if (option.equals("intersection")) areaOne.intersect(areaTwo); Graphics2D surface = (Graphics2D) g;
else if (option.equals("subtract")) areaOne.subtract(areaTwo); GeneralPath dessin = new GeneralPath();
else if (option.equals("exclusive or")) areaOne.exclusiveOr(areaTwo); dessin.moveTo(180, 30);
g2.setPaint(Color.orange); dessin.lineTo(105, 105);
dessin.moveTo(30, 30);
g2.fill(areaOne); // remplissage via un area
dessin.lineTo(30, 180);
g2.setPaint(Color.black);
dessin.lineTo(180, 180);
g2.draw(areaOne); // draw conteur un area dessin.closePath();
…….. surface.setStroke(new BasicStroke(20));
– } surface.draw(dessin);
– }
}
Graphisme 2D et les images: outils de dessin Graphisme 2D et les images: outils de dessin
Intersection de deux traits
Extrémités du trait – Lorsque deux tracés épais se croisent, il existe trois possibilités pour le style de
– Lorsqu'un outil fait plus d'un pixel de large, son extrémité peut prendre différents l'intersection :
aspects : Une intersection en biais : les deux tracés sont reliés par une ligne droite
Une extrémité droite : perpendiculaire à la bissectrice de l'angle entre les deux tracés -
– l'outil s'arrête exactement au dernier point tracé - BasicStroke.CAP_BUTT. BasicStroke.JOIN_BEVEL.
Une extrémité arrondie : Une intersection arrondie : les deux tracés sont prolongés par une extrémité
– un demi-cercle est ajouté à la fin du tracé - BasicStroke.CAP_ROUND. arrondie - BasicStroke.JOIN_ROUND.
Une extrémité carré : Une intersection angulaire : les deux tracés sont prolongés par un angle -
BasicStroke.JOIN_MITER.
– un demi carré est ajouté à la fin du tracé - BasicStroke.CAP_SQUARE.
– Remarque
L'intersection angulaire n'est pas adaptée aux lignes qui se croisent selon un angle
aigu.
Si deux lignes se croisent selon un angle inférieur à la limite angulaire, une
intersection en biais est choisie automatiquement en remplacement.
Cela permet d'éviter les prolongements angulaires trop longs.
– Par défaut, cette limite angulaire est fixée à dix degrés.
Graphisme 2D et les images: outils de dessin Graphisme 2D et les images: outils de dessin
Exemple des extrémités et des intersections des traits
– Pour spécifier les extrémités et les intersections, on doit utiliser la méthode setStroke(). Motif de remplissage pour des lignes
– On passe en argument à cette méthode un objet de type BasicStroke, ceci en construisant – On peut choisir des lignes pointillées en définissant un motif de remplissage.
cet objet à l'aide de trois ou quatre arguments :
– Un motif de remplissage est composé d'un tableau float[ ] de nombres contenant la
surface.setStroke(new BasicStroke(épaisseur, extrémité, intersection, limite longueur des tirets blancs et noirs.
angulaire (en option)));
– En reprenant l’exemple précédant avec un tracé plutôt arrondi:
class Zone extends JComponent {
– Remarque
– protected void paintComponent(Graphics g) {
Graphics2D surface = (Graphics2D) g; Le motif de remplissage et la phase de remplissage peuvent être spécifiés lors de la
GeneralPath dessin = new GeneralPath( ); construction du BasicStroke.
dessin.moveTo(180, 30); Toutefois, cette partie s'intègre à la suite de la définition des extrémités et des
dessin.lineTo(105, 105); intersections de traits.
dessin.moveTo(30, 30); La phase de remplissage indique la position de démarrage de chaque ligne par
dessin.lineTo(30, 180); rapport au motif de remplissage.
dessin.lineTo(180, 180); – Normalement cette valeur vaut 0 (point de commencement de la ligne).
dessin.closePath();
surface.setStroke(new BasicStroke(20, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND));
surface.draw(dessin);
– }
}
Exemple (ok)
– class Zone extends JComponent { Lorsqu'une forme est remplie, son intérieur est recouvert d'une couleur de remplissage.
protected void paintComponent(Graphics g) {
– Graphics2D surface = (Graphics2D) g; La méthode setPaint( ) permet de choisir un style de remplissage parmi plusieurs objets
– GeneralPath dessin = new GeneralPath(); «Color, GradientPaint, TexturePaint , …» qui implémentent l'interface Paint.
– dessin.moveTo(180, 30); dessin.lineTo(105, 105);
– dessin.moveTo(30, 30); dessin.lineTo(30, 180); Dans l'API Java 2D, il existe trois classes adéquates suivant le type de remplissage voulu :
– dessin.lineTo(180, 180); – Couleurs unies : la classe Color implémente l'interface Paint pour remplir des formes
– dessin.closePath(); avec une couleur unie.
– float[ ] motif = {5, 10, 5, 10, 20, 10};
– Dégradés : la classe GradientPaint fait varier la couleur de remplissage en l'interpolant
– surface.setStroke( new BasicStroke(5, // épaisseur
entre deux valeurs spécifiées.
– BasicStroke.CAP_ROUND, // extrémité
– Textures : La classe TexturePaint remplit une zone en répétant une image.
– BasicStroke.JOIN_MITER, // intersection
– 15, // limite angulaire
– motif, // motif de remplissage Remarque
– 0 // phase de remplissage – Ces types de remplissages peuvent être utilisés pour:
– )); l'apparence du trait (du contour) ,
– surface.draw(dessin); l'apparence du fond de la forme choisie.
}
– Suivant le cas, il suffit alors de faire appel,
– }
soit à la méthode draw( ),
– Remarque: valeurs par défauts sont BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0F,
motif, 0 soit à la méthode fill( ) de la classe Graphics2D.
Graphisme 2D et les images: remplissage Graphisme 2D et les images: remplissage
Couleurs unies Remarque
– La méthode setPaint( ) de la classe Graphics2D permet de sélectionner une couleur qui – On peut spécifier une couleur personnalisée en créant un objet Color à l'aide de ses
sera employée par toutes les opérations de dessin ultérieures pour le contexte graphique. composantes rouge, verte et bleue.
surface.setPaint(Color.red); En utilisant une échelle de 0 à 255 (chaque composante est codée sur un octet) pour
– Pour dessiner avec plusieurs couleurs, effectuer une opération, puis sélectionner une les proportions de rouge, de vert et de bleu, appelez le constructeur de Color de la
autre couleur avant de procéder à l'opération suivante. façon suivante :
– Les couleurs sont définies à l'aide de la classe Color. – surface.setPaint(new Color(0, 128, 128)); // un bleu-vert foncé
– La classe java.awt.Color propose des constantes prédéfinies pour les treize couleurs
standard indiqué dans le tableau ci-dessous. – Les méthodes brighter( ) et darker( ) de la classe Color produisent des versions plus
vives ou plus foncées de la couleur actuelle.
Constantes prédéfinies Couleur standard correspondante
La méthode brighter() permet de mettre un élément en surbrillance, mais avive en
Color.black noir
Color.blue bleu
réalité à peine la couleur.
Color.cyan cyan (bleu clair) Pour obtenir une couleur plus visible, appelez plusieurs fois la méthode.
Color.darkGray gris foncé – ObjetCouleur.brighter().brighter().brighter();
Color.gray gris
Color.green vert
Color.lightGray gris clair
Color.magenta magenta
Color.orange orange
Color.pink rose
Color.red rouge
Color.white blanc
Color.yellow jaune
Graphisme 2D et les images: tracé de texte Graphisme 2D et les images: tracé de texte
Changement de police
Tout comme le tracé du contour d'une forme, celui du texte n'est qu'une variante du remplissage – Il est possible d'écrire un texte avec une police différente que celle prévue par défaut.
d'une forme.
Les polices de caractères, appelées aussi fontes, sont représentées par des objets de la
classe java.awt.Font.
Lorsqu’on demande à un Graphics2D de dessiner un texte, – Un objet Font est construit à partir d'un nom de police, un identificateur de style et d'une
– il détermine les formes nécessaires au dessin et les remplit. taille.
Les formes représentant des caractères sont baptisées Glyphes. Font police = new Font( nom de police, style, taille );
Une police est une collection (un ensemble) de glyphes. – Il existe trois sortes de noms de polices :
les familles, les caractères (également baptisés noms de polices) et les noms
Pour dessiner un texte, on fait appel à la méthode drawString( ) de Graphics2D qui existait déjà logiques.
dans la classe mère Graphics, – Les noms de famille et les noms de police sont étroitement liés.
– Elle est redéfinie afin de permettre les différents traitements Par exemple, "Garamond Italic" est une police de la famille "Garamond".
remplissage, tranformations, clipping, etc.... Police logique
– surface.drawString("Bienvenue ! ", 50, 150)); – Un nom logique est un nom générique attribué à la famille.
– Lors de l’appel de drawString( ), – Les noms des polices logiques ci-dessous sont en général disponibles sur toutes les
Graphics2D utilise la police courante pour récupérer les glyphes correspondant aux plateformes :
caractères de la chaîne. Serif (nom générique de TimesRoman) ;
– Puis les glyphes (qui ne sont pas des Shape) sont remplis à l'aide du Paint en SansSerif (nom générique de Helvetica) ;
cours. Monospaced (nom générique de Courier) ;
Graphics2D.drawString(texte à afficher, x, y)); Dialog ;
DialogInput.
Graphisme 2D et les images: tracé de texte Graphisme 2D et les images: tracé de texte
Graphisme 2D et les images: tracé de texte Graphisme 2D et les images: tracé de texte
Taille d'une police de caractères
Changement d'un seul paramètre de la police par défaut
– Afin de centrer une chaîne de caractère dans la fenêtre au lieu de l'écrire à une
– Parfois, plutôt que de créer une nouvelle police, il peut être judicieux de changer un seul des
paramètres de la police déjà utilisée. position arbitraire,
– C'est le cas notamment pour changer uniquement le style ou la taille de la police par défaut (ou une On doit connaître la largeur et la hauteur de la chaîne en pixels.
autre déjà existante). – Ces dimensions dépendent de trois facteurs :
– Pour cela, utilisez la méthode deriveFont( ) de la classe Font. La police ou la fonte utilisée.
– Cette méthode est surchargée pour permettre le changement,
La chaîne (ici "Bienvenue").
soit du style de la fonte (le paramètre est de type int),
L'unité sur laquelle la chaîne est écrite (ici, l'écran de l'ordinateur).
soit la taille de la fonte (le paramètre est de type float) :
– fonte.deriveFont(Font.BOLD); // change la style de la police
– fonte.deriveFont(48F); // change la taille de la police – Pour obtenir un objet qui représente les caractéristiques de la fonte utilisée à l'écran,
– Remarque On appelle la méthode getFontRenderContext( ) de la classe Graphics2D.
si on veut changer le nom de la police alors on doit créer une nouvelle fonte.
Exemple (**) Elle renvoie un objet de la classe FontRenderContext.
– class Zone extends JComponent {
– Ce qui permet de récupérer le rectangle qui englobe la chaîne au moyen de la
protected void paintComponent(Graphics g) {
méthode getStringBounds( ) de la classe Font :
– Graphics2D surface = (Graphics2D) g;
– surface.setPaint(new GradientPaint( 10, 10, Color.red, 30, 30, Color.yellow, true ));
– surface.setFont(this.getFont().deriveFont(48F)); FontRenderContext contexte = surface.getFontRenderContext();
// surface.setFont(new Font("SansSerif", Font.ITALIC+Font.BOLD, 48)); Surface est le contexte graphique dans lequel on dessine le texte
– surface.drawString("Bienvenue !", 10, 50); contexte : le contexte d'affichage de police « il gère les métriques du
} texte »
– } Rectangle2D rectangle = fonte.getStringBounds("Bienvenue !", contexte);
Graphisme 2D et les images: tracé de texte Graphisme 2D et les images: tracé de texte
– L'interligne (leading) :
est l'intervalle entre la partie inférieure d'une ligne et la partie supérieure de la ligne
suivante.
– La hauteur (height) :
est la distance verticale entre deux lignes de base successives et équivaut à (jambage
descendant + interligne + jambage ascendant).
Graphisme 2D et les images: tracé de texte Graphisme 2D et les images: tracé de texte
Exemple qui centre le texte "Bienvenue!" dans le sens de la hauteur et dans le sens de la largeur
– class Zone extends JComponent {
Remarque
protected void paintComponent(Graphics g) {
– La largeur (width) du rectangle que renvoie la méthode getStringBounds() est l'étendue – Graphics2D surface = (Graphics2D) g;
horizontale de la chaîne. – surface.setPaint(new GradientPaint(10, 10, Color.red, 30, 30, Color.yellow, true));
– String message = "Bienvenue !";
– La hauteur du rectangle est la somme des jambages ascendant, descendant et de – Font police = getFont().deriveFont(48F);
l'interligne. – surface.setFont(police);
– FontRenderContext contexte = surface.getFontRenderContext();
– L'origine du rectangle se trouve à la ligne de base de la chaîne. – Rectangle2D rectangle = police.getStringBounds(message, contexte);
// coin supérieur gauche du texte
– double x = (this.getWidth( ) - rectangle.getWidth( )) / 2;
– La coordonnée y supérieure du rectangle est négative.
– double y = (this.getHeight( ) - rectangle.getHeight( )) / 2;
// ajouter jambage ascendant à y pour atteindre la ligne de base
On peut obtenir les valeurs de largeur, de hauteur et des jambages ascendant d'une chaîne de la – double ascendant = - rectangle.getY( );
façon suivante : – surface.drawString(message, (int) x, (int) (y+ascendant));
– FontRenderContext contexte = surface.getFontRenderContext(); – // surface.drawString(message, (float) x, (float) (y+ascendant));
– Rectangle2D rectangle = fonte.getStringBounds("Bienvenue !", contexte); } // ainsi j‘affiche à la base du rectangle englobant
– double largeur = rectangle.getWidth( ); – }
– double hauteur = rectangle.getHeight( );
Remarque:
– double ascendant = - rectangle.getY( ); – Y + ascendant: car l’écriture de l’image du String doit commencer à la ligne principale du rectangle
englobant, donc on doit descendre de y par la valeur de ascendant qui est négative.
Graphisme 2D et les images: tracé de texte Diagramme UML récapitulant les différentes classes utilisées
Remarque
– Si on veut connaitre le jambage descendant ou l'interligne, on doit appeler la méthode
getLineMetrics() de la classe Font.
– Cette fonction renvoie un objet de la classe LineMetrics,
possédant les méthodes permettant d'obtenir les dimensions intrinsèques d'une police
de caractères, comme :
– getAscent( ) : jambage ascendant.
– getLeading( ) : interligne.
– getDescent( ) : jambage descendant.
– getHeight( ) : hauteur.
– Exemple
FontRenderContext contexte = surface.getFontRenderContext();
LineMetrics dimensions = fonte.getLineMetrics("Bienvenue !", contexte);
float ascendant = dimensions.getAscent();
float hauteur = dimensions.getHeight();
float descendant = dimensions.getDescent();
float interligne = dimensions.getLeading();
Graphisme 2D et les images: dessin d'images Graphisme 2D et les images: dessin d'images
Les images sont traitées un peu différemment des formes.
– En particulier, on ne fait pas appel au Paint courant pour dessiner une image car celle-ci Remarque
contient ses propres informations de couleurs. – La classe java.awt.Image représente une vue d'une image.
– La vue est créée à partir d'une image source fournissant des données sous la forme de
Comme pour le texte, la classe Graphics2D dispose de la méthode spécifique drawImage( ) qui pixels.
permet de placer l'image à l'emplacement indiqué. – Les images peuvent provenir
d'une source statique, comme des fichiers GIF, JPAG, PNG
– Cette méthode a pour premier argument l'objet de type Image qui représente l'image réelle d'une source dynamique comme un stream d'animation ou un moteur graphique.
récupérée à partir du disque dur. – La classe Image de Java_2D gère également l'animation GIF89a (gifs animés), de sorte
On sait que la classe ImageIO permet de récupérer un tel fichier. qu'il est aussi facile de travailler avec des animations simples qu'avec des images statiques.
– Image image = ImageIO.read(new File("fichier image.gif"));
– surface.drawImage(image, 50, 150, null));
Aussi, la méthode read( ) de la classe ImageIO peut récupérer une image à partir
d'une URL :
– Image image = ImageIO.read(new URL("http://site/répertoire/fichier_image.gif"));;
– surface.drawImage(image, 50, 150, null));
Remarque
– La variable image contient une référence à un objet qui encapsule les données images.
On peut afficher l'image grâce à la méthode drawImage( ) de la classe Graphics.
– surface.drawImage(image, positionX, positionY, spectateur));
Graphisme 2D et les images: dessin d'images Graphisme 2D et les images: dessin d'images
Exemple d’affichage d’une image à partir du coin supérieur gauche Exemple d’affichage d’une image en tenant compte de la dimension de l'image afin qu'elle soit
toujours centrée par rapport à l’écran:
– class Zone extends JPanel{
– class Zone extends JComponent {
protected void paintComponent(Graphics g) {
protected void paintComponent(Graphics g) {
– Graphics2D surface = (Graphics2D) g;
– Graphics2D surface = (Graphics2D) g;
– try {
– try {
Image image = ImageIO.read(new File("chouette.jpg"));
Image image = ImageIO.read(new File("chouette.jpg"));
surface.drawImage(image, 0, 0, null);
double positionX = (this.getWidth()-image.getWidth(null)) / 2;
– }
double positionY = (this.getHeight()-image.getHeight(null)) / 2;
– catch (IOException e) {
surface.drawImage(image, (int)positionX, (int)positionY, null);
surface.drawString("Image inexistante", 10, 10);
– }
– }
– catch (IOException e) {
}
surface.drawString("Image inexistante", 10, 10);
– }
– }
}
– }
Graphisme 2D et les images: dessin d'images Graphisme 2D et les images: dessin d'images..
Imposer une taille à l'image Spectateurs
– La méthode drawImage( ) permet de changer l'échelle d'une image. – Problèmes:
Cette version de la fonction drawImage( ) utilise deux arguments supplémentaires Lorsque Java récupère une image, comment savoir si elle est entièrement chargée ?
pour désigner Que se passe-t-il si nous avons besoin de connaître les propriétés de l'image (comme ses
– la largeur et la hauteur voulues quelle que soit les dimensions originales de dimensions) avant de pouvoir commencer à travailler avec?
l'image. Que se passe-t-il si une erreur se produit lors du chargement de l'image ?
– Ces problèmes sont traités par les spectateurs:
surface.drawImage(image, positionX, positionY, largeur, hauteur,
spectateur)); se sont des objets des classes qui implémentent l'interface ImageObserver.
– Toutes les opérations qui dessinent ou traitent des objets Image reviennent immédiatement,
Cette méthode permet donc de réaliser un reéchantillonage : mais prennent un objet spectateur en paramètre.
– Exemple qui adapte la taille de l'image à la dimension de la fenêtre (Attention, le ratio ??? – Les objets ImageObserver surveillent l'état de l'image et mettent ces informations à la
n'est pas respecté: ratio = rapport de la hauteur et de largeur de l’image) : disposition du reste de l'application.
class Zone extends JComponent { – Lorsque les données de l'image sont chargées, un spectateur est informé de la progression.
– protected void paintComponent(Graphics g) { – Le spectateur est averti de la disponibilité de nouveaux pixels, de l'achèvement d'une zone
de l'image et de la survenue d'une erreur en cours de chargement.
Graphics2D surface = (Graphics2D) g;
– Le spectateur reçoit dès que possible certains attributs sur l'image tels que la dimensions et
try { d'autres propriétés.
Image image = ImageIO.read(new File("chouette.jpg")); – Remarque
surface.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), La méthode drawImage() prend une référence sur un objet ImageObserver en paramètre.
null); Cette méthode renvoie une valeur booléenne qui indique si l'image a été (ou pas) affichée
} entièrement.
catch (IOException e) { surface.drawString("Image inexistante", 10, 10); } – Si l'image n'a pas encore été téléchargée ou si elle n'est qu'en partie disponible, la méthode
drawImage() ne dessine qu'une fraction de l'image et se termine.
– }
}
Graphisme 2D et les images: dessin d'images Graphisme 2D et les images: dessin d'images
Remarque**
Remarque
– Le spectateur peut faire ce qu'il veut des informations qu’il reçoit. – Dans l’exemple, notre composant Zone est utilisé comme spectateur et appelle la méthode
Le plus souvent, il appelle la méthode repaint( ) (qui fait appelle à paintComponent()) pour ordonner au
repaint( ) pour redessiner l'image si nécessaire.
composant graphique contenant l'image de dessiner la zone de l'image fraîchement arrivée. Si l'image arrive lentement, le composant Zone est averti régulièrement à l'arrivée de
– Il existe des spectateurs préfabriqués. Il se trouve précisément dans tous les composants graphiques, comme nouvelles données.
JComponent. L'image est donc affichée progressivement.
JComponent implémente l'interface ImageObserver et fournit une fonction de rafraîchissement simple. – Les propriétés awt.image.incrementaldraw et awt.image.redrawrate contrôle le
Cela signifie que tout composant graphique peut être utilisé comme son propre spectateur. comportement de l’affichage progresseive.
Exemple **: en faisant passer une référence à notre propre objet graphique à l'aide de this.
redrawrate limite le nombre d'appels à la méthode repaint( ) : la valeur par défaut est
– class Zone extends JComponent {
une fois toutes les 100 millisecondes.
protected void paintComponent(Graphics g) {
– incrementaldraw est la valeur par défaut.
– Graphics2D surface = (Graphics2D) g;
– try { – Elle est initialisée à true.
Image image = ImageIO.read(new File("chouette.jpg")); – Il suffit de la positionner à false pour différer le tracé de l'image.
double positionX = (this.getWidth() - image.getWidth(this)) / 2; – Dans les exemples précédant, le spectateur = null, puisque l'image est petite et de plus
double positionY = (this.getHeight() - image.getHeight(this)) / 2; elle est présente sur le disque dur.
surface.drawImage(image, (int)positionX, (int)positionY, this); L'interface ImageObserver déclare une unique méthode imageUpdate
– } Il est possible de redéfinir la méthode imageUpdate pour suivre le chargement de l'image. Cette
– catch (IOException e) { méthode reçoit plusieurs paramètres dont le premier est l'image et le second infoflags est un
– surface.drawString("Image inexistante", 10, 10); entier qui indique (par certains bits) quelles informations sont maintenant disponibles.
– } – public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height) {
} System.out.println("imageUpdate() : x = " + x + ", y = " + y + ", width = " + width + ", height = " + height);
– // Affichage de l'image lorsque l'image est totalement chargée
– }
– if ((flags & ALLBITS) != 0) repaint(); return true; }
Graphisme 2D et les images: dessin d'images Graphisme 2D et les images: dessin d'images
Toutes les méthodes drawImage sont données par:
Remarque** – public boolean drawImage(Image img, int x, int y, ImageObserver spectateur)
– System.setProperty("awt.image.incrementalDraw", "true"); Affiche l'image à l'endroit indiqué
– boolean incrementalDraw = Boolean.getBoolean ("awt.image.incrementalDraw"); – public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver
– Long redrawRate = Long.getLong ("awt.image.redrawrate"); spectateur)
– if (incrementalDraw) { Les parties transparentes sont rendues dans la couleur de fond «bgcolor ».
if (redrawRate != null) { – public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver
– long tm = redrawRate.longValue( ); spectateur)
– if (tm < 0) tm = 0; L’image est déformée pour remplir le rectangle donné.
– repaint (tm); – public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor,
ImageObserver spectateur)
}
L’image est déformée pour remplir le rectangle donné. Variante avec couleur de fond.
else repaint (100);
– public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int
– }
sx2, int sy2, ImageObserver spectateur)
La partie de l'image délimitée par le rectangle donné par les points s1 et s2 est
affichée dans le rectangle donné par les points d1 et d2. Une déformation peut avoir
lieu.
– public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int
sx2, int sy2, Color bgcolor, ImageObserver spectateur)
La partie de l'image délimitée par le rectangle donné par les points s1 et s2 est
affichée dans le rectangle donné par les points d1 et d2. Une déformation peut avoir
lieu. Variante avec couleur de fond.
Graphisme 2D et les images: dessin d'images Graphisme 2D et les images: Transformation de coordonnées
La classe Image permet de faire quelques traitements élémentaires sur les images en voici les On sait que quatre parties du pipeline d'affichage affectent chaque opération graphique.
principaux : – En particulier, tout le rendu est transformé, composé et masqué.
– int getHeight(ImageObserver ) retourne la hauteur de l’image en pixels. Supposons qu’on doit dessiner un objet, par exemple une voiture.
– int getWidth(ImageObserver ) retourne la largeur de l’image en pixels. – On connait, grâce aux indications du constructeur, la hauteur, l'empattement et la longueur
– Image getScaledInstance(int, int, int) retourne une copie redimensionnée de l’image. totale de cette voiture.
les deux premiers paramètres précisent la hauteur et la largeur désirées pour la copie. – On peut naturellement déterminer la position de tous les pixels, en choisissant une échelle
Si l’un d’entre eux vaut –1 il sera adapté pour conserver l’aspect initial de l’image. en nombre de pixels par mètre.
Le dernier paramètre indique l’algorithme à utiliser pour créer cette copie. Il peut – Cependant, il existe une technique plus simple, on peut demander au contexte graphique
prendre les valeurs : d'effectuer une conversion à notre place « changement d’échelle »:
– Image.SCALE_DEFAULT surface.scale(pixels par mètre, pixels par mètre);
algorithme standard surface.draw(new Rectangle2D.Double(coordonnées et dimensions en mètres)));
– Image.SCALE_FAST La méthode scale() (étirement) de la classe Graphics2D définit la transformation de
algorithme rapide coordonnées du contexte graphique et choisit une transformation d'échelle.
– Image.SCALE_SMOOTH – Cette transformation permet de passer de coordonnées de l'utilisateur (c'est-à-dire les
algorithme qui préserve la qualité de l’image unités spécifiées par l'utilisateur) à des coordonnées machine (c'est-à-dire des pixels).
– Image.SCALE_REPLICATE
algorithme simple qui se contente de dupliquer ou d’enlever des pixels
– Image.SCALE_AVERAGING
algorithme qui utilise une méthode basée sur la moyenne entre pixels
voisins.
Graphisme 2D et les images: Transformation de coordonnées Graphisme 2D et les images: Transformation de coordonnées
Types de transformation pour les transformations affines
Remarque – Il existe quatre transformations fondamentales pour les transformations de coordonnées:
– Les transformations de coordonnées sont très utiles dans la pratique. Changement d'échelle - scale( ): Réduit ou augmente toutes les distances à un point
Elles permettent de travailler avec des valeurs de coordonnées plus simple et plus spécifié (on fait c’est un étirement ou homothéties).
significatives. Rotation - rotate( ) : Tourne tous les points autour d'un point fixe.
Elles correspondent à notre logique métier, avec celles dont on a l'habitude de Translation - translate( ): Déplace tous les points d'une quantité donnée.
travailler.
Déformation linéaire - shear( ) : Une ligne reste fixe et toutes les lignes parallèles sont
Le contexte graphique s'occupe ensuite de les transformer en pixels ( à notre place). décalées d'une quantité proportionnelle à la distance entre cette ligne et la ligne fixe.
(cisaillement).
– Remarque
Les méthodes scale( ), rotate( ), translate( ) et shear( ) de la classe Graphics2D
choisissent
– une transformation de coordonnées pour le contexte graphique, en fonction de
l'une de ces quatre transformations fondamentales (avec possibilité de
concaténation d’une transformation avec la transformation courante).
Graphisme 2D et les images: Transformation de coordonnées Graphisme 2D et les images: Transformation de coordonnées
En général une transformation affine est donnée par le système:
Le cisaillement ( shear( ) ) est une transformation qui fait penser à un étirement selon un axe.
– X’ = a X + b Y + e
Le cisaillement selon l'axe des x ne modifie pas la coordonnée en y
– Y’ = d X + c Y + f
tandis que le cisaillement selon l'axe des y ne modifie par la coordonnée en x.
Types de transformation
On peut également combiner ces deux cisaillements
– avec un Graphics2D, on peut effectuer:
On a
des rotations:
– Cisaillement selon les abscisses : x' = x + shx * y; y' = y
– rotate(double theta)
– Cisaillement selon les ordonnées : x' = x; y' = y + shy * x
theta = angle en radians dans le sens des aiguilles d'une montre
des homothéties:
– scale(double sx, double sy)
x' = x + shx . y sx et sy = coefficients de l'homothétie
y' = y
des cisaillements: (étirement suivant l’axe x et/ou axe y)
– shear(double shx, double shy)
– shx et shy = coefficients du cisaillement
Les translations: il existe 2 méthodes documentées un peu différemment:
– translate(int x, int y)
le point (x, y) est la nouvelle origine du repère
– translate(double tx, double ty)
tx et ty sont les longueurs des déplacements horizontaux et verticaux
– Remarque: En pratique, ça revient au même
Graphisme 2D et les images: Transformation de coordonnées Graphisme 2D et les images: Transformation de coordonnées
Transformation.shear(shx, shy); où 0 0 1
Graphisme 2D et les images: Transformation de coordonnées Graphisme 2D et les images: Transformation de coordonnées
Graphisme 2D et les images: Transformation de coordonnées Graphisme 2D et les images: Transformation de coordonnées
Remarque
– Les méthodes: getRotateInstance( ), geScaletInstance( ), getTranlateInstance( ) et Exemple de synthèse
getShearInstance( ), de la classe AffineTransform, construisent des objets de – Cet exemple regroupe: le tracé de formes quelconques, de texte et d'image
transformation affine relatif aux transformations requises.
Ceci permet de montrer que les transformations s'appliquent quelque soit le type de
AffineTransform Transformation =AffineTransform.getTranslateInstance(10, 250); tracé.
– On commence par le code sans aucune transformation:
– Une fois qu'un objet AffineTransform est construit,
Graphisme 2D et les images: Transformation de coordonnées Graphisme 2D et les images: Transformation de coordonnées
class Zone extends JComponent {
– protected void paintComponent(Graphics g) { Utilisation d’un objet AffineTransfom pour le dessin d’une forme: (voir classe TesteImage _8)
Graphics2D surface = (Graphics2D) g; – AffineTransform at = new AffineTransform( );
AffineTransform transformation = surface.getTransform(); // transformation initiale= identité
try {
– at.translate(150,200);
surface.shear(-0.5, 0); – at.rotate(-Math.PI/3);
surface.translate(70, 0);
– at.scale(2, 0.5);
Image image = ImageIO.read(new File("chouette.jpg"));
surface.drawImage(image, 10, 10, getWidth( ) / 2, getHeight( ) / 2, null); – Ellipse2D.Float cercle = new Ellipse2D.Float(-50, -50, 100, 100);
surface.setTransform(transformation); // recup trans formation_initiale
– Shape shape = at.createTransformedShape(cercle); // création d’une forme via AffineTransform
// tracé du pétale de fleur
surface.rotate(-Math.PI/4, 150, 170); – surface.draw(shape);
CubicCurve2D pétale = new CubicCurve2D.Double(150, 170, 10, 10, 290, 10, 150, 170); Remarque:
surface.setPaint(Color.BLUE);
surface.fill(pétale); – Le dessin du cercle passe par un scale, une rotate et enfin par une translate.
Ellipse2D cercle = new Ellipse2D.Double(120, 140, 60, 60); – Ceci est fait via l’tilisation d’un objet de type AffineTransform sans toucher à la
surface.setStroke(new BasicStroke(10));
transformation affine par défaut associée au contexte graphique
surface.draw(cercle);
surface.setPaint(new Color(255, 128, 0));
surface.fill(cercle); surface.setTransform(transformation);
// tracé du message de bienvenue
surface.shear(0.5, 0.4);
surface.translate(-20, - 20);
surface.setPaint(new GradientPaint(10, 10, Color.red, 30, 30, Color.yellow, true));
String message = "Bienvenue !";
Font police = this.getFont().deriveFont(48F);
surface.setFont(police);
surface.drawString(message, 20, 80); }
catch (IOException e) { surface.drawString("Image inexistante", 10, 10); } } }
Graphisme 2D et les images: clipping Graphisme 2D et les images: clipping
En définissant une forme de clipping dans le contexte graphique, on restreint toutes les
opérations graphiques à l'intérieur de cette forme. Exemple
Le clipping = limiter l'affichage à une région définie par une forme géométrique // créer un arc de type corde de 240°
– Cela correspond à la mise en œuvre d'un masque dans les logiciels de traitement d'images. – Arc2D.Double arc = new Arc2D.Double(0, 0, getWidth(), getHeight(), 0, 240, Arc2D.CHORD);
surface.setClip(forme du masque); // ************ définir la zone de dessin de clippage.
surface.draw(forme quelconque); – surface.setClip(arc);
– Cela permet d’afficher uniquement la partie de la forme qui se trouve à – Image image = ImageIO.read(new File("Images/lapin3.jpg"));
l'intérieur du masque. – surface.drawImage(image, 0, 0, getWidth( )/2, getHeight( )/2, this);
// ************ créer un rectangle
Dans la pratique, on n'appelle pas explicitement la méthode setClip( ) puisqu'elle remplace le – Rectangle2D.Double rect = new Rectangle2D.Double(0, 0, getWidth( ) / 2, getHeight()/2);
masque que le contexte graphique possède éventuellement.
// **** modifier la zone de dessin = intersection de l’ancienne avec le rectangle
– Par exemple,
– surface.clip(rect);
un contexte graphique d'impression contient un masque sous forme de rectangle qui
– Image image2 = ImageIO.read(new File("Images/papillon.jpg"));
empêche d'imprimer sur les marges de la feuille.
– surface.drawImage(image2, 0, 0, getWidth()/4, getHeight()/2, this);
Il vaut mieux, à la place, appeler la méthode clip( ) du contexte graphique
– Dans ce cas là, c'est juste la forme qui est passée en paramètre qui sert de masque
temporaire.
surface.clip(forme du masque);
– La méthode clip() réalise l'intersection du masque existant avec la nouvelle
forme de masque qu’on passe en paramètre.
Graphisme 2D et les images: clipping Graphisme 2D et les images: clipping via un Texte
Fabriquer un masque (ou un clipping) à partir d'un texte
– On va utiliser un exemple qui utilise un texte comme masque.
– Puis, on va afficher une image au travers de ce masque.
– Ceci consiste à utiliser un gestionnaire de disposition particulier qui permet de placer des
éléments quelconques (des formes, des images ..) dans la surface délimité par un texte.
Ce gestionnaire est représenté par la classe TextLayout.
Remarque Remarque
– la classe TextLayout (package java.awt.font) enregistre la représentation graphique d'un – La classe TextLayout possède une méthode importante:
texte avec ses différents attributs (police, style, ...). ** getOutLine( )
– qui retourne un objet Shape qui décrit la forme du contour des caractères,
– Cette classe utilise un objet de type ** utilisés dans le texte , dans la mise en page de texte retenu.
FontRenderContext qui gère les métriques du texte (les dimensions d’un texte) dans – Cette méthode prend comme paramètre un objet de type AffineTransform.
le contexte graphique donné. « elle représente les caractéristiques de fonte à l'écran »
La forme du contour commence à l'origine (0, 0) qui va correspondre à la ligne de
– Les dimensions d'un texte ( c.à.d.: le rectangle englobant) peuvent être récupéré en base (donc la partie au-dessus de la ligne de base ne sera pas visible), ce qui n'est pas
invoquant la méthode getBounds( ) sur l'objet de type TextLayout. très pratique pour la plupart des opérations de dessin.
– Aussi, on peut utiliser via la classe TextLayout, les méthode suivantes: – Par conséquent,
getAdvance: longueur du texte, il faut fournir une transformation affine comme paramètre, au moyen de la
classe AffineTransform, pour la méthode getOutLine( ), afin de spécifier
getAscent: hauteur de lettre de base à haut total,
la nouvelle position du contour.
getDescent: base à queue des lettres,
getLeading : interligne
On prendra ce contour comme zone de clliping afin d’afficher une image à travers ce
masque
Graphisme 2D et les images: Transparence et composition Graphisme 2D et les images: Transparence et composition
Règles de composition pour la transparence
– Lorsqu’on superpose deux formes alors Mise en oeuvre de la composition
on mélange ou on compose les couleurs et les valeurs alpha des pixels sources et destinations. – La méthode setComposite() de la classe Graphics2D sert à installer un objet d'une classe
– Il existe douze règles de composition possibles pour ce traitement. qui implémente l'interface Composite.
Elles permettent de spécifier une préférence plus marquée soit sur la source ou soit sur la L'API Java2D fournit une classe de ce type, AlphaComposite, qui implémente les
destination (voir tableau) : règles (les douze règles précédentes).
– Remarque: œufs
– La méthode getInstance( ) de la classe AlphaComposite fournit un objet AlphaComposite.
Si les règles sont obscures et mystérieuses, il suffit de choisir la règle SRC_OVER.
On doit fournir la règle et la valeur alpha à utiliser pour les pixels source :
– Il s'agit de la règle par défaut pour les objets Graphics2D et c'est celle qui fournit les
résultats les plus intuitifs. – int règle = AlphaComposite.SRC_OVER;
CLEAR La source efface la destination. – float alpha = 0.25F ;
SRC La source remplace la destination et les pixels vides.
– surface.setComposite(AlphaComposite.getInstance(règle, alpha));
DST La source n'affecte pas la destination. – surface.setPaint(Color.blue);
SRC_OVER La source est mélangée à la destination et remplace les pixels vides. – surface.drawString("Chouette", 10, 130);
DST_OVER La source n'affecte pas la destination et remplace les pixels vides. – Voici quelques exemples de l'exemple précédent suivant la règle de composition :
SRC_IN La source remplace la destination. AlphaComposite.CLEAR
SRC_OUT La source efface la destination et remplace les pixels vides. AlphaComposite.SRC_OUT
DST_IN L'alpha de la source modifie la destination. AlphaComposite.DST
DST_OUT Le complément de l'alpha de la source modifie la destination. AlphaComposite.DST_OVER
SRC_ATOP La source se mélange à la destination. AlphaComposite.DST_IN
AlphaComposite.DST_OUT
DST_ATOP L'alpha de la source modifie la destination. La source remplace les pixels vides. AlphaComposite.DST_ATOP
XOR Le complément de l'alpha de la source modifie la destination. La source remplace les pixels vides. AlphaComposite.XOR
Graphisme 2D et les images: Transparence et composition Graphisme 2D et les images: Conseil d'affichage
Graphisme 2D et les images: Conseil d'affichage Graphisme 2D et les images: Conseil d'affichage
Clé Valeurs Explications
VALUE_ANTIALIAS_ON,
Active ou désactive l'anticrénelage des
KEY_ANTIALIASING VALUE_ANTIALIAS_OFF,
formes. L'anticrénelage : anti-aliasing
VALUE_ANTIALIAS_DEFAULT
Lorsque c'est possible, sélectionne des – L'aspect le plus intéressant est la gestion de l'anticrénelage (en anglais : anti-aliasing). Il
VALUE_RENDER_QUALITY,
KEY_RENDERING VALUE_RENDER_SPEED,
algorithmes d'affichage pour un meilleur s'agit d'une technique permettant de réduire l'effet d'escalier des lignes inclinées et des
résultat en termes de qualités ou de
VALUE_RENDER_DEFAULT courbes.
vitesse.
VALUE_DITHER_ENABLE,
Active ou désactive la diffusion (dithering) – Dans la première image, on constate que
des couleurs. La diffusion simule un nombre
KEY_DITHERING VALUE_DITHER_DISABLE, les formes et les textes sont affichés avec un effet de marches d'escalier . Cet effet est
plus important de couleurs en créant des
VALUE_DITHER_DEFAULT
motifs de couleurs proches. très peu esthétique
VALUE_TEXT_ANTIALIAS_ON,
KEY_TEXT_ANTIALIASING VALUE_TEXT_ANTIALIAS_OFF,
Active ou désactive l'anticrénelage des – Dans la deuxième image
polices.
VALUE_TEXT_ANTIALIAS_DEFAULT
Le résultat est plus précis, l’image et le texte sont plus lisses aux bords qu’avant.
Active ou désactive le calcul des dimensions
VALUE_FRACTIONALMETRICS_ON, fractionnelles des caractères. Les
KEY_FRACTIONALMETRICS VALUE_FRACTIONALMETRICS_OFF, dimensions fractionnelles des caractères
VALUE_FRACTIONALMETRICS_DEFAULT permettent de les positionner plus
précisément.
VALUE_ALPHA_INTERPOLATION_QUALITY,
Active ou désactive le calcul précis des
KEY_ALPHA_INTERPOLATION VALUE_ALPHA_INTERPOLATION_SPEED,
composantes alpha.
VALUE_ALPHA_INTERPOLATION_DEFAULT
VALUE_COLOR_RENDER_QUALITY,
Choisit la qualité ou la vitesse pour
KEY_COLOR_RENDERING VALUE_COLOR_RENDER_SPEED,
l'affichage des couleurs.
VALUE_COLOR_RENDER_DEFAULT
VALUE_INTERPOLATION_NEAREST_NEIGHB
OR, Sélectionne une règle pour interpoler les
KEY_INTERPOLATION
VALUE_INTERPOLATION_BILINEAR, pixels lorsque les images sont déformées.
VALUE_INTERPOLATION_BICUBIC Sans anticrénelage Avec anticrénelage
VALUE_STROKE_NORMALYZE,
Sélectionne une règle pour la combinaison
KEY_STROKE_CONTROL VALUE_STROKE_PURE,
des traits.
VALUE_STROKE_DEFAULT
Graphisme 2D et les images: Conseil d'affichage Graphisme 2D et les images: Conseil d'affichage
Exemple de programme sur l'anticrénelage global
Remarque
– class Zone extends JComponent {
– Voici comment demander un filtre anticrénelage pour les formes :
protected void paintComponent(Graphics g) {
surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON); – Graphics2D surface = (Graphics2D) g;
– Il peut également être utile d'appliquer un anticrénelage aux polices de caractères // règles de rendu
uniquement : – surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
surface.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // dessin du pétale
– CubicCurve2D pétale = new CubicCurve2D.Double(150, 130, 10, -20, 290, -
20, 150, 130);
– surface.setStroke(new BasicStroke(5));
– surface.draw(pétale);
// dessin du texte
– surface.setFont(new Font("SansSerif", Font.BOLD+Font.ITALIC, 60));
– surface.drawString("Bonjour !", 10, 190);
}
– }
– L’utilisation des threads et le détail de leur comportement est différent dans chaque
système d’exploitation (Windows NT, Unix)
– Certains langages, comme Java, C# ou Ada, définissent leur propre mécanisme de threads,
afin de permettre l’utilisation facile et portable des threads sur tous les systèmes.
Les Threads Les Threads
Intérêts d'une application multi-threads :
En java, il est possible de simuler l'exécution de plusieurs programmes en même temps: – gérer l'exécution de traitements longs sans bloquer les autres
– c'est le multithreading. exemples :
– calculs, affichage et gestion des interactions dans une interface graphique
Les programmes qui utilisent plusieurs threads sont dits multithreadés. – lancer des programmes démons qui tournent en tâche de fond
Le calcul de la multiplication de 2 matrice (m, p) et (p, n) peut être
Le multithreading est intégré au langage Java. effectuée en parallèle par m*n threads
– La création de threads est très simple : Dans une interface de traitement de texte,
Thread t = new Thread ( ); // créer un nouveau thread un thread s'occupe de ce que tape l'utilisateur,
t. start ( ); // lancer ou activer le thread un autre est en charge de souligner les erreurs,
– En créant un nouvel objet Thread, on crée un fil d'exécution qui possède sa propre pile. un 3ème se charge de faire parler le trombone
– lancer plusieurs exécutions du même code simultanément sur différentes données
exemples :
– répondre à plusieurs requêtes en même temps dans un serveur,
– traiter deux flux sonores en parallèle.
– exploiter la structure multi-processeurs des ordinateurs modernes ?
Un thread est dans l’état initial tant que la méthode start n’a pas été appelée sur lui.
Constructeurs de la classe Thread
– Thread( )
Crée un nouveau thread
– Thread(Runnable target)
Crée un nouveau Thread relatif à l'objet implémentant l'interface Runnable
currentThread( )
L’appel à la méthode start lance l'exécution d'un thread, donc on arrive dans l’état “en marche” – Donne le thread actuellement en cours d'exécution
où le fonctionnement du thread est alors soumis à l’ordonnanceur de la machine virtuelle Java. Thread.currentThread() renvoie la référence au thread courant c'est-à-dire celui qui
exécute currentThread( ).La méthode
Une première façon de quitter l’état “en marche” est la terminaison de la méthode run qui setName( )
achève également l’instance d’exécution ou soit à l'exécution de stop( ). – Fixe le nom du thread
Un thread à l'état mort ne peut plus redémarrer. getName( )
– Nom du thread
Il existe en revanche deux méthodes pour suspendre temporairement le fonctionnement d’un isAlive( )
thread : – Indique si le thread est actif (true) ou non (false)
l’appel à la méthode sleep où l’exécution du thread est suspendue pour un temps donné. start( )
l’appel à la méthode wait permet d’attendre certains évènements. – Lance l'exécution d'un thread
run( )
L’appel à la méthode interrupt( ) permet d‘interrompre ou de tuer proprement un thread ceci en – Méthode exécutée automatiquement après que la méthode start() précédente ait été
déclenchant l'exception InterruptedException dans l'objet auquel on applique la méthode. exécutée
sleep(n)
la méthode interrupt( ) sur un thread n’est détectée que si dans la méthode run du thread – Arrête l'exécution d'un thread pendant n millisecondes (throws InterruptedException )
un appel à interrupted( ) est effectué dans le bloc du catch de l’exception – Remarque
InterruptedException pour voir si il y a une interruption.
Si cette méthode est appelée dans du code synchronisé (synchronized) le thread ne
perd pas le moniteur (voir plus loin).
Les Threads: Quelques méthodes Les Threads: Changement d’état
join( )
– Opération bloquante - attend la fin du thread pour passer à l'instruction suivante Un thread passe d'un état exécutable à un état non exécutable (état bloquant) sous l'invocation
– T.join( ) : de l'une de ces méthodes :
bloque le thread courant (qui n'est pas le thread T ), jusqu'à ce que le thread T soit Thread.sleep(long durée), qui suspend le thread durant quelques instants,
terminé. (exemple identification de tous les joueurs avant commencement d’un jeu) – où
throws InterruptedException les méthodes wait de la classe java.lang.Object (utiliser dans la synchronisation)
yield( )
– Provoque une pause de l'exécution du thread et autorise les autres threads à s'exécuter Le passage à un état exécutable à nouveau, à partir d'un état non exécutable se fait soit :
ceux qui ont même priorité ou de priorité supérieure. – après l'écoulement du temps indiqué dans la méthode sleep
– soit après la réception d'une notification d'un autre thread via l’une des méthodes:
interrupt( ) notify( ) ou notifyAll( ).
– permet au thread A de demander l’interruption d’un thread B.
– permet d'interrompre un thread en cours d'exécution d'une méthode
sleep(), join() ou wait()
– Elle provoque la levée de l’exception InterruptedException suite à des appels d’opération
bloquante ( wait( ), join( ) ou .sleep( )).
Les Threads: Démarrage, suspension, reprise et arrêt d'un thread Les Threads: Démarrage, suspension, reprise et arrêt d'un thread
Pour gérer l'exécution des threads, on dispose de différentes méthodes dont celles ci-dessous. – public void stop() :
– public void start( ) : cette dernière méthode permet de stopper, de manière définitive, l'exécution du
cette méthode permet de démarrer un thread. thread.
Remarque, Cette méthode est dépréciée:
– si on invoque la méthode run (au lieu de start), – lorsqu'un thread est tué, il n'est pas possible de savoir ce qu'il était en train de
le code s'exécute bien, mais aucun nouveau thread n'est lancé dans le faire, il est donc possible qu'il soit arrêté au milieu d'une modification d'un
système. objet;
– Inversement, la méthode start, lance un nouveau thread dans le système dont le cet objet est donc laissé dans un état incohérent.
code à exécuter démarre par le run. – Remarque:
Des problèmes similaires peuvent se produire avec les méthodes suspend() et
– public void suspend( ) : resume( ) de plus elles sont sources de nombreux deadlock.
cette méthode permet d'arrêter temporairement un thread en cours d'exécution
(dépréciée). Une solution pour gérer proprement le stop d’un thread, consiste à
– Sortir par un teste dans la boucle de la méthode run.
– public void resume( ) : – Via la levée d’une exception InterrupedException en utilisant la méthode interrupt().
celle-ci permet de relancer l'exécution d'un thread, au préalable mis en pause via
suspend.
Remarque:
– Attention, le thread ne reprend pas au début du run, mais continue bien là où il
s'était arrêté.
Les Threads: Démarrage, suspension, reprise et arrêt d'un thread Les Threads: Démarrage, suspension, reprise et arrêt d'un thread
Exemple (utilisation d’une variable volatile partagée par plusieurs threads)
Remarque: – public class TesteRunnable implements Runnable {
– On peut simuler stop en utilisant une variable. protected volatile int x, j;
public TesteRunnable(int x, int j) { this.x = x; this.j = j; }
Pour rendre l’arrêt d’un thread T, on peut utiliser une variable arretThread visible public void run( ) {
depuis T et les threads qui peuvent stopper T: – for (int i = 0; i < 4; i++) {
– T initialise arretThread à false lorsqu’il démarre. System.out.println("avant sleep " + x++ +", j= "+ j++);
– Pour stopper T, un autre thread met arretThread à true try { Thread.sleep(500);
} catch (InterruptedException e) { System.out.println(e); }
– T inspecte à intervalles réguliers la valeur de arretThread et s'arrête quand
System.out.println("après sleep " + x +", j= "+ j);
arretThread à la valeur true.
– }
}
De plus, arretThread doit être déclarée volatile si elle n’est pas accédée dans du code – }
synchronisé. – public static void main(String args[]) {
– Donc, tous les threads partagent une zone mémoire commune pour ranger la TesteRunnable r = new TesteRunnable(0, 0);
valeur de la variable arretThread (concurrence d’accée arretThread ) Thread tr1 = new Thread(r), tr2 = new Thread(r);
– De plus, si une variable de type long et double est déclarée volatile, sa lecture tr1.start(); tr2.start();
et son écriture est garantie atomique (voir slide 424). – }
Le mot-clé volatile posé sur un paramètre, permet de garantir qu’une valeur écrite ou modifiée
par un thread sera lue correctement par un autre thread. Remarque
Volatile : permet d'assurer un accès ordonné à un champ par deux threads différents – Le mot-clé volatile est relativement peu utilisé et toutes les JVM ne le prennent pas en compte.
Volatile est utilisé pour des types primitifs java seulement. – Le plus souvent, les champs volatiles on les utilises pour terminer ou arrêter un thread
Les Threads: Démarrage, suspension, reprise et arrêt d'un thread Les Threads: Démarrage, suspension, reprise et arrêt d'un thread
Exemple (arrêt d’un Thread utilisant une variable volatile): ok
Exemple (arrêt d’un Thread utilisant un boolean dans la boucle du run)
class ExampleThread extends Thread {
class MonThread extends Thread {
– private volatile int testValue;
– protected volatile boolean running = true;
– public ExampleThread(int testValue) { this.testValue = testValue; }
– public Monthread () {
public void run() {
// Mon constructeur
– for (int i = 0; i < 10; i++) {
– }
if (testValue > 25) { return; }
– public arret( ) { // Méthode 2
testValue += i * i;
running = false;
System.out.println("boucle numero " + i + " avec testValue = " +
– }
testValue);
– public void run() {
try {Thread.sleep(500);
// Initialisation
} catch (InterruptedException exception) { }
while(running == true) { // Boucle infinie pour effectuer des traitements.
– }
– // Traitement à faire
}
– if (/*Condition d'arret*/) // Méthode 1
– public static void main(String args[]) {
– running = false;
ExampleThread ve = new ExampleThread(0);
}
new Thread(ve).start();
– }
new Thread(ve).start();
}
– }
}
Les Threads: Démarrage, suspension, reprise et arrêt d'un thread Les Threads: Démarrage, suspension, reprise et arrêt d'un thread
Exemple (arrêt d’un Thread utilisant la méthode interrupt( )) Exemple (arrêt d’un Thread utilisant la méthode interrupt( ))
– public class ThreadInter extends Thread{ Ou bien; dans le cas
public void run() { – D’attente du retour d'une opération bloquante (wait) dans un état d'attente (sleep), Dans
– try{ ce cas, on peut interrompre le thread
System.out.println("running...");
for(long l = 0; l < 30000000; l++); – public class MonThread extends Thread {
Thread.sleep(1000L); public void run() {
System.out.println("faire..."); – try{
– }catch(InterruptedException e) { while ( ! Thread.currentThread().isInterrupted( ) ) {
System.err.println(e); // autre code…..
– } } catch (InterruptedException e) {
} /* nous avons été interrompu , on remet interrupted à false par
static public void main(String [] args) throws Exception{ l'appel à cette méthode */
– Thread t = new ThreadInter(); Thread.currentThread().interrupted() ; }
– t.start(); – }
– t.interrupt( ); }
– System.err.println("interrupted!"); public void cancel() {
} – // interruption du thread courant, c'est-à-dire le nôtre
– } – Thread.currentThread().interrupt() ;
}
– }
Les Threads: Gestion de la priorité d'un thread. Les Threads: Gestion de la priorité d'un thread.
Ou Ordonnancement des threads Ou Ordonnancement des threads
Remarque:
– Il n'est pas interdit à la machine virtuelle Java d'augmenter la priorité d'un thread trop
longtemps oublié.
Il est donc fortement conseillé de ne pas utiliser la priorité comme ingrédient de
solutions à des problèmes de synchronisation
Les Threads: Gestion de la priorité d'un thread. Les Threads: Gestion de la priorité d'un thread.
Ou Ordonnancement des threads Ou Ordonnancement des threads
Exemple Résultat
– On lance trois threads. Chacun d'eux avec une priorité différente. Au bout d'un certain
temps, le thread initial (celui du main) stoppe les trois autres et l'on regarde le nombre
d'incrémentations réalisé par chacun d'entre eux.
public class ThreadPriority extends Thread { Thread 1 Thread 2 Thread 3
– int counter = 0; Thread.NORM_PRIORITY Thread.NORM_PRIORITY Thread.NORM_PRIORITY
– public void run() {while(true) counter++; // incrémente indéfiniment un compteur}
250 752 409 256 697 243 251 964 807
– public static void main(String args[]) throws Exception {
Thread.MIN_PRIORITY Thread.NORM_PRIORITY Thread.MAX_PRIORITY
ThreadPriority thread1 = new ThreadPriority(), thread2 = new ThreadPriority(),
thread3 = new ThreadPriority();
11 104 663 20 673 290 1 164 460 398
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.NORM_PRIORITY);
thread3.setPriority(Thread.MIN_PRIORITY);
thread1.start(); thread2.start(); thread3.start();
Thread.sleep(5000);
thread1.stop(); thread2.stop(); thread3.stop();
System.out.println("Thread 1 : counter == " + thread1. counter);
System.out.println("Thread 2 : counter == " + thread2. counter);
System.out.println("Thread 3 : counter == " + thread3. counter); }
}
Les Threads: Gestion d'un groupe de threads Les Threads: Gestion d'un groupe de threads
Les Threads: Gestion d'un groupe de threads Synchronisation de threads et accès aux ressources partagées.
class Th2 extends Thread {
Synchronisation de threads et accès aux ressources partagées Synchronisation de threads et accès aux ressources partagées
– Méthodes synchronisées:
Lorsqu'un thread rentre dans la section critique, il acquiert le moniteur et si d'autres Threads
tentent de rentrer dans cette section critique, ils se mettent en attente jusqu'à ce que le thread On peut déclarer qu'une méthode est en section critique sur le moniteur this ou en
détenteur du moniteur le libère utilisant le mot clé synchronized devant la déclaration de la méthode, les deux
syntaxes ci-dessous sont équivalentes
– synchronized void methode( ) { //section critique}
Deux moyens de synchronisation: les méthodes synchronisées et les blocs synchronisés
– void methode() { synchronized(this) { //section critique} }
– Bloc synchronisé sur un objet (un objet quelconque)
Remarque
En Java, tout objet peut jouer le rôle de moniteur.
– objetXX. nomMethode(…) : on synchronise le message methode( ) sur l’objet objetXX
Synchronisation de threads et accès aux ressources partagées Synchronisation de threads et accès aux ressources partagées
Acquisition et restitution d’un moniteur
– Un thread W acquiert automatiquement le moniteur d’un objet F en exécutant du code Résumé
synchronisé sur cet objet F.
– Tant que Thread_1 exécute du code synchronisé sur un objet objetXXX, les autres threads
– W rend le moniteur en quittant le code synchronisé (ou se met en attente en appelant F.wait()
dans le code synchronisé).
ne peuvent exécuter du code synchronisé sur ce même objet objetXXX
– W peut quitter le code synchronisé normalement, ou si une exception est lancée et qui n’est pas Ceci concerne le même code excécuter par thread_1, ou n’importe quel autre code
saisie dans le code synchronisé. synchronisé sur objetXXX , ils sont mis en attente
– Lorsque Thread_1 quitte le code synchronisé ou se met en attente par la méthode wait( ),
Remarque un des threads en attente peut commencer à exécuter le code synchronisé
– utilisation du mot clé synchronized Les autres threads en attente auront la main à tour de rôle (si tout se passe bien…)
synchronized void f( ) { /*...*/ }
synchronized void g( ) { /*...*/ } Exemple : ok
– si f( ) est appelée par l’objet ObjetXXX , donc exécutée par un thread – public class Compte {
g( ) ne peut être appelée sur l’instance ObjetXXX , par un autre thread, tant que f( ) n’est private double solde;
pas terminée dans son exécution.
public void deposer(double somme) {
– il y a mise en place automatique d’un principe de verrouillage (lock) des données de l’instance
concernée. – solde = solde + somme;
– C.a.d « aucune autre méthode synchronisée de l’objetXXX ne peut être exécutée }
tout autre thread T2 qui tentera d’utiliser une opération synchronisée sur ce même objet public double getSolde() {
ObjetXXX (en appelant une autre méthode synchronized de cette même classe) sera bloque – return solde;
jusqu'a ce que ce verrou soit enlevé. }
Mais T2 peut appeler la méthode g avec une autre instance de la même classe que
– }
ObjetXXX
Synchronisation de threads et accès aux ressources partagées Synchronisation de threads et accès aux ressources partagées
Autre exemple
On lance 3 threads du type suivant : – class ListeTab {
private String[ ] tab = new String[50];
– Thread t1 = new Thread() {
private int index = 0; void ajoute(String s) { tab[index] = s; index++; }
public void run( ) {
– }
– for (int i = 0; i < 100; i++) {
Soient deux threads T1 et T2 qui exécutent en parallèle la fonction ajoute(String) sur la même
compte.deposer(1000); ListTab. Donc , on aura les deux exécutions.
– } void ajoute(String s) { void ajoute(String s) {
} tab[index] = s; //(a1) tab[index] = s; //(b1)
– }; index++; //(a2) } index++; //(b2) }
Plusieurs exécutions sont possibles.Par exemple :
A la fin de l’exécution, des trois thread qui attaque le même compte, on n’obtient pas – (a1) (a2) (b1) (b2), est une exécution possible, cohérente ;
nécessairement 300.000 – (a1) (b1) (b2) (a2), est une exécution possible, mais incohérente : le tableau ne contient pas la
chaîne de caractères ajoutée par T1, et une case de la liste est vide.
Remarque: (voir la classe Compte_Cours) Pour éviter cela, on synchronise la section critique
– void ajoute(String s) {
– Pour éviter ce problème, il faut rendre la méthode deposer synchronisée :
Synchronized (tab)){
public synchronized void deposer(double somme)
– tab[index] = s;
– index++;
}
– }
Synchronisation de threads et accès aux ressources partagées Synchronisation de threads et accès aux ressources partagées
Remarque
– Il faut synchroniser le moins de code possible pour faciliter les accès multiples
Remarque
les performances seront meilleures s’il y a moins de threads en attente d’un moniteur.
– Méthodes de classe synchronisées
Si on synchronise une méthode static, on bloque le moniteur de la classe.
– Synchronisation et performances
– On bloque ainsi tous les appels à des méthodes synchronisées de la classe (c.a.d
L’exécution de code synchronisé peut nuire aux performances (un mécanisme toutes les fonctions déclarées static)
couteux)
mais pas les appels synchronisés sur une instance de la classe.
Si un thread entre dans le moniteur de classe alors les autres restent en
Il peut provoquer des blocages entre threads (blocage temporaire de traitement) ; attente.
Du code synchronisé peut empêcher des optimisations (inlining) au moment de la – Méthode synchronisée et héritage
compilation.
La redéfinition d’une méthode synchronisée dans une classe fille peut ne pas être
– appel de méthode « synchronized » est 4 fois + long qu'appel méthode "normal" synchronisée.
De même, la redéfinition d’une méthode non synchronisée peut être synchronisée.
Il faut faire des fonctions synchronisées petites pour que le blocage soit le plus court
possible.
Exécution conditionnelle
– Lorsqu’un programme est multi-tâche, la situation suivante peut se rencontrer : Schéma d’utilisation de wait-notify
Un thread T1 ne peut continuer son exécution que si une condition est remplie – Cette utilisation demande un travail coopératif entre les threads T1 et T2 :
Le fait que la condition soit remplie ou non cela dépend d’un autre thread T2 Ils se mettent d’accord sur un objet commun: Obj
– Par exemple, T1 a besoin du résultat d’un calcul effectué par T2 – Obj est un objet quelconque qui sera l’objet source du blocage
– Obj sera aussi l’objet de verrouillage (-- synchronized (Obj) --).
– Une solution coûteuse serait que T1 teste la condition à intervalles réguliers.
Arrivé à l’endroit où il ne peut continuer que si la condition est remplie,
– Les méthodes wait( ), notify( ) et notifyAll( ) de la classe Object permettent de – T1 se met en attente : Obj.wait( );
programmer plus efficacement ce genre de situation (collaboration entre threads) – wait doit être invoquée sur l’objet verrouillée (le moniteur)
Ces méthodes permettent la communication entre Threads
Quand T2 a effectué le travail pour que la condition soit remplie, il le notifie en
On a un blocage avec wait et déblocage avec notify / notifyAll utilisant l’objet source de blocage de la fonction wait:
Obj.notify( );
Ces méthodes sont implémentées comme final dans la classe Object, de sorte que ce qui débloque T1
toutes les classes en disposent.
Communication entre threads: wait et notify Communication entre threads : wait et notify
Besoin de synchronisation
– Le mécanisme d’attente-notification (Bloquage-débloquage) lié à un objet met en jeu l’état wait(long timeout)
interne de l’objet ; – suspend le processus courant jusqu'à ce que la méthode notify() ou notifyAll() de cet objet
pour éviter des accès concurrent à cet état interne, une synchronisation est nécessaire soit appelée, ou bien que le temps indiqué soit écoulé
Communication entre threads: wait et notify Communication entre threads: wait et notify
Communication entre threads: wait et notify Communication entre threads: wait et notify
/*on arrête si le nombre de jetons présent dans le dépôt est > 100 avec le nombre de jetton
fabriqués est 2 jettons à la fois par le producteur */ Autre exemple
public void run() { – class ListeTab {
– while (true) { private List<String> tab = new ArrayList<>( );
System.out.println("nom thread actif = " + nom); void String supprimer(String s) {
if (depotClient.getNbJetons() > 100) { – synchronized(tab){
– System.out.println("nbJetons en course = " + depotClient.getNbJetons( ) while(tab.isEmpty()) { tab.wait( ) ;}
+ " lors de l'appel de " + nom); String element = tab.remove(0);
– return; – }
} }
if (nom.equalsIgnoreCase("consommateur")) { public void addElemnt(String element){
– depotClient.donneJeton(); cpConsommer++; synchronized(tab){
– System.out.println("le nombre de jetons consommer est: " + cpConsommer); – tab.add(element);
} else if (nom.equalsIgnoreCase("producteur")) { – tab.notifyAll();
– depotClient.recois(2); // fabrique 2 jetton à la fois – ……..
– cpProduit += 2; }
– System.out.println("le nombre de jetons Produit est: " + cpProduit); – }
} – Après pour le teste, on crée deux threads un qui exécute la fonction supprimer et l’autre
else { System.out.println("Ce depot ne fait aucune opération."); } qui fait addElement afin de débloquer celui qui est bloqué par wait
(voir class ObjectDemo)
– }
}
Communication entre threads: wait et notify Communication entre threads: wait et notify --Resumé
Variante de wait Java permet à des threads de "communiquer" entre eux sur leur état via (join, notify, wait).
– Si on ne veut pas attendre éternellement une notification, on peut utiliser une des variantes
suivantes de wait :
Les méthodes wait et notify permettent de gérer la programmation concurrentielle (accès
public void wait(long timeout) concurrent à un même objet par plusieurs threads).
public void wait(long timeout, int nanos)
– Dans ce cas, le thread doit gérer lui-même le fait de connaître la cause de son déblocage Elles permettent de construire un mécanisme explicite de blocage et déblocage (ou mécanisme
(notify ou temps écoulé) d’attente-notification) de Thread.
– Blocage avec wait et déblocage avec notify / notifyAll.
Moniteurs réentrants
– Un thread qui a acquis le moniteur d’un objet peut exécuter les autres méthodes wait() et notify() synchronisent des threads sur un moniteur (objet verrou)
synchronisées de cet objet ; il n’est pas bloqué en demandant à nouveau le moniteur.
– Elles ne peuvent être appelées que depuis un block synchronized ou fonction synchronized
Affectations atomiques
– Il est inutile de synchroniser une partie de code qui ne fait qu’affecter (ou lire) une valeur
à une variable de type primitif de longueur 32 bits ou moins (int, short, …).
En effet, la spécification du langage Java spécifie qu’une telle affectation ne peut être
interrompue pour donner la main à un autre thread.
Mais, cette spécification n’assure rien pour les affectations de double et de long !
– JVM garantit atomicité d'accès au byte, char, short, int, float, réf. d'objet
!! pas long, ni double !!
Pragmatiquement
Définition:
– Un Thread pour repousser une action dans le temps
– Une expression régulière (en anglais regexp pour regular expression) est une chaine de
Dans 3 secondes, si l’utilisateur n’a pas bougé sa souris, afficher un popup disant « caractères «que l’on appelle parfois un motif» qui décrit un ensemble de chaines de
Ce bouton sert à quitter le document » caractères.
– Un Thread pour répéter une action régulièrement Tous les 0.5 secondes, redessine la barre – une expression régulière est une chaîne de caractères écrite dans une syntaxe particulière,
de progression. propre à la bibliothèque d'expressions régulières utilisée.
– Pour ces cas simple, pas besoin de faire des Threads compliqués : Utiliser un Timer !
Exemple:
– L’expression régulière [0-9][a-z] décrit l’ensemble des chaines de caractères composées
d’un chiffre et d’une lettre.
M.AFILAL 454
Utilité des expressions régulières Composantes d’une des expressions régulières: Les caractères
Les expressions régulières ont de nombreuses utilités en informatique, elles servent
principalement pour réaliser : Caractère Signification
– des recherches multiples ou des filtres :
X Le caractère X
ne conserver que certaines lignes d’un fichier texte, de la forme nom=valeur par
exemple \\ Le caractère \
– des contrôles :
\t Le caractère tabulation
vérifier qu’une donnée entrée par un utilisateur a bien le format d’une adresse IP ou
une adresse e-mail par exemple, comme « [email protected] ». \n Le caractère nouvelle ligne
– des substitutions :
\r Le caractère retour chariot
Remplacer un motif par une chaine de caractères précise.
Remplacer une date sous format américain (08-05-1985) pour la mettre au format en \f Le caractère saut de page
français (05/08/1985). Le caractère sonnette '\u0007'
\a
Remplacer automatiquement toutes les adresses « http:// » par des liens cliquables,
comme cela se fait sur certains forums. \e Le caractère d'échappement '\u001B'
– des découpages : Caractère de contrôle de tabulation
récupérer une partie d’une chaine de caractères par exemple découper une ligne par \v
verticale [\x0B]
rapport aux « ; » dans le cas d’un fichier .csv.
Remarque Exemple
– Les expressions régulières sont un moyen très puissant et très important pour faire des – AB\tCD représente la chaine de caractère AB suivit d’une tabulation suivi de CD
recherches dans des ensembles de documents textuels ou dans des chaînes de caractères
et leurs appliquer un traitement automatisé.
M.AFILAL 455 M.AFILAL 456
Composantes d’une des expressions régulières:
Composantes d’une des expressions régulières:
Les méta caractères
Classes de caractères
Méta Caractères Signification
Classe de caractères Signification
. Remplace n'importe quel caractère, sauf la fin de ligne.
[0-9] Un caractère numérique entre 0 et 9
? Opérateur portant sur l'expression précédente : 0 ou une fois l'expression précédente.
[abc] Un caractère de la classe des trois caractères a, b et c
* Opérateur de Kleene : 0, 1 ou plusieurs fois l'expression précédente.
[^abc] Un caractère de la classe de tous Les caractères sauf a, b et c
+ 1 ou plusieurs fois l'expression précédente.
[a-z] Un caractère de a à z
[] Intervalle de caractères.
[a-zA-Z] Un caractère de a à z minuscule ou majuscule
{} Quantificateur.
[a-gmn] Un caractère de a à g, ou m ou n.
\ Le caractère qui suit n'est plus considéré comme un méta-caractère.
On peut inclure des classes les unes dans les autres. Cette classe représente un unique
^ Négation ou début de ligne. [a-g[A-G]] caractère, compris entre a et g, en minuscule ou en majuscule. Elle est équivalente à
$ Fin de ligne. [a-gA-G].
Le signe && représente l'intersection. Le résultat est l'intersection entre la classe [a-g]
| Opérateur ou. [a-g&&[c-k]]
et la classe [c-k]. Il s'agit donc de la classe [c-g].
Le résultat est l'intersection entre la classe qui représente tous les caractères de a à g,
Les méta-caractères sont des caractères qui sont interprétés par l'analyseur. [a-g&&[^cd]] et celle qui représente tous les caractères, sauf c et d. Il reste donc a, b, e, f et g, que
Pour qu'un méta-caractère ne soit par interprété par l'analyseur, il faut le faire précéder du l'on peut aussi écrire [abefg] ou [abe-g].
caractère '\'.
Réalise l'intersection de tous les caractères compris entre a et z, et de tous les
Les caractères '-' et ']' ont un statut spécial : dans un intervalle ce sont des méta-caractères, et [a-z&&[^m-p]]
caractères sauf ceux compris entre m et p. Il nous reste donc [a-lq-z].
en dehors d'un intervalle ils se comportent comme des caractères normaux.
– [a\]b]*c est équivalent à (a|]|b)*c M.AFILAL 457 Exemple M.AFILAL 458
– [a\-b]*c est équivalent à (a|-|b)*c – [0-9][a-z] représente une chaine de caractères constitué d’un chiffre puis d’une lettre
Composantes d’une des expressions régulières: Composantes d’une des expressions régulières:
Classes de caractères prédéfinies Classes de caractères POSIX
Classe de caractères Signification
Classe signification
. Caractère quelconque
\p{Lower} Une minuscule:[a-z]
\d Un caractère numérique: [0-9]
\p{Upper} Une majuscule:[A-Z]
\D Un caractère non numérique: [^0-9]
\p{Alpha} Une caractère alphabétique: [\p{Lower} \p{Upper}]
\s N'importe quel caractère blanc (espace, tabulation, retour-chariot, etc...):
[ \t\n\x0B\f\r] \p{Digit} Un chiffre:[0-9]
\S Un caractère non blanc: [^\s] \p{Alnum} Un caractère alphanumérique:[\p{Alpha} \p{Digit}]
\w N'importe quel caractère utilisable dans un mot (w est utilisé pour word). \p{Punct} Ponctuation: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
Cela représente les caractères alphabétiques minuscules et majuscules, les
chiffres et le caractère souligné (underscore). Notons que les caractères \p{Blank} Espace ou tabulation: [ \t]
accentués ne s'y trouvent pas : [a-zA-Z_0-9]
\p{XDigit} Caractère hexadécimale: [0-9a-fA-F]
\W Inverse de la classe précédente : [^\w]
\p{Space} Un caractère blanc: [ \t\n\x0B\f\r]
N'importe quel caractère minuscule. Les caractères accentués s'y trouvent !
\p{javaLowerCase}
Equivalent to java.lang.Character.isLowerCase() \p{ASCII} tout caractère ASCII :[\x00-\x7F]
N'importe quel caractère majuscule. Les majuscules accentuées s'y
\p{javaUpperCase} \p{Graph} Un caractère visible : [\p{Alnum}\p{Punct}]
trouvent. Equivalent to java.lang.Character.isUpperCase()
\p{javaWhitespace} N'importe quel espace. Equivalent to java.lang.Character.isWhitespace() \p{Print} Un caractère imprimable [\p{Graph}\x20]
X+ X+ X++ X une fois au moins (XX*) Recherche d'un caractère e el{1, 2} Elle est belle Isabelle lorsqu'elle se lève.
suivi par un (minimum) ou
X{n} X{n}? X{n}+ X n fois deux (maximum) l
X{n,} X{n,}? X{n,}+ X, au moins n fois Recherche d'un caractère e el{1,} Elle est belle Isabelle lorsqu'elle se lève.
suivi par un (minimum) ou
X{n, m} X{n, m}? X{n, m}+ X entre n et m fois plusieurs l
Composantes d’une des expressions régulières: Composantes d’une des expressions régulières:
Caractères de répétition Caractères de répétition
Remarque
Les quantificateurs gloutons consomment la chaîne de caractères cible entière lors d'une
première tentative de recherche. Puis si cette première tentative échoue, alors à partir de Remarque
la fin de la chaîne cible, ils reculent d'un caractère, essayent à nouveau une mise en Les quantificateurs hésitants fonctionnent différemment des quantificateurs gloutons. En
correspondance, puis répètent ce processus jusqu'à que ce la recherche réussisse ou qu'il effet, ils démarrent une recherche au début de la chaîne de caractères cible, consomment
n'y ait plus de caractères. un caractère à la fois pour une mise en correspondance. La dernière chose qu'ils essayent
Exemple: Recherche d’une expression régulière dans une chaîne cible est une mise en correspondance sur le chaîne de caractères cible entière.
Exemple: Recherche d’une expression régulière dans une chaîne cible
Cible regexp Résultat
Certains caractères spéciaux permettent de détecter des éléments particuliers d'un texte.
Remarque
Ils précisent les limites des occurrences correspondant à une expression régulière ou à
Les quantificateurs possessifs consomment toujours la chaîne de caractères cible entière, l'une de ses parties.
en essayant une seule fois une mise en correspondance. A la différence des
quantificateurs gloutons (greedy), ceux-ci ne reculent jamais, même si cela permettrait De cette manière, il est possible de délimiter une ligne (^Ligne...$)ou un mot (\bmot\b).
de réussir une recherche.
Exemple: Recherche d’une expression régulière dans une chaîne cible Caractère Signification
^ Un début de ligne.
Composantes d’une des expressions régulières: Composantes d’une des expressions régulières:
Caractère de début ou de terminaison Opérateurs logiques
Exemple:
Expression signification
Délimitation d'une entrée \A.*\Z Du sublime au ridicule il n'y a qu'un pas. X|Y X ou Y
(Napoléon 1er)
Groupe d'un caractère X. Sachant que ( ) représente délimiteurs de groupe (avec
(X)
Délimitation d'une entrée \b.*\b Du sublime au ridicule il n'y a qu'un pas. capture)
(Napoléon 1er)
Délimitation d'une entrée \bN\P{Lower}+\b Du sublime au ridicule il n'y a qu'un pas.
(Napoléon 1er)
Recherche du premier mot ^\w*\b Du sublime au ridicule il n'y a qu'un pas.
d'une ligne (Napoléon 1er)
Recherche d'une sous-chaîne \([\p{Lower}[0-9 ]]*\)$ Du sublime au ridicule il n'y a qu'un pas.
entre parenthèses et en fin de (Napoléon 1er)
ligne
Recherche d'une sous-chaîne ^<tr>.*</tr>$ <html>
entre parenthèses et en fin de <body>
ligne <table>
<tr><td>A</td></tr> <tr><td>B</td></tr>
<tr><td>C</td></tr> <tr><td>D</td></tr>
<tr><td>E</td></tr> <tr><td>F</td></tr>
M.AFILAL </table> 467 M.AFILAL 468
</body>
Composantes d’une des expressions régulières: Composantes d’une des expressions régulières:
Exemples Exemples
Expression régulière correspondant à une adresse IP
[0-9]{1,3}(?:.[0-9]{1,3}){3}
Exemple: 192.168.0.1
Si, on n’impose pas un nombre de chiffres compris entre un et trois Expression régulière correspondant à une date
\d+\.\d+\.\d+\.\d+ Une date au format 29 février 2012 suit le motif suivant : Un ou deux chiffres, un
Expression régulière correspondant à une adresse e-mail espace, un nombre indéfini de lettres, un espace puis quatre chiffres. L’expression
régulière associée est donc :
(\\w+)@(\\w+\\.)(\\w+)(\\.\\w+)*
[0-9]{1,2} [a-z]+ [0-9]{4}
Exemple: [email protected]
ou
Expression régulière correspondant à un numéro téléphonique
\d{1,2} \p{Lower}+ \d{4}
numéro de téléphone au format français: formé de 5 blocs de 2 chiffres avec n’importe
quel caractère entre chaque bloc
([0-9]{2}.){4}[0-9]{2}
Expression régulière correspondant à une URL
[a-z]{3,}://[a-z0-9-]+.[.a-z0-9-]+(?::[0-9]*)?
Exemple: http://5.freshminutes.it/index.php
Expression régulière correspondant à un nombre réel.
(\+|-)?([0-9]+\.?[0-9]*|\.[0-9]+)([eE](\+|-)?[0-9]+)?
Remarque
Le point s’écrit \. car « . » est un caractère qui signifie « un caractère quelconque ».
Le \ précédent le . sert à indiquer qu’il ne faut pas interpréter le point comme une
expression régulière mais comme le caractère point.
M.AFILAL 469 M.AFILAL 470
Idem pour \+
Les expressions régulières en java : la classe Pattern La classe Pattern: les méthodes compile( )
Description des méthodes de la classe Pattern
Méthode Description
La création d'un objet Pattern nécessite l'appel de l'une des méthodes statiques compile( ). La
static Pattern compile(String regex) crée un modèle à partir de l'expression régulière fournie. classe Pattern ne possède pas de constructeurs.
static Pattern compile(String regex, crée un modèle à partir de l'expression régulière et d'un indicateur passés
int flags) en argument. L'indicateur est une combinaison des options précitées Ces méthodes acceptent soit une expression régulière exprimée sous la forme d'une chaîne de
caractères, soit une expression régulière avec un paramètre optionnel flags ‘un drapeau’.
int flags() retourne l'indicateur pour le modèle courant.
Syntaxe :
Matcher matcher(CharSequence crée un objet Matcher qui appliquera le modèle courant sur la chaîne de static Pattern compile(String regex)
input) caractères passée en argument. static Pattern compile(String regex, int flags)
static boolean matches(String regex, compile une expression régulière à appliquer sur la chaîne de caractères
CharSequence input) fournie.
L'attribut flags précise les options à utiliser par la classe Pattern.
String pattern() retourne l'expression régulière du modèle courant. Les valeurs possibles sont :
String[] split(CharSequence input) découpe la chaîne de caractères spécifiée en fonction du modèle courant. UNIX_LINES, CASE_INSENSITIVE, COMMENTS, MULTILINE, DOTALL,
UNICODE_CASE et CANON_EQ
découpe la chaîne de caractères spécifiée en fonction du modèle courant.
La limite indique le nombre de fois que le modèle courant devra
s'appliquer à la chaîne de caractères. Lorsqu'un pattern doit être configuré de telle sorte à satisfaire à plusieurs options, le flags
String[] split(CharSequence input, n < 0 : n-1 applications du modèle. doit être une combinaison d'options, ceci grâce à l'opérateur OU binaire : |..
int limit) n = 0 : autant d'applications que possible, mais les sous-chaînes de
caractères vides sont supprimées.
n > 0 : autant d'applications que possible en conservant toutes les sous-
chaînes y-compris les vides.
M.AFILAL 475 M.AFILAL 476
La classe Pattern: les méthodes compile( ) La classe Pattern: les méthodes compile( )
Exemple Remarque
Si on veut ne pas tenir compte des majuscules On vu comment passer les options en paramètre à la méthode compile( ). Il est
également possible d'écrire ces options directement dans le motif de la regex. Elles
Pattern p = Pattern.compile("^[abc]$", Pattern.CASE_INSENSITIVE); doivent être placées en tout début.
La méthode matches( ) retourne vrai (true) si une chaîne de caractères cible contient une La méthode Matcher renvoie une instance de type Matcher associée au pattern courant afin de
occurrence correspondant à une expression régulière. rechercher l’expression régulière dans le texte cible (et éventuellement effectuer des
remplacements ou autres actions)
Syntaxe
static boolean matches(String regex, CharSequence input) Syntaxe
Matcher matcher(CharSequence input)
Exemple
Recherche de chaine commençant par le caractère U suivi par au moins un caractère de Exemple
mot suivi par la lettre Z à la fin de la chaine recherchée dans la chaine cible. Pattern patternCourant = Pattern.Compile("toto");
boolean b = Pattern.matches("\\bU\\w+a\\b", "UwghjanZ") Matcher recherche = patternCourant.matcher("TexteCible");
// lancement de la recherche de toutes les occurrences boolean trouve = recherche.find();
boolean b = Pattern.matches("(a((b)(c)))", "abc");
Remarque
La méthode matches ( ) permet de faire directement une recherche sans passer
explicitement par la classe Matcher
Elle fait la même chose que l’expression suivante:
Pattern.compile(exprReg).matcher(texte).matches( )