Anda di halaman 1dari 706

Cet ouvrage a bnci des relectures attentives des zCorrecteurs.

Sauf mention contraire, le contenu de cet ouvrage est publi sous la licence : Creative Commons BY-NC-SA 2.0 La copie de cet ouvrage est autorise sous rserve du respect des conditions de la licence Texte complet de la licence disponible sur : http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ Simple IT 2011 - ISBN : 978-2-9535278-3-4

Avant-propos

i vous lisez ces lignes, c'est que nous avons au moins deux choses en commun : l'informatique vous intresse et vous avez envie d'apprendre programmer. Enn, quand je dis en commun, je voulais dire en commun avec moi au moment o je voulais apprendre la programmation. Pour moi, tout a commenc sur un site maintenant trs connu : le Site du Zro. tant dbutant et cherchant tout prix des cours adapts mon niveau, je suis naturellement tomb amoureux de ce site qui propose des cours d'informatique accessibles au plus grand nombre. Vous l'aurez sans doute remarqu, trouver un cours d'informatique simple et clair (sur les rseaux, les machines, la programmation. . .) est habituellement un vrai parcours du combattant. Je ne me suis pas dcourag et je me suis professionnalis, via une formation diplmante, tout en suivant l'actualit de mon site prfr. . . Au sein de cette formation, j'ai pu voir divers aspects de mon futur mtier, notamment la programmation dans les langages PHP, C#, JavaScript et, bien sr, Java. Trs vite, j'ai aim travailler avec ce dernier, d'une part parce qu'il est agrable manipuler, souple utiliser en demandant toutefois de la rigueur (ce qui oblige structurer ses programmes), et d'autre part parce qu'il existe de nombreuses ressources disponibles sur Internet (mais pas toujours trs claires pour un dbutant). J'ai depuis obtenu mon diplme et trouv un emploi, mais je n'ai jamais oubli la dicult des premiers temps. Comme le Site du Zro permet d'crire des tutoriels et de les partager avec la communaut, j'ai dcid d'employer les connaissances acquises durant ma formation et dans mon travail rdiger un tutoriel permettant d'aborder mon langage de prdilection avec simplicit. J'ai donc pris mon courage deux mains et j'ai commenc crire. Beaucoup de lecteurs se sont rapidement montrs intresss, pour mon plus grand plaisir. De ce fait, mon tutoriel a t mis en avant sur le site et, aujourd'hui, il est adapt dans la collection  Livre du Zro . Je suis heureux du chemin parcouru, heureux d'avoir pu aider tant de dbutants et heureux de pouvoir vous aider votre tour !

CHAPITRE 0. AVANT-PROPOS

Et Java dans tout a ?


Java est un langage de programmation trs utilis, notamment par un grand nombre de dveloppeurs professionnels, ce qui en fait un langage incontournable actuellement. Voici les caractristiques de Java en quelques mots.  Java est un langage de programmation moderne dvelopp par Sun Microsystems, aujourd'hui rachet par Oracle. Il ne faut surtout pas le confondre avec JavaScript (langage de script utilis sur les sites Web), car ils n'ont rien voir.  Une de ses plus grandes forces est son excellente portabilit : une fois votre programme cr, il fonctionnera automatiquement sous Windows, Mac, Linux, etc.  On peut faire de nombreux types de programmes avec Java :  des applications, sous forme de fentre ou de console ;  des applets, qui sont des programmes Java incorpors des pages Web ;  des applications pour appareils mobiles, comme les smartphones, avec J2ME (Java 2 Micro Edition) ;  des sites web dynamiques, avec J2EE (Java 2 Enterprise Edition, maintenant JEE) ;  et bien d'autres : JMF (Java Media Framework), J3D pour la 3D. . . Comme vous le voyez, Java permet de raliser une trs grande quantit d'applications direntes ! Mais. . . comment apprendre un langage si vaste qui ore tant de possibilits ? Heureusement, ce livre est l pour tout vous apprendre sur Java partir de zro. Java est donc un langage de programmation, un langage dit compil : il faut comprendre par l que ce que vous allez crire n'est pas directement comprhensible et utilisable par votre ordinateur. Nous devrons donc passer par une tape de compilation (tape obscure o votre code source est entirement transform). En fait, on peut distinguer trois grandes phases dans la vie d'un code Java :  la phase d'criture du code source, en langage Java ;  la phase de compilation de votre code ;  la phase d'excution. Ces phases sont les mmes pour la plupart des langages compils (C, C++. . .). Par contre, ce qui fait la particularit de Java, c'est que le rsultat de la compilation n'est pas directement utilisable par votre ordinateur. Les langages mentionns ci-dessus permettent de faire des programmes directement comprhensibles par votre machine aprs compilation, mais avec Java, c'est lgrement dirent. En C++ par exemple, si vous voulez faire en sorte que votre programme soit exploitable sur une machine utilisant Windows et sur une machine utilisant Linux, vous allez devoir prendre en compte les spcicits de ces deux systmes d'exploitation dans votre code source et compiler une version spciale pour chacun d'eux. Avec Java, c'est un programme appel la machine virtuelle qui va se charger de retranscrire le rsultat de la compilation en langage machine, interprtable par celle-ci. Vous n'avez pas vous proccuper des spcicits de la machine qui va excuter votre programme : la machine virtuelle Java s'en charge pour vous ! ii

QU'ALLEZ-VOUS APPRENDRE EN LISANT CE LIVRE ?

Qu'allez-vous apprendre en lisant ce livre ?


Ce livre a t conu en partant du principe que vous ne connaissez rien la programmation. Voil le plan en quatre parties que nous allons suivre tout au long de cet ouvrage. 1. Les bases de Java : nous verrons ici ce qu'est Java et comment il fonctionne. Nous crerons notre premier programme, en utilisant des variables, des oprateurs, des conditions, des boucles. . . Nous apprendrons les bases du langage, qui vous seront ncessaires par la suite. 2. Java et la Programmation Oriente Objet : aprs avoir dompt les bases du langage, vous allez devoir apprivoiser une notion capitale : l'objet. Vous apprendrez encapsuler vos morceaux de code an de les rendre modulables et rutilisables, mais il y aura du travail fournir. 3. Les interfaces graphiques : l, nous verrons comment crer des interfaces graphiques et comment les rendre interactives. C'est vrai que jusqu' prsent, nous avons travaill en mode console. Il faudra vous accrocher un peu car il y a beaucoup de composants utilisables, mais le jeu en vaut la chandelle ! Nous passerons en revue dirents composants graphiques tels que les champs de texte, les cases cocher, les tableaux, les arbres ainsi que quelques notions spciques comme le drag'n drop. 4. Interactions avec les bases de donnes : de nos jours, avec la course aux donnes, beaucoup de programmes doivent interagir avec ce qu'on appelle des bases de donnes. Dans cette partie, nous verrons comment s'y connecter, comment rcuprer des informations et comment les exploiter.

Comment lire ce livre ?


Suivez l'ordre des chapitres
Lisez ce livre comme on lit un roman. Il a t conu de cette faon. Contrairement beaucoup de livres techniques o il est courant de lire en diagonale et de sauter certains chapitres, ici il est trs fortement recommand de suivre l'ordre du cours, moins que vous ne soyez dj un peu expriments.

Pratiquez en mme temps


Pratiquez rgulirement. N'attendez pas d'avoir ni la lecture de ce livre pour allumer votre ordinateur et faire vos propres essais. iii

CHAPITRE 0. AVANT-PROPOS

Utilisez les codes web !


An de tirer parti du Site du Zro dont est issu ce livre, celui-ci vous propose ce qu'on appelle des  codes web . Ce sont des codes six chires entrer sur une page du Site du Zro pour tre automatiquement redirig vers un site web sans avoir en recopier l'adresse. Pour utiliser les codes web, rendez-vous sur la page suivante 1 :
http://www.siteduzero.com/codeweb.html

Un formulaire vous invite rentrer votre code web. Faites un premier essai avec le code ci-dessous :  Tester le code web Code web : 123456  Ces codes web ont deux intrts :  vous faire tlcharger les codes source inclus dans ce livre, ce qui vous vitera d'avoir recopier certains codes un peu longs ;  vous rediriger vers les sites web prsents tout au long du cours. Ce systme de redirection nous permet de tenir jour le livre que vous avez entre les mains sans que vous ayez besoin d'acheter systmatiquement chaque nouvelle dition. Si un site web change d'adresse, nous modierons la redirection mais le code web utiliser restera le mme. Si un site web disparat, nous vous redirigerons vers une page du Site du Zro expliquant ce qui s'est pass et vous proposant une alternative. En clair, c'est un moyen de nous assurer de la prennit de cet ouvrage sans que vous ayez faire quoi que ce soit !

Ce livre est issu du Site du Zro


Cet ouvrage reprend le cours Java prsent sur le Site du Zro dans une dition revue et corrige, avec de nombreuses mises jour. Il reprend les lments qui ont fait le succs des cours du site, c'est--dire leur approche progressive et pdagogique, le ton dcontract et lger, ainsi que les TP vous permettant de rellement pratiquer de faon autonome. Ce livre s'adresse donc toute personne dsireuse d'apprendre les bases de la programmation en Java, que ce soit :  par curiosit ;  par intrt personnel ;  par besoin professionnel.
1. Vous pouvez aussi utiliser le formulaire de recherche du Site du Zro, section  Code Web .

iv

REMERCIEMENTS

Remerciements
Comme pour la plupart des ouvrages, beaucoup de personnes ont particip de prs ou de loin l'laboration de ce livre et j'en prote donc pour les en remercier.  Ma compagne, Manuela, qui me supporte et qui tolre mes heures passes crire les tutoriels pour le Site du Zro. Un merci spcial toi qui me prends dans tes bras lorsque a ne va pas, qui m'embrasses lorsque je suis triste, qui me souris lorsque je te regarde, qui me donnes tant d'amour lorsque le temps est maussade : pour tout a et plus encore, je t'aime ;  Agns HAASSER (Ttie), Damien SMEETS (Karl Yeurl), Mickal SALAMIN (micky), Franois GLORIEUX (Nox), Christophe TAFANI-DEREEPER, Romain CAMPILLO (Le Chapelier Toqu), Charles DUPR (Barbatos), Maxence CORDIEZ (Ziame), Philippe LUTUN (ptipilou), zCorrecteurs m'ayant accompagn dans la correction de cet ouvrage ;  Mathieu NEBRA (alias M@teo21), pre fondateur du Site du Zro, qui m'a fait conance, soutenu dans mes dmarches et qui m'a donn de prcieux conseils ;  Tous les Zros qui m'ont apport leur soutien et leurs remarques ;  Toutes les personnes qui m'ont contact pour me faire des suggestions et m'apporter leur expertise. Merci aussi toutes celles et ceux qui m'ont apport leur soutien et qui me permettent d'apprendre toujours plus au quotidien, mes collgues de travail :  Thomas, qui a toujours des questions sur des sujets totalement dlirants ;  Angelo, mon chef ador, qui est un puits de science en informatique ;  Olivier, la force zen, qui n'a pas son pareil pour aller droit au but ;  Dylan, discret mais d'une comptence plus que certaine dans des domaines aussi divers que varis ;  Jrme, que j'ai martyris mais qui, j'en suis persuad, a ador. . . :-)

CHAPITRE 0. AVANT-PROPOS

vi

Sommaire

Avant-propos
Et Java dans tout a ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Qu'allez-vous apprendre en lisant ce livre ? . . . . . . . . . . . . . . . . . . . Comment lire ce livre ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ce livre est issu du Site du Zro . . . . . . . . . . . . . . . . . . . . . . . . . Remerciements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

i
ii iii iii iv v

I Les bases de Java


1 Installer les outils de dveloppement
Installer les outils ncessaires . . . . . . . . . . . . . . . . . . . . . . . . . . .

1
3
4

Votre premier programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2 Les variables et les oprateurs

23

Les dirents types de variables . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Les oprateurs arithmtiques . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Les conversions, ou  cast  . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

3 Lire les entres clavier

33

La classe Scanner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Rcuprer ce que vous tapez . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

4 Les conditions
vii

39

SOMMAIRE La structure if... else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 La structure switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 La condition ternaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

5 Les boucles

47

La boucle while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 La boucle do... while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 La boucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

6 TP : conversion Celsius - Fahrenheit

55

laboration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

7 Les tableaux

61

Tableau une dimension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 Les tableaux multidimensionnels . . . . . . . . . . . . . . . . . . . . . . . . . 62 Utiliser et rechercher dans un tableau . . . . . . . . . . . . . . . . . . . . . . 63

8 Les mthodes de classe

69

Quelques mthodes utiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Crer sa propre mthode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 La surcharge de mthode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

II Java et la Programmation Oriente Objet


9 Votre premire classe

79
81

Structure de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 Les constructeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Accesseurs et mutateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Les variables de classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Le principe d'encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

10 L'hritage

99

Le principe de l'hritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 Le polymorphisme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 viii

SOMMAIRE

11 Modliser ses objets grce UML

111

Prsentation d'UML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 Modliser ses objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Modliser les liens entre les objets . . . . . . . . . . . . . . . . . . . . . . . . 114

12 Les packages

119

Cration d'un package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Droits d'accs entre les packages . . . . . . . . . . . . . . . . . . . . . . . . . 121

13 Les classes abstraites et les interfaces

123

Les classes abstraites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Les interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 Le pattern strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

14 Les exceptions

157

Le bloc try{...} catch{...} . . . . . . . . . . . . . . . . . . . . . . . . . . 158 Les exceptions personnalises . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 La gestion de plusieurs exceptions . . . . . . . . . . . . . . . . . . . . . . . . 164

15 Les ux d'entre/sortie

167

Utilisation de java.io . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 Utilisation de java.nio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Le pattern decorator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190

16 Les numrations

197

Avant les numrations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 Une solution : les enum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199

17 Les collections d'objets


Les Les Les Les dirents types objets List . . objets Map . . objets Set . . de collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

203
204 205 208 209

18 La gnricit en Java

213

Principe de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 Gnricit et collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 ix

SOMMAIRE

19 Java et la rexivit

227

L'objet Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 Instanciation dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232

III Les interfaces graphiques


20 Notre premire fentre

237
239

L'objet JFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 L'objet JPanel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 Les objets Graphics et Graphics2D . . . . . . . . . . . . . . . . . . . . . . . 246

21 Le l rouge : une animation

259

Cration de l'animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Amliorations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263

22 Positionner des boutons

269

Utiliser la classe JButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 Positionner son composant : les layout managers . . . . . . . . . . . . . . . . 272

23 Interagir avec des boutons


Une classe Bouton personnalise . . . . . . . . . . . . . . Interagir avec son bouton . . . . . . . . . . . . . . . . . . tre l'coute de ses objets : le design pattern Observer Cadeau : un bouton personnalis optimis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

289
290 298 318 327

24 TP : une calculatrice
laboration . . . . . . . . . Conception . . . . . . . . . Correction . . . . . . . . . . Gnrer un .jar excutable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

331
332 332 333 338

25 Excuter des tches simultanment


Une classe hrite de Thread Utiliser l'interface Runnable . Synchroniser ses threads . . . Contrler son animation . . . x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

345
346 350 354 355

SOMMAIRE

26 Les champs de formulaire


Les listes : l'objet JComboBox . . . . . . . . . Les cases cocher : l'objet JCheckBox . . . . Les champs de texte : l'objet JTextField . . Contrle du clavier : l'interface KeyListener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

359
360 370 381 385

27 Les menus et botes de dialogue

391

Les botes de dialogue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 Les menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408

28 TP : l'ardoise magique
Cahier des charges . . . Prrequis . . . . . . . . Correction . . . . . . . . Amliorations possibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

439
440 441 442 448

29 Conteneurs, sliders et barres de progression

449

Autres conteneurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 Enjoliver vos IHM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467

30 Les arbres et leur structure


La composition des arbres . . . . Des arbres qui vous parlent . . . Dcorez vos arbres . . . . . . . . Modier le contenu de nos arbres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

471
472 476 481 486

31 Les interfaces de tableaux


Premiers pas . . . . . . . . . . . Gestion de l'achage . . . . . . . Interaction avec l'objet JTable . Ajouter des lignes et des colonnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

495
496 497 508 515

32 TP : le pendu

519

Cahier des charges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 Prrequis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 xi

SOMMAIRE

33 Mieux structurer son code : le pattern MVC

525

Premiers pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526 Le modle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 Le contrleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 La vue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534

34 Le Drag'n Drop

539

Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 Fonctionnement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 Crer son propre TransferHandler . . . . . . . . . . . . . . . . . . . . . . . . 547 Activer le drop sur un JTree . . . . . . . . . . . . . . . . . . . . . . . . . . . 553 Eet de dplacement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558

35 Mieux grer les interactions avec les composants

565

Prsentation des protagonistes . . . . . . . . . . . . . . . . . . . . . . . . . . 566 Utiliser l'EDT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567 La classe SwingWorker<T, V> . . . . . . . . . . . . . . . . . . . . . . . . . . . 570

IV Interactions avec les bases de donnes


36 JDBC : la porte d'accs aux bases de donnes

577
579

Rappels sur les bases de donnes . . . . . . . . . . . . . . . . . . . . . . . . . 580 Prparer la base de donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 Se connecter la base de donnes . . . . . . . . . . . . . . . . . . . . . . . . . 591

37 Fouiller dans sa base de donnes

597

Le couple Statement  ResultSet . . . . . . . . . . . . . . . . . . . . . . . . 598 Les requtes prpares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 Modier des donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613
Statement, toujours plus fort . . . . . . . . . . . . . . . . . . . . . . . . . . . 615

Grer les transactions manuellement . . . . . . . . . . . . . . . . . . . . . . . 617

38 Limiter le nombre de connexions

621

Pourquoi ne se connecter qu'une seule fois ? . . . . . . . . . . . . . . . . . . . 622 Le pattern singleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 622 xii

SOMMAIRE Le singleton dans tous ses tats . . . . . . . . . . . . . . . . . . . . . . . . . . 625

39 TP : un testeur de requtes

629

Cahier des charges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630 Quelques captures d'cran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630 Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630

40 Lier ses tables avec des objets Java : le pattern DAO

633

Avant toute chose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634 Le pattern DAO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639 Le pattern factory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649

xiii

SOMMAIRE

xiv

Premire partie
Les bases de Java

Chapitre

1
Dicult :

Installer les outils de dveloppement

'un des principes phares de Java rside dans sa machine virtuelle : celle-ci assure tous les dveloppeurs Java qu'un programme sera utilisable avec tous les systmes d'exploitation sur lesquels est installe une machine virtuelle Java. Lors de la phase de compilation de notre code source, celui-ci prend une forme intermdiaire appele byte code : c'est le fameux code inintelligible pour votre machine, mais interprtable par la machine virtuelle Java. Cette dernire porte un nom : on parle plus communment de JRE (Java Runtime Environment). Plus besoin de se soucier des spcicits lies tel ou tel OS (Operating System, soit systme d'exploitation). Nous pourrons donc nous consacrer entirement notre programme. An de nous simplier la vie, nous allons utiliser un outil de dveloppement, ou IDE (Integrated Development Environment), pour nous aider crire nos futurs codes source. . . Nous allons donc avoir besoin de direntes choses an de pouvoir crer des programmes Java : la premire est ce fameux JRE !

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT

Installer les outils ncessaires


JRE ou JDK
Tlchargez votre environnement Java sur le site d'Oracle.


Tlcharger JRE Code web : 924260 

Choisissez la dernire version stable (gure 1.1).

Figure

1.1  Encart de tlchargement

Vous avez sans doute remarqu qu'on vous propose de tlcharger soit le JRE, soit le JDK 1 . La dirence entre ces deux environnements est crite, mais pour les personnes fches avec l'anglais, sachez que le JRE contient tout le ncessaire pour faire en sorte que vos programmes Java puissent tre excuts sur votre ordinateur ; le JDK, en plus de contenir le JRE, contient tout le ncessaire pour dvelopper, compiler. . . L'IDE contenant dj tout le ncessaire pour le dveloppement et la compilation, nous n'avons besoin que du JRE. Une fois que vous avez cliqu sur  Download JRE , vous arrivez sur la page correspondante (gure 1.2). Slectionnez votre systme d'exploitation et cochez la case :  I agree to the Java SE Development Kit 6 License Agreement . Lorsque vous serez l'cran correspondant (gure 1.3), slectionnez celui de votre choix puis validez. Je vous ai dit que Java permet de dvelopper dirents types d'applications : il y a donc des environnements permettant de crer des programmes pour direntes platesformes.  J2SE 2 : permet de dvelopper des applications dites  client lourd , par exemple
1. Java Development Kit. 2. Java 2 Standard Edition, celui qui nous intresse dans cet ouvrage.

INSTALLER LES OUTILS NCESSAIRES

Figure

1.2  Page de choix de votre systme d'exploitation

Figure

1.3  Choix de l'excutable

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT Word, Excel, la suite OpenOce.org. . . Toutes ces applications sont des  clients lourds . C'est ce que nous allons faire dans ce livre.  J2EE 3 : permet de dvelopper des applications web en Java. On parle aussi de clients lgers.  J2ME 4 : permet de dvelopper des applications pour appareils portables, comme des tlphones portables, des PDA. . .

Eclipse IDE
Avant toute chose, quelques mots sur le projet Eclipse. Eclipse IDE est un environnement de dveloppement libre permettant de crer des programmes dans de nombreux langages de programmation (Java, C++, PHP. . .). C'est en somme l'outil que nous allons utiliser pour programmer.

Eclipse IDE est lui-mme principalement crit en Java.


Je vous invite donc tlcharger Eclipse IDE. Tlcharger Eclipse Code web : 395144  Accdez la page de tlchargement puis choisissez  Eclipse IDE for Java Developers , en choisissant la version d'Eclipse correspondant votre OS 5 (gure 1.4).


Figure

1.4  Version d'Eclipse IDE

Slectionnez maintenant le miroir que vous souhaitez utiliser pour obtenir Eclipse. Voil, vous n'avez plus qu' attendre la n du tlchargement. Pour ceux qui l'avaient devin, Eclipse est le petit logiciel qui va nous permettre de dvelopper nos applications ou nos applets, et aussi celui qui va compiler tout a. Notre logiciel va donc permettre de traduire nos futurs programmes Java en langage byte code, comprhensible uniquement par votre JRE, frachement install. La spcicit d'Eclipse IDE vient du fait que son architecture est totalement dveloppe autour de la notion de plug-in. Cela signie que toutes ses fonctionnalits sont dveloppes en tant que plug-ins. Pour faire court, si vous voulez ajouter des fonctionnalits Eclipse, vous devez :
3. Java 2 Enterprise Edition. 4. Java 2 Micro Edition. 5. Operating System = systme d'exploitation.

INSTALLER LES OUTILS NCESSAIRES  tlcharger le plug-in correspondant ;  copier les chiers spcis dans les rpertoires spcis ;  dmarrer Eclipse, et a y est !

Lorsque vous tlchargez un nouveau plug-in pour Eclipse, celui-ci se prsente souvent comme un dossier contenant gnralement deux sous-dossiers : un dossier  plugins  et un dossier  features . Ces dossiers existent aussi dans le rpertoire d'Eclipse. Il vous faut donc copier le contenu des dossiers de votre plug-in vers le dossier correspondant dans Eclipse ( plugins dans plugins, et features dans features).
Vous devez maintenant avoir une archive contenant Eclipse. Dcompressez-la o vous voulez, puis entrez dans ce dossier (gure 1.5). Cela fait, lancez Eclipse.

Figure

1.5  Contenu du dossier Eclipse

Ici (gure 1.6), Eclipse vous demande dans quel dossier vous souhaitez enregistrer vos projets ; sachez que rien ne vous empche de spcier un autre dossier que celui propos par dfaut.

Figure

1.6  Premire fentre Eclipse 7

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT Une fois cette tape eectue, vous arrivez sur la page d'accueil d'Eclipse. Si vous avez envie d'y jeter un il, allez-y.

Prsentation rapide de l'interface


Je vais maintenant vous faire faire un tour rapide de l'interface d'Eclipse.

Le menu  File  (gure 1.7)

Figure

1.7  Menu  File 

C'est ici que nous pourrons crer de nouveaux projets Java, les enregistrer et les exporter le cas chant. Les raccourcis retenir sont :  ALT + SHIFT + N : nouveau projet ;  CTRL + S : enregistrer le chier o l'on est positionn ;  CTRL + SHIFT + S : tout sauvegarder ;  CTRL + W : fermer le chier o l'on est positionn ;  CTRL + SHIFT + W : fermer tous les chiers ouverts. 8

INSTALLER LES OUTILS NCESSAIRES

Figure

1.8  Menu  Edit 

Le menu  Edit  (gure 1.8)


Dans ce menu, nous pourrons utiliser les commandes  copier ,  coller , etc. Ici, les raccourcis retenir sont :  CTRL + C : copier la slection ;  CTRL + X : couper la slection ;  CTRL + V : coller la slection ;  CTRL + A : tout slectionner ;  CTRL + F : chercher-remplacer.

Le menu  Window  (gure 1.9)

Figure

1.9  Menu  Window  9

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT Dans celui-ci, nous pourrons congurer Eclipse selon nos besoins.

La barre d'outils (gure 1.10)

Figure

1.10  Barre d'outils

Nous avons dans l'ordre : 1. 2. 3. 4. 5. 6. nouveau gnral. Cliquer sur ce bouton revient faire  Fichier / Nouveau  ; enregistrer. Revient faire CTRL + S ; imprimer ; excuter la classe ou le projet spci. Nous verrons ceci plus en dtail ; crer un nouveau projet. Revient faire  Fichier / Nouveau / Java Project  ; crer une nouvelle classe, c'est--dire en fait un nouveau chier. Revient faire  Fichier / Nouveau / Classe .

Maintenant, je vais vous demander de crer un nouveau projet Java (gures 1.11 et 1.12).

Figure

1.11  Cration de projet Java - tape 1

Renseignez le nom de votre projet comme je l'ai fait (encadr 1). Vous pouvez aussi voir o sera enregistr ce projet (encadr 2). Un peu plus compliqu, maintenant : vous avez donc un environnement Java sur votre machine, mais dans le cas o vous en auriez plusieurs, vous pouvez aussi spcier Eclipse quel JRE 6 utiliser pour ce projet. Vous devriez avoir un nouveau projet dans la fentre de gauche (gure 1.13).
6. Vous pourrez changer ceci tout moment dans Eclipse en allant dans  Window / Preferences , en dpliant l'arbre  Java  dans la fentre et en choisissant  Installed JRE .

10

INSTALLER LES OUTILS NCESSAIRES

Figure

1.12  Cration de projet Java - tape 2

Figure

1.13  Explorateur de projet 11

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT Pour boucler la boucle, ajoutons ds maintenant une nouvelle classe dans ce projet comme nous avons appris le faire plus tt. Voici la fentre sur laquelle vous devriez tomber : gure 1.14.

Une classe est un ensemble de codes contenant plusieurs instructions que doit eectuer votre programme. Ne vous attardez pas trop sur ce terme, nous aurons l'occasion d'y revenir.

Figure

1.14  Cration d'une classe

Dans l'encadr 1, nous pouvons voir o seront enregistrs nos chiers Java. Dans l'encadr 2, nommez votre classe Java ; moi, j'ai choisi sdz1. Dans l'encadr 3, Eclipse vous demande si cette classe a quelque chose de particulier. Eh bien oui ! Cochez  public static void main(String[] args) 7 , puis cliquez sur  Finish . Avant de commencer coder, nous allons explorer l'espace de travail (gure 1.15). Dans l'encadr de gauche, vous trouverez le dossier de votre projet ainsi que son contenu. Ici, vous pourrez grer votre projet comme bon vous semble (ajout, suppression. . .). Dans l'encadr positionn au centre, je pense que vous avez devin : c'est ici que nous
7. Nous reviendrons plus tard sur ce point.

12

INSTALLER LES OUTILS NCESSAIRES

Figure

1.15  Fentre principale

13

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT allons crire nos codes source. Dans l'encadr du bas, c'est l que vous verrez apparatre le contenu de vos programmes. . . ainsi que les erreurs ventuelles ! Et pour nir, c'est dans l'encadr de droite, ds que nous aurons appris coder nos propres fonctions et nos objets, que la liste des mthodes et des variables sera ache.

Votre premier programme


Comme je vous l'ai maintes fois rpt, les programmes Java sont, avant d'tre utiliss par la machine virtuelle, prcompils en byte code (par votre IDE ou la main). Ce byte code n'est comprhensible que par une JVM, et c'est celle-ci qui va faire le lien entre ce code et votre machine. Vous aviez srement remarqu que sur la page de tlchargement du JRE, plusieurs liens taient disponibles :  un lien pour Windows ;  un lien pour Mac ;  un lien pour Linux. Ceci, car la machine virtuelle Java se prsente diremment selon qu'on se trouve sous Mac, sous Linux ou encore sous Windows. Par contre, le byte code, lui, reste le mme quel que soit l'environnement avec lequel a t dvelopp et prcompil votre programme Java.

Consquence directe : quel que soit l'OS sous lequel a t cod un programme Java, n'importe quelle machine pourra l'excuter si elle dispose d'une JVM ! Tu n'arrtes pas de nous rabcher byte code par-ci, byte code par-l. . . Mais c'est quoi, au juste ?
Eh bien, un byte code 8 n'est rien d'autre qu'un code intermdiaire entre votre code Java et le code machine. Ce code particulier se trouve dans les chiers prcompils de vos programmes ; en Java, un chier source a pour extension .java et un chier prcompil a l'extension .class : c'est dans ce dernier que vous trouverez du byte code. Je vous invite examiner un chier .class la n de cette partie (vous en aurez au moins un), mais je vous prviens, c'est illisible ! Par contre, vos chiers .java sont de simples chiers texte dont l'extension a t change. Vous pouvez donc les ouvrir, les crer ou encore les mettre jour avec le Bloc-notes de Windows, par exemple. Cela implique que, si vous le souhaitez, vous pouvez crire des programmes Java avec le Bloc-notes ou encore avec Notepad++.
8. Il existe plusieurs types de byte code, mais nous parlons ici de celui cr par Java.

14

VOTRE PREMIER PROGRAMME Reprenons. Vous devez savoir que tous les programmes Java sont composs d'au moins une classe. Cette classe doit contenir une mthode appele main : ce sera le point de dmarrage de notre programme. Une mthode est une suite d'instructions excuter. C'est un morceau de logique de notre programme. Une mthode contient :  un en-tte : celui-ci va tre en quelque sorte la carte d'identit de la mthode ;  un corps : le contenu de la mthode, dlimit par des accolades ;  une valeur de retour : le rsultat que la mthode va retourner.

Vous verrez un peu plus tard qu'un programme n'est qu'une multitude de classes qui s'utilisent l'une l'autre. Mais pour le moment, nous n'allons travailler qu'avec une seule classe.
Je vous avais demand de crer un projet Java ; ouvrez-le (gure 1.16).

Figure

1.16  Mthode principale

Vous voyez la fameuse classe dont je vous parlais ? Ici, elle s'appelle  sdz1 . Vous pouvez voir que le mot class est prcd du mot public, dont nous verrons la signication lorsque nous programmerons des objets. Pour le moment, ce que vous devez retenir, c'est que votre classe est dnie par un mot cl (class), qu'elle a un nom (ici, sdz1) et que son contenu est dlimit par des accolades ({}). Nous crirons nos codes sources entre la mthode main. La syntaxe de cette mthode est toujours la mme :
puli stti void min@tring rgsA{ GGgontenu de votre lsse }

Ce sera entre les accolades de la mthode main que nous crirons nos codes source.
15

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT

Excuse-nous, mais. . . pourquoi as-tu crit  //Contenu de votre classe  et pas  Contenu de votre classe  ?
Bonne question ! Je vous ai dit plus haut que votre programme Java, avant de pouvoir tre excut, doit tre prcompil en byte code. Eh bien, la possibilit de forcer le compilateur ignorer certaines instructions existe ! C'est ce qu'on appelle des commentaires, et deux syntaxes sont disponibles pour commenter son texte.  Il y a les commentaires unilignes : introduits par les symboles //, ils mettent tout ce qui les suit en commentaire, du moment que le texte se trouve sur la mme ligne que les //.
puli stti void min@tring rgsA{ GGn ommentire GGn utre GGinore un utre gei n9est ps un ommentire 3 }

 Il y a les commentaires multilignes : ils sont introduits par les symboles /* et se terminent par les symboles */.
puli stti void min@tring rgsA{ GB n ommentire n utre inore un utre BG gei n9est ps un ommentire 3 }

D'accord, mais a sert quoi ?


C'est simple : au dbut, vous ne ferez que de trs petits programmes. Mais ds que vous aurez pris de la bouteille, leurs tailles et le nombre de classes qui les composeront vont augmenter. Vous serez contents de trouver quelques lignes de commentaires au dbut de votre classe pour vous dire quoi elle sert, ou encore des commentaires dans une mthode qui eectue des choses compliques an de savoir o vous en tes dans vos traitements. . . Il existe en fait une troisime syntaxe, mais elle a une utilit particulire. Elle permettra de gnrer une documentation pour votre programme : une Javadoc (Java Documenta16

VOTRE PREMIER PROGRAMME tion). Je n'en parlerai que trs peu, et pas dans ce chapitre. Nous verrons cela lorsque nous programmerons des objets, mais pour les curieux, je vous conseille le trs bon cours de dworkin sur ce sujet disponible sur le Site du Zro. Prsentation de la Javadoc Code web : 478278 


partir de maintenant et jusqu' ce que nous programmions des interfaces graphiques, nous allons faire ce qu'on appelle des programmes procduraux. Cela signie que le programme s'excutera de faon procdurale, c'est--dire qui s'eectue de haut en bas, une ligne aprs l'autre. Bien sr, il y a des instructions qui permettent de rpter des morceaux de code, mais le programme en lui-mme se terminera une fois parvenu la n du code. Cela vient en opposition la programmation vnementielle (ou graphique) qui, elle, est base sur des vnements (clic de souris, choix dans un menu. . .).

Hello World
Maintenant, essayons de taper le code suivant :
puli stti void min@tring rgsA{ ystemFoutFprint@4rello orld 34AY }

en Java sont suivies d'un point-virgule.

N'oubliez surtout pas le " ; " la n de la ligne ! Toutes les instructions

Une fois que vous avez saisi cette ligne de code dans votre mthode main, il vous faut lancer le programme. Si vous vous souvenez bien de la prsentation faite prcdemment, vous devez cliquer sur la che blanche dans un rond vert (gure 1.17).

Figure

1.17  Bouton de lancement du programme

Si vous regardez dans votre console, dans la fentre du bas sous Eclipse, vous devriez voir la gure 1.18. Expliquons un peu cette ligne de code. Littralement, elle signie  la mthode print() va crire Hello World ! en utilisant l'objet out de la classe System .  System : ceci correspond l'appel d'une classe qui se nomme  System . C'est une classe utilitaire qui permet surtout d'utiliser l'entre et la sortie standard, c'est--dire la saisie clavier et l'achage l'cran.  out : objet de la classe System qui gre la sortie standard. 17

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT

Figure

1.18  Console d'Eclipse

 print : mthode qui crit dans la console le texte pass en paramtre. Si vous mettez plusieurs System.out.print, voici ce qui se passe. Prenons ce code :
ystemFoutFprint@4rello orld 34AY ystemFoutFprint@4wy nme is4AY ystemFoutFprint@4gysoy4AY

Lorsque vous l'excutez, vous devriez voir des chanes de caractres qui se suivent sans saut de ligne. Autrement dit, ceci s'achera dans votre console :
Hello World !My name isCysboy

Je me doute que vous souhaiteriez insrer un retour la ligne pour que votre texte soit plus lisible. . . Pour cela, vous avez plusieurs solutions :  soit vous utilisez un caractre d'chappement, ici \n ;  soit vous utilisez la mthode println() la place de la mthode print(). Donc, si nous reprenons notre code prcdent et que nous appliquons cela, voici ce que a donnerait :
ystemFoutFprint@4rello orld 3 n4AY ystemFoutFprintln@4wy nme is4AY ystemFoutFprintln@4ngysoy4AY

Le rsultat :
Hello World ! My name is Cysboy

Vous pouvez voir que :  lorsque vous utilisez le caractre d'chappement \n, quelle que soit la mthode appele, celle-ci ajoute immdiatement un retour la ligne son emplacement ;  lorsque vous utilisez la mthode println(), celle-ci ajoute automatiquement un retour la ligne la n de la chane passe en paramtre ;  un caractre d'chappement peut tre mis dans la mthode println(). J'en prote au passage pour vous mentionner deux autres caractres d'chappement : 18

VOTRE PREMIER PROGRAMME  \r va insrer un retour chariot, parfois utilis aussi pour les retours la ligne ;  \t va faire une tabulation.

Vous avez srement remarqu que la chane de caractres que l'on ache est entoure de "<chane>". En Java, les guillemets doubles 9 sont des dlimiteurs de chanes de caractres ! Si vous voulez acher un guillemet double dans la sortie standard, vous devrez  l'chapper 10  avec un \, ce qui donnerait : System.out.println("Coucou mon \"chou\" ! "); .
Je vous propose maintenant de passer un peu de temps sur la compilation de vos programmes en ligne de commande. Cette section n'est pas obligatoire, loin de l, mais elle ne peut tre qu'enrichissante.

Compilation en ligne de commande (Windows)


Bienvenue donc aux plus curieux ! Avant de vous apprendre compiler et excuter un programme en ligne de commande, il va vous falloir le JDK ( Java SE Development Kit). C'est avec celui-ci que nous aurons de quoi compiler nos programmes. Le ncessaire l'excution des programmes est dans le JRE. . . mais il est galement inclus dans le JDK. Je vous invite donc retourner sur le site d'Oracle et tlcharger ce dernier. Une fois cette opration eectue, il est conseill de mettre jour votre variable d'environnement %PATH%.

Euh. . . quoi ?
Votre variable d'environnement . C'est grce elle que Windows trouve des excutables sans qu'il soit ncessaire de lui spcier le chemin d'accs complet. Vous  enn, Windows  en a plusieurs, mais nous ne nous intresserons qu' une seule. En gros, cette variable contient le chemin d'accs certains programmes. Par exemple, si vous spciez le chemin d'accs un programme X dans votre variable d'environnement et que, par un malheureux hasard, vous n'avez plus aucun raccourci vers X : vous l'avez dnitivement perdu dans les mandres de votre PC. Eh bien vous pourrez le lancer en faisant  Dmarrer Excuter  et en tapant la commande  X.exe  (en partant du principe que le nom de l'excutable est X.exe).

D'accord, mais comment fait-on ? Et pourquoi doit-on faire a pour le JDK ?


9. Il n'est pas rare de croiser le terme anglais quote pour dsigner les guillemets droits. Cela fait en quelque sorte partie du jargon du programmeur. 10. Terme dsignant le fait de dsactiver : ici, dsactiver la fonction du caractre  " .

19

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT J'y arrive. Une fois votre JDK install, ouvrez le rpertoire bin de celui-ci, ainsi que celui de votre JRE. Nous allons nous attarder sur deux chiers. Dans le rpertoire bin de votre JRE, vous devez avoir un chier nomm java.exe. Fichier que vous retrouvez aussi dans le rpertoire bin de votre JDK. C'est grce ce chier que votre ordinateur peut lancer vos programmes par le biais de la JVM. Le deuxime ne se trouve que dans le rpertoire bin de votre JDK, il s'agit de javac.exe 11 . C'est celui-ci qui va prcompiler vos programmes Java en byte code. Alors, pourquoi mettre jour la variable d'environnement pour le JDK ? Eh bien, compiler et excuter en ligne de commande revient utiliser ces deux chiers en leur prcisant o se trouvent les chiers traiter. Cela veut dire que si l'on ne met pas jour la variable d'environnement de Windows, il nous faudrait :  ouvrir l'invite de commande ;  se positionner dans le rpertoire bin de notre JDK ;  appeler la commande souhaite ;  prciser le chemin du chier .java ;  renseigner le nom du chier. Avec notre variable d'environnement mise jour, nous n'aurons plus qu' :  nous positionner dans le dossier de notre programme ;  appeler la commande ;  renseigner le nom du chier Java. Allez dans le  Panneau de configuration  de votre PC ; de l, cliquez sur l'icne  Systme  ; choisissez l'onglet  Avanc  et vous devriez voir en bas un bouton nomm  Variables d'environnement  : cliquez dessus. Une nouvelle fentre s'ouvre. Dans la partie infrieure intitule  Variables systme , cherchez la variable Path. Une fois slectionne, cliquez sur  Modifier . Encore une fois, une fentre, plus petite celle-ci, s'ouvre devant vous. Elle contient le nom de la variable et sa valeur.

Ne changez pas son nom et n'eacez pas son contenu ! Nous allons juste ajouter un chemin d'accs.
Pour ce faire, allez jusqu'au bout de la valeur de la variable, ajoutez-y un point-virgule ( ;) s'il n'y en a pas, et ajoutez alors le chemin d'accs au rpertoire bin de votre JDK, en terminant celui-ci par un point-virgule ! Chez moi, a donne ceci :  C:\Sun\SDK\jdk\bin . Auparavant, ma variable d'environnement contenait, avant mon ajout :
7ystemoot7systemQPY7ystemoot7Y7ystemoot7ystemQPemY

Et maintenant :
7ystemoot7systemQPY7ystemoot7Y7ystemoot7ystemQPemYgXunhujdkinY

11.

Java compiler.

20

VOTRE PREMIER PROGRAMME Validez les changements : vous tes maintenant prts compiler en ligne de commande. Pour bien faire, allez dans le rpertoire de votre premier programme et eacez le .class. Ensuite, faites  Dmarrer > Excuter 12  et tapez  cmd .

Pour rappel, dans l'invite de commande, on se dplace de dossier en dossier grce l'instruction cd. cd <nom du dossier enfant> : pour aller dans un dossier contenu dans celui dans lequel nous nous trouvons. cd .. : pour remonter d'un dossier dans la hirarchie.
Par exemple, lorsque j'ouvre la console, je me trouve dans le dossier C:\toto\titi et mon application se trouve dans le dossier C:\sdz, je fais donc :
d FF d FF d sdz

Aprs de la premire instruction, je me retrouve dans le dossier C:\toto. Grce la deuxime instruction, j'arrive la racine de mon disque. Via la troisime instruction, je me retrouve dans le dossier C:\sdz. Nous sommes maintenant dans le dossier contenant notre chier Java ! Cela dit, nous pouvions condenser cela en :
d FFGFFGsdz

Maintenant, vous pouvez crer votre chier .class en excutant la commande suivante :
jv `nomhepihierFjvb

Si, dans votre dossier, vous avez un chier test.java, compilez-le en faisant : javac test.java. Et si vous n'avez aucun message d'erreur, vous pouvez vrier que le chier test.class est prsent en utilisant l'instruction dir qui liste le contenu d'un rpertoire. Cette tape franchie, vous pouvez lancer votre programme Java en faisant ce qui suit :
jv `nompihierglssnsixtensionb

Ce qui nous donne : java test. Et normalement, le rsultat de votre programme Java s'ache sous vos yeux bahis !

Attention : il ne faut pas mettre l'extension du chier pour le lancer, mais il faut la mettre pour le compiler.
Donc voil : vous avez compil et excut un programme Java en ligne de commande. . . Vous avez pu voir qu'il n'y a rien de vraiment compliqu et, qui sait, vous en aurez peut-tre besoin un jour.
12. Ou encore touche Windows + R.

21

CHAPITRE 1. INSTALLER LES OUTILS DE DVELOPPEMENT

En rsum
          La JVM est le cur de Java. Elle fait fonctionner vos programmes Java, prcompils en byte code. Les chiers contenant le code source de vos programmes Java ont l'extension .java. Les chiers prcompils correspondant vos codes source Java ont l'extension .class. Le byte code est un code intermdiaire entre celui de votre programme et celui que votre machine peut comprendre. Un programme Java, cod sous Windows, peut tre prcompil sous Mac et enn excut sous Linux. Votre machine ne peut pas comprendre le byte code, elle a besoin de la JVM. Tous les programmes Java sont composs d'au moins une classe. Le point de dpart de tout programme Java est la mthode public static void main(String[] args). On peut acher des messages dans la console grce ces instructions :  System.out.println, qui ache un message avec un saut de ligne la n ;  System.out.print, qui ache un message sans saut de ligne.

22

Chapitre

2
Dicult :

Les variables et les oprateurs

ous commenons maintenant srieusement la programmation. Dans ce chapitre, nous allons dcouvrir les variables. On les retrouve dans la quasi-totalit des langages de programmation. Une variable est un lment qui stocke des informations de toute sorte en mmoire : des chires, des rsultats de calcul, des tableaux, des renseignements fournis par l'utilisateur. . . Vous ne pourrez pas programmer sans variables. Il est donc indispensable que je vous les prsente !

23

CHAPITRE 2. LES VARIABLES ET LES OPRATEURS

Les dirents types de variables


Nous allons commencer par dcouvrir comment crer des variables dans la mmoire. Pour cela, il faut les dclarer. Une dclaration de variable se fait comme ceci : <Type de la variable> <Nom de la variable> ; Cette opration se termine toujours par un point-virgule ( ; ) 1 . Ensuite, on l'initialise en entrant une valeur. En Java, nous avons deux types de variables :  des variables de type simple ou  primitif  ;  des variables de type complexe ou des  objets . Ce qu'on appelle des types simples ou types primitifs, en Java, ce sont tout bonnement des nombres entiers, des nombres rels, des boolens ou encore des caractres, et vous allez voir qu'il y a plusieurs faons de dclarer certains de ces types.

Les variables de type numrique


- Le type byte (1 octet) peut contenir les entiers entre 128 et +127.
yte tempertureY temperture a TRY

- Le type short (2 octets) contient les entiers compris entre 32768 et +32767.
short vitessewxY vitessewx a QPHHHY

- Le type int (4 octets) va de 2 109 2 109 (2 et 9 zros derrire. . . ce qui fait dj un joli nombre).
int tempertureoleilY tempertureoleil a ISTHHHHHY

Remarquez qu'ici, la temprature est exprime en kelvins. - Le type long (8 octets) peut aller de 9 1018 9 1018 (encore plus gros. . .).
long nneevumiereY nneevumiere a WRTHUHHHHHHHHHHHY

- Le type float (4 octets) est utilis pour les nombres avec une virgule ottante.
flot piY pi a QFIRISWPTSQfY

1. Comme toutes les instructions de ce langage.

24

LES DIFFRENTS TYPES DE VARIABLES Ou encore :


flot nomreY nomre a PFHfY

Vous remarquerez que nous ne mettons pas une virgule, mais un point ! Et vous remarquerez aussi que mme si le nombre en question est rond, on crit .0 derrire celui-ci, le tout suivi de  f .
- Le type double (8 octets) est identique float, si ce n'est qu'il contient plus de chires derrire la virgule et qu'il n'a pas de suxe.
doule divisionY division a HFQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQRY

Nous avons aussi des variables stockant un caractre


- Le type char contient UN caractre stock entre apostrophes ( ' ' ), comme ceci :
hr rtereY rtere a 9e9Y

Des variables de type boolen


- Le type boolean, lui, ne peut contenir que deux valeurs : true (vrai) ou false (faux), sans guillemets 2 .
oolen questionY question a trueY

Et aussi le type String


Le type String permet de grer les chanes de caractres, c'est--dire le stockage de texte. Il s'agit d'une variable d'un type plus complexe que l'on appelle objet. Vous verrez que celle-ci s'utilise un peu diremment des variables prcdentes :
tring phrseY phrse a 4iti et qrosminet4Y GGheuxime mthode de dlrtion de type tring tring str a new tring@AY str a 4ne utre hne de rtres4Y GGv troisime

2. Ces valeurs sont natives dans le langage. Il les comprend directement et sait les interprter.

25

CHAPITRE 2. LES VARIABLES ET LES OPRATEURS


tring string a 4ne utre hne4Y GGit une qutrime pour l route tring hine a new tring@4it une de plus 34AY

Attention : String commence par une majuscule ! Et lors de l'initialisation, on utilise ici des guillemets doubles ( " " ).
Cela a t mentionn plus haut : String n'est pas un type de variable, mais un objet. Notre variable est un objet, on parle aussi d'une instance : ici, une instance de la classe String. Nous y reviendrons lorsque nous aborderons les objets.

On te croit sur parole, mais pourquoi et pas les autres ?

String

commence par une majuscule

C'est simple : il s'agit d'une convention de nommage. En fait, c'est une faon d'appeler nos classes, nos variables, etc. Il faut que vous essayiez de la respecter au maximum. Cette convention, la voici :  tous vos noms de classes doivent commencer par une majuscule ;  tous vos noms de variables doivent commencer par une minuscule ;  si le nom d'une variable est compos de plusieurs mots, le premier commence par une minuscule, le ou les autres par une majuscule, et ce, sans sparation ;  tout ceci sans accentuation ! Je sais que la premire classe que je vous ai demand de crer ne respecte pas cette convention, mais je ne voulais pas vous en parler ce moment-l. . . Donc, prsent, je vous demanderai de ne pas oublier ces rgles ! Voici quelques exemples de noms de classes et de variables :
puli lss oto{} puli lss xomre{} puli lss otoititi{} tring hineY tring hinehegrteresY int nomreY int nomrelusqrndY GGFFF

Donc, pour en revenir au pourquoi du comment, je vous ai dit que les variables de type String sont des objets. Les objets sont dnis par une ossature (un squelette) qui est en fait une classe. Ici, nous utilisons un objet String dni par une classe qui s'appelle  String  ; c'est pourquoi String a une majuscule et pas int, float, etc., qui eux ne sont pas dnis par une classe. 26

LES OPRATEURS ARITHMTIQUES

Chose importante : veillez bien respecter la casse (majuscules et minuscules), car une dclaration de CHAR la place de char ou autre chose provoquera une erreur, tout comme une variable de type string la place de String !
Faites donc bien attention lors de vos dclarations de variables. . . Une petite astuce quand mme (enn deux, plutt) : on peut trs bien compacter les phases de dclaration et d'initialisation en une seule phase ! Comme ceci :
int entier flot pi a hr r tring mot a QPY QFIRITfY a 9z9Y a new tring@4gouou4AY

Et lorsque nous avons plusieurs variables d'un mme type, nous pouvons rsumer tout ceci une dclaration :
int nreI a PD nreP a QD nreQ a HY

Ici, toutes les variables sont des entiers, et toutes sont initialises. Avant de nous lancer dans la programmation, nous allons faire un peu de mathmatiques avec nos variables.

Les oprateurs arithmtiques


Ce sont ceux que l'on apprend l'cole primaire. . .   +  : permet d'additionner deux variables numriques (mais aussi de concatner des chanes de caractres ! Ne vous inquitez pas, on aura l'occasion d'y revenir).   -  : permet de soustraire deux variables numriques.   *  : permet de multiplier deux variables numriques.   /  : permet de diviser deux variables numriques (mais je crois que vous aviez devin).   %  : permet de renvoyer le reste de la division entire de deux variables de type numrique ; cet oprateur s'appelle le modulo.

Quelques exemples de calcul


int nreID nrePD nreQY nreI nreP nreQ nreI nreP nreQ a a a a a a GGdlrtion des vriles I C QY GGnreI vut R P B TY GGnreP vut IP nreP G nreIY GGnreQ vut Q S 7 PY GGnreI vut ID r S a P B P C I WW 7 VY GGnreP vut QD r WW a V B IP C Q T 7 QY GGlD nreQ vut HD r il n9y ps de reste

27

CHAPITRE 2. LES VARIABLES ET LES OPRATEURS Ici, nous voyons bien que nous pouvons aecter des rsultats d'oprations sur des nombres nos variables, mais aussi aecter des rsultats d'oprations sur des variables de mme type.

Je me doute bien que le modulo est assez dicile assimiler. Voici une utilisation assez simple : pour vrier qu'un entier est pair, il sut de vrier que son modulo 2 renvoie 0.
Maintenant, voici quelque chose que les personnes qui n'ont jamais programm ont du mal intgrer. Je garde la mme dclaration de variables que ci-dessus.
int nreID nrePD nreQY nreI a nreP a nreQ a HY nreI a nreI a a P nreP a nreP a nreQ a nreQ a nreI a nreI a nreI C IY nreI C IY nreIY nreP B PY nrePY nreQ G nreQY nreQY nreI E IY GGdlrtion des vriles GGinitilistion

GGnreI a luiEmmeD don H C I ab nreI a I GGnreI a I @fF iEdessusAD mintenntD nreI a I C I GGnreP GGnreP GGnreQ GGnreQ GGnreI GGnreI a a a a a a nreI a P P ab nreP a P B P a R nreP a R R G R a I nreQ a I I E I a H

Et l aussi, il existe une syntaxe qui raccourcit l'criture de ce genre d'oprations. Regardez bien :
nreI a nreI C IY nreI Ca IY nreICCY CCnreIY

Les trois premires syntaxes correspondent exactement la mme opration. La troisime sera certainement celle que vous utiliserez le plus, mais elle ne fonctionne que pour augmenter d'une unit la valeur de nbre1 ! Si vous voulez augmenter de 2 la valeur d'une variable, utilisez les deux syntaxes prcdentes. On appelle cette cela l'incrmentation. La dernire fait la mme chose que la troisime, mais il y a une subtilit dont nous reparlerons dans le chapitre sur les boucles. Pour la soustraction, la syntaxe est identique :
nreI a nreI E IY nreI Ea IY nreIEEY EEnreIY

Mme commentaire que pour l'addition, sauf qu'ici, la troisime syntaxe s'appelle la dcrmentation. 28

LES OPRATEURS ARITHMTIQUES Les raccourcis pour la multiplication fonctionnent de la mme manire ; regardez plutt :
nreI nreI nreI nreI a nreI B PY Ba PY a nreI G PY Ga PY

Trs important :

on ne peut faire du traitement arithmtique que sur des variables de mme type sous peine de perdre de la prcision lors du calcul. On ne s'amuse pas diviser un int par un float, ou pire, par un char ! Ceci est valable pour tous les oprateurs arithmtiques et pour tous les types de variables numriques. Essayez de garder une certaine rigueur pour vos calculs arithmtiques.

Voici les raisons de ma mise en garde. Comme je vous l'ai dit plus haut, chaque type de variable a une capacit dirente et, pour faire simple, nous allons comparer nos variables dirents rcipients. Une variable de type :  byte correspondrait un d coudre, elle ne peut pas contenir grand-chose ;  int serait un verre, c'est dj plus grand ;  double serait un baril. Pou, on en met l-dedans. . . partir de l, ce n'est plus qu'une question de bon sens. Vous devez facilement constater qu'il est possible de mettre le contenu d'un d coudre dans un verre ou un baril. Par contre, si vous versez le contenu d'un baril dans un verre. . . il y en a plein par terre ! Ainsi, si nous aectons le rsultat d'une opration sur deux variables de type double dans une variable de type int, le rsultat sera de type int et ne sera donc pas un rel mais un entier. Pour acher le contenu d'une variable dans la console, appelez l'instruction System.out.println(maVariable); , ou encore System.out.print(maVariable); . Je suppose que vous voudriez aussi mettre du texte en mme temps que vos variables. . . Eh bien sachez que l'oprateur  +  sert aussi d'oprateur de concatnation, c'est--dire qu'il permet de mlanger du texte brut et des variables. Voici un exemple d'achage avec une perte de prcision :
doule nreI a IHD nreP a QY int resultt a @intA@nreI G nrePAY ystemFoutFprintln@4ve rsultt est a 4 C resulttAY

Sachez aussi que vous pouvez tout fait mettre des oprations dans un achage, comme ceci : System.out.print("Rsultat = " + nbre1/nbre2); (le plus joue ici le rle d'oprateur de concatnation) ; ceci vous permet d'conomiser une variable et par consquent de la mmoire.
29

CHAPITRE 2. LES VARIABLES ET LES OPRATEURS Cependant, pour le bien de ce chapitre, nous n'allons pas utiliser cette mthode. Vous allez constater que le rsultat ach est 3 au lieu de 3.33333333333333. . . Et je pense que ceci vous intrigue : int resultat = (int)(nbre1 / nbre2); . Avant que je ne vous explique, remplacez la ligne cite ci-dessus par : int resultat = nbre1 / nbre2; . Vous allez voir qu'Eclipse n'aime pas du tout ! Pour comprendre cela, nous allons voir les conversions.

Les conversions, ou  cast 


Comme expliqu plus haut, les variables de type double contiennent plus d'informations que les variables de type int. Ici, il va falloir couter comme il faut. . . heu, pardon : lire comme il faut ! Nous allons voir un truc super important en Java. Ne vous en dplaise, vous serez amens convertir des variables. D'un type int en type float :
int i a IPQY flot j a @flotAiY

D'un type int en double :


int i a IPQY doule j a @douleAiY

Et inversement :
doule i a IFPQY doule j a PFWWWWWWWY int k a @intAiY GGk vut I k a @intAjY GGk vut P

Ce type de conversion s'appelle une conversion d'ajustement, ou cast de variable. Vous l'avez vu : nous pouvons passer directement d'un type int un type double. L'inverse, cependant, ne se droulera pas sans une perte de prcision. En eet, comme vous avez pu le constater, lorsque nous castons un double en int, la valeur de ce double est tronque, ce qui signie que l' int en question ne prendra que la valeur entire du double, quelle que soit celle des dcimales. Pour en revenir notre problme de tout l'heure, il est aussi possible de caster le rsultat d'une opration mathmatique en la mettant entre  ()  et en la prcdant du type de cast souhait. Donc : 30

LES CONVERSIONS, OU  CAST 


doule nreI a IHD nreP a QY int resultt a @intA@nreI G nrePAY ystemFoutFprintln@4ve rsultt est a 4 C resulttAY

Voil qui fonctionne parfaitement. Pour bien faire, vous devriez mettre le rsultat de l'opration en type double. Et si on fait l'inverse : si nous dclarons deux entiers et que nous mettons le rsultat dans un double ? Voici une possibilit :
int nreI a QD nreP a PY doule resultt a nreI G nrePY ystemFoutFprintln@4ve rsultt est a 4 C resulttAY

Vous aurez 1 comme rsultat. Je ne caste pas ici, car un double peut contenir un int. En voici une autre :
int nreI a QD nreP a PY doule resultt a @douleA@nreI G nrePAY ystemFoutFprintln@4ve rsultt est a 4 C resulttAY

Idem. . . An de comprendre pourquoi, vous devez savoir qu'en Java, comme dans d'autres langages d'ailleurs, il y a la notion de priorit d'opration ; et l, nous en avons un trs bon exemple !

Sachez que l'aectation, le calcul, le cast, le test, l'incrmentation. . . toutes ces choses sont des oprations ! Et Java les fait dans un certain ordre, il y a des priorits.
Dans le cas qui nous intresse, il y a trois oprations :  un calcul ;  un cast sur le rsultat de l'opration ;  une aectation dans la variable resultat. Eh bien, Java excute notre ligne dans cet ordre ! Il fait le calcul (ici 3/2), il caste le rsultat en double, puis il l'aecte dans notre variable resultat. Vous vous demandez srement pourquoi vous n'avez pas 1.5. . . C'est simple : lors de la premire opration de Java, la JVM voit un cast eectuer, mais sur un rsultat de calcul. La JVM fait ce calcul (division de deux int qui, ici, nous donne 1), puis le cast (toujours 1), et aecte la valeur la variable (encore et toujours 1). Donc, pour avoir un rsultat correct, il faudrait caster chaque nombre avant de faire l'opration, comme ceci :
int nreI a QD nreP a PY doule resultt a @douleA@nreIA G @douleA@nrePAY ystemFoutFprintln@4ve rsultt est a 4 C resulttAY GGffihe X ve rsultt est a IFS

31

CHAPITRE 2. LES VARIABLES ET LES OPRATEURS Je ne vais pas trop dtailler ce qui suit 3 ; mais vous allez maintenant apprendre transformer l'argument d'un type donn, int par exemple, en String.
int i a IPY tring j a new tring@AY j a jFvlueyf@iAY

j est donc une variable de type String contenant la chane de caractres 12. Sachez que

ceci fonctionne aussi avec les autres types numriques. Voyons maintenant comment faire marche arrire en partant de ce que nous venons de faire.
int i a IPY tring j a new tring@AY j a jFvlueyf@iAY int k a sntegerFvlueyf@jAFintlue@AY

Maintenant, la variable k de type int contient le nombre 12.

Il existe des quivalents intValue() pour les autres types numriques : floatValue(), doubleValue(). . .

En rsum
 Les variables sont essentielles dans la construction de programmes informatiques.  On aecte une valeur dans une variable avec l'oprateur gal ( = ).  Aprs avoir aect une valeur une variable, l'instruction doit se terminer par un point-virgule ( ; ).  Vos noms de variables ne doivent contenir ni caractres accentus ni espaces et doivent, dans la mesure du possible, respecter la convention de nommage Java.  Lorsque vous eectuez des oprations sur des variables, prenez garde leur type : vous pourriez perdre en prcision.  Vous pouvez caster un rsultat en ajoutant un type devant celui-ci : (int), (double), etc.  Prenez garde aux priorits lorsque vous castez le rsultat d'oprations, faute de quoi ce dernier risque d'tre incorrect.

3. Vous verrez cela plus en dtail dans la partie sur la programmation oriente objet.

32

Chapitre

3
Dicult :

Lire les entres clavier

prs la lecture de ce chapitre, vous pourrez saisir des informations et les stocker dans des variables an de pouvoir les utiliser a posteriori. En fait, jusqu' ce que nous voyions les interfaces graphiques, nous travaillerons en mode console. Donc, an de rendre nos programmes plus ludiques, il est de bon ton de pouvoir interagir avec ceux-ci. Par contre, ceci peut engendrer des erreurs (on parlera d'exceptions, mais ce sera trait plus loin). An de ne pas surcharger le chapitre, nous survolerons ce point sans voir les dirents cas d'erreurs que cela peut engendrer.

33

CHAPITRE 3. LIRE LES ENTRES CLAVIER

La classe Scanner
Je me doute qu'il vous tardait de pouvoir communiquer avec votre application. . . Le moment est enn venu ! Mais je vous prviens, la mthode que je vais vous donner prsente des failles. Je vous fais conance pour ne pas rentrer n'importe quoi n'importe quand. . . Je vous ai dit que vos variables de type String sont en ralit des objets de type String. Pour que Java puisse lire ce que vous tapez au clavier, vous allez devoir utiliser un objet de type Scanner. Cet objet peut prendre dirents paramtres, mais ici nous n'en utiliserons qu'un : celui qui correspond l'entre standard en Java. Lorsque vous faites System.out.println(); , je vous rappelle que vous appliquez la mthode println() sur la sortie standard ; ici, nous allons utiliser l'entre standard System.in. Donc, avant d'indiquer Java qu'il faut lire ce que nous allons taper au clavier, nous devrons instancier un objet Scanner. Avant de vous expliquer ceci, crez une nouvelle classe et tapez cette ligne de code dans votre mthode main :
nner s a new nner@ystemFinAY

Vous devez avoir une jolie vague rouge sous le mot Scanner. Cliquez sur la croix rouge sur la gauche et faites un double-clic sur  Import 'Scanner' java.util (gure 3.1). Et l, l'erreur disparat !

Figure

3.1  Importer la classe Scanner

Maintenant, regardez au-dessus de la dclaration de votre classe, vous devriez voir cette ligne :
import jvFutilFnnerY

Voil ce que nous avons fait. Je vous ai dit qu'il fallait indiquer Java o se trouve la classe Scanner. Pour faire ceci, nous devons importer la classe Scanner grce l'instruction import. La classe que nous voulons se trouve dans le package java.util. Un package est un ensemble de classes. En fait, c'est un ensemble de dossiers et de sous-dossiers contenant une ou plusieurs classes, mais nous verrons ceci plus en dtail lorsque nous ferons nos propres packages. Les classes qui se trouvent dans les packages autres que java.lang 1 sont importer la main dans vos classes Java pour pouvoir vous en servir. La faon dont nous avons
1. Package automatiquement import par Java. On y trouve entre autres la classe System.

34

RCUPRER CE QUE VOUS TAPEZ import la classe java.util.Scanner dans Eclipse est trs commode. Vous pouvez aussi le faire manuellement :
GGgei import GGgei import importe l lsse nner du pkge jvFutil jvFutilFnnerY importe toutes les lsses du pkge jvFutil jvFutilFBY

Rcuprer ce que vous tapez


Voici l'instruction pour permettre Java de rcuprer ce que vous avez saisi pour ensuite l'acher :
nner s a new nner@ystemFinAY ystemFoutFprintln@4euillez sisir un mot X4AY tring str a sFnextvine@AY ystemFoutFprintln@4ous vez sisi X 4 C strAY

Une fois l'application lance, le message que vous avez crit auparavant s'ache dans la console, en bas d'Eclipse. Pensez cliquer dans la console an que ce que vous saisissez y soit crit et que Java puisse rcuprer ce que vous avez inscrit (gure 3.2) !

Figure

3.2  Saisie utilisateur dans la console

Si vous remplacez la ligne de code qui rcupre une chane de caractres comme suit :
nner s a new nner@ystemFinAY ystemFoutFprintln@4euillez sisir un nomre X4AY int str a sFnextsnt@AY ystemFoutFprintln@4ous vez sisi le nomre X 4 C strAY

. . . vous devriez constater que lorsque vous introduisez votre variable de type Scanner et que vous introduisez le point permettant d'appeler des mthodes de l'objet, Eclipse vous propose une liste de mthodes associes cet objet 2 ; de plus, lorsque vous commencez taper le dbut de la mthode nextInt(), le choix se restreint jusqu' ne laisser que cette seule mthode. Excutez et testez ce programme : vous verrez qu'il fonctionne la perfection. Sauf. . . si vous saisissez autre chose qu'un nombre entier !
2. Ceci s'appelle l'autocompltion.

35

CHAPITRE 3. LIRE LES ENTRES CLAVIER Vous savez maintenant que pour lire un int, vous devez utiliser nextInt(). De faon gnrale, dites-vous que pour rcuprer un type de variable, il vous sut d'appeler next<Type de variable commenant par une majuscule> 3 .
nner s a new nner@ystemFinAY int i a sFnextsnt@AY doule d a sFnexthoule@AY long l a sFnextvong@AY yte a sFnextfyte@AY GGitF

la classe Scanner : il s'agit du type char. Voici comment on pourrait rcuprer un caractre :
ystemFoutFprintln@4isissez une lettre X4AY nner s a new nner@ystemFinAY tring str a sFnextvine@AY hr r a strFhret@HAY ystemFoutFprintln@4ous vez sisi le rtre X 4 C rAY

Attention : il y a un type de variables primitives qui n'est pas pris en compte par

Qu'avons-nous fait ici ? Nous avons rcupr une chane de caractres, puis utilis une mthode de l'objet String (ici, charAt(0) ) an de rcuprer le premier caractre saisi. Mme si vous tapez une longue chane de caractres, l'instruction charAt(0) 4 ne renverra que le premier caractre. Jusqu' ce qu'on aborde les exceptions, je vous demanderai d'tre rigoureux et de faire attention ce que vous attendez comme type de donnes an d'utiliser la mthode correspondante. Une prcision s'impose, toutefois : la mthode nextLine() rcupre le contenu de toute la ligne saisie et replace la  tte de lecture  au dbut d'une autre ligne. Par contre, si vous avez invoqu une mthode comme nextInt(), nextDouble() et que vous invoquez directement aprs la mthode nextLine(), celle-ci ne vous invitera pas saisir une chane de caractres : elle videra la ligne commence par les autres instructions. En eet, celles-ci ne repositionnent pas la tte de lecture, l'instruction nextLine() le fait leur place. Pour faire simple, ceci :
import jvFutilFnnerY puli lss win { puli stti void min@tring rgsA{ nner s a new nner@ystemFinAY ystemFoutFprintln@4isissez un entier X 4AY int i a sFnextsnt@AY ystemFoutFprintln@4isissez une hne X 4AY tring str a sFnextvine@AY

3. Rappelez-vous de la convention de nommage Java ! 4. Vous devez vous demander pourquoi charAt(0) et non charAt(1) : nous aborderons ce point lorsque nous verrons les tableaux. . .

36

RCUPRER CE QUE VOUS TAPEZ


ystemFoutFprintln@4psx 3 4AY

. . . ne vous demandera pas de saisir une chane et achera directement  Fin . Pour pallier ce problme, il sut de vider la ligne aprs les instructions ne le faisant pas automatiquement :
import jvFutilFnnerY puli lss win { puli stti void min@tring rgsA{ nner s a new nner@ystemFinAY ystemFoutFprintln@4isissez un entier X 4AY int i a sFnextsnt@AY ystemFoutFprintln@4isissez une hne X 4AY GGyn vide l ligne vnt d9en lire une utre sFnextvine@AY tring str a sFnextvine@AY ystemFoutFprintln@4psx 3 4AY } }

En rsum
 La lecture des entres clavier se fait via l'objet Scanner.  Ce dernier se trouve dans le package java.util que vous devrez importer.  Pour pouvoir rcuprer ce vous allez taper dans la console, vous devrez initialiser l'objet Scanner avec l'entre standard, System.in.  Il y a une mthode de rcupration de donnes pour chaque type (sauf les char) : nextLine() pour les String, nextInt() pour les int . . .

37

CHAPITRE 3. LIRE LES ENTRES CLAVIER

38

Chapitre

4
Dicult :

Les conditions

ous abordons ici l'un des chapitres les plus importants : les conditions sont une autre notion fondamentale de la programmation. En eet, ce qui va tre dvelopp ici s'applique normment de langages de programmation, et pas seulement Java. Dans une classe, la lecture et l'excution se font de faon squentielle, c'est--dire ligne par ligne. Avec les conditions, nous allons pouvoir grer dirents cas de gure sans pour autant lire tout le code. Vous vous rendrez vite compte que tous vos projets ne sont que des enchanements et des imbrications de conditions et de boucles (notion que l'on abordera au chapitre suivant). Assez de belles paroles ! Entrons tout de suite dans le vif du sujet.

39

CHAPITRE 4. LES CONDITIONS

La structure if... else


Avant de pouvoir crer et valuer des conditions, vous devez savoir que pour y parvenir, nous allons utiliser ce qu'on appelle des oprateurs logiques. Ceux-ci sont surtout utiliss lors de conditions (si [test] alors [faire ceci]) pour valuer dirents cas possibles. Voici les dirents oprateurs connatre :   ==  : permet de tester l'galit.   !=  : permet de tester l'ingalit.   <  : strictement infrieur.   <=  : infrieur ou gal.   >  : strictement suprieur.   >=  : suprieur ou gal.   &&  : l'oprateur et. Il permet de prciser une condition.   ||  : le ou. Mme combat que le prcdent.   ? :  : l'oprateur ternaire. Pour celui-ci, vous comprendrez mieux avec un exemple qui sera donn vers la n de ce chapitre. Comme je vous l'ai dit dans le chapitre prcdent, les oprations en Java sont soumises des priorits. Tous ces oprateurs se plient cette rgle, de la mme manire que les oprateurs arithmtiques. . . Imaginons un programme qui demande un utilisateur d'entrer un nombre entier relatif (qui peut tre soit ngatif, soit nul, soit positif). Les structures conditionnelles vont nous permettre de grer ces trois cas de gure. La structure de ces conditions ressemble a :
if@GGonditionA { FFF GGixution des instrutions si l ondition est remplie } else { FFF GGixution des instrutions si l ondition n9est ps remplie }

Cela peut se traduire par  si. . . sinon. . . . Le rsultat de l'expression value par l'instruction if sera un boolean, donc soit true, soit false. La portion de code du bloc if ne sera excute que si la condition est remplie. Dans le cas contraire, c'est le bloc de l'instruction else qui le sera. Mettons notre petit exemple en pratique :
int i a IHY if @i ` HA ystemFoutFprintln@4le nomre est ngtif4AY else ystemFoutFprintln@4le nomre est positif4AY

Essayez ce petit code, et vous verrez comment il fonctionne. Dans ce cas, notre classe ache que  le nombre est positif . Expliquons un peu ce qui se passe. 40

LA STRUCTURE IF... ELSE  Dans un premier temps, la condition du if est teste (elle dit si i est strictement infrieur 0). . .  Dans un second temps, vu que celle-ci est fausse, le programme excute le else.

Attends un peu ! Lorsque tu nous as prsent la structure des conditions, tu as mis des accolades et l, tu n'en mets pas. . .
Bien observ. En fait, les accolades sont prsentes dans la structure  normale  des conditions, mais lorsque le code l'intrieur de l'une d'entre elles n'est compos que d'une seule ligne, les accolades deviennent facultatives. Comme nous avons l'esprit perfectionniste, nous voulons que notre programme ache  le nombre est nul  lorsque i est gal 0 ; nous allons donc ajouter une condition. Comment faire ? La condition du if est remplie si le nombre est strictement ngatif, ce qui n'est pas le cas ici puisque nous allons le mettre 0. Le code contenu dans la clause else est donc excut si le nombre est gal ou strictement suprieur 0. Il nous sut d'ajouter une condition l'intrieur de la clause else, comme ceci :
int i a HY if @i ` HA { ystemFoutFprintln@4ge nomre est ngtif 34AY } else { if@i aa HA ystemFoutFprintln@4ge nomre est nul 34AY else } ystemFoutFprintln@4ge nomre est positif 34AY

Maintenant que vous avez tout compris, je vais vous prsenter une autre faon d'crire ce code, avec le mme rsultat : on ajoute juste un petit sinon si.
int i a HY if @i ` HA ystemFoutFprintln@4ge nomre est ngtif 34AY else if@i b HA ystemFoutFprintln@4ge nomre est positif 34AY else ystemFoutFprintln@4ge nomre est nul 34AY

Alors ? Explicite, n'est-ce pas ? 41

CHAPITRE 4. LES CONDITIONS   


i est strictement ngatif excution du code. i est strictement positif excution du code. sinon i est forcment nul excution du code.
si sinon si

Il faut absolument donner une condition au else

if

pour qu'il fonctionne.

Ici, je vais trs fortement insister sur un point : regardez l'achage du code et remarquez le petit dcalage entre le test et le code excuter. On appelle cela l'indentation ! Pour vous reprer dans vos futurs programmes, cela sera trs utile. Imaginez deux secondes que vous avez un programme de 700 lignes avec 150 conditions, et que tout est crit le long du bord gauche. Il sera dicile de distinguer les tests du code. Vous n'tes pas obligs de le faire, mais je vous assure que vous y viendrez.

Avant de passer la suite, vous devez savoir qu' on ne peut pas tester l'galit de chanes de caractres ! Du moins, pas comme je vous l'ai montr ci-dessus. Nous aborderons ce point plus tard.

Les conditions multiples


Derrire ce nom barbare se cachent simplement plusieurs tests dans une instruction if (ou else if). Nous allons maintenant utiliser les oprateurs logiques que nous avons vus au dbut en vriant si un nombre donn appartient un intervalle connu. Par exemple, on va vrier si un entier est compris entre 50 et 100.
int i a SVY if@i ` IHH 88 i b SHA ystemFoutFprintln@4ve nomre est ien dns l9intervlleF4AY else ystemFoutFprintln@4ve nomre n9est ps dns l9intervlleF4AY

Nous avons utilis l'oprateur &&. La condition de notre if est devenue : si i est infrieur 100 et suprieur 50, alors la condition est remplie.

Avec l'oprateur &&, la clause est remplie si et seulement si les conditions la constituant sont toutes remplies ; si l'une des conditions n'est pas vrie, la clause sera considre comme fausse.
Cet oprateur vous initie la notion d'intersection d'ensembles. Ici, nous avons deux conditions qui dnissent un ensemble chacune :  i < 100 dnit l'ensemble des nombres infrieurs 100 ;  i > 50 dnit l'ensemble des nombres suprieurs 50. 42

LA STRUCTURE SWITCH L'oprateur && permet de faire l'intersection de ces ensembles. La condition regroupe donc les nombres qui appartiennent ces deux ensembles, c'est--dire les nombres de 51 99 inclus. Rchissez bien l'intervalle que vous voulez dnir. Voyez ce code :
int i a SVY if@i ` IHH 88 i b IHHA ystemFoutFprintln@4ve nomre est ien dns l9intervlleF4AY else ystemFoutFprintln@4ve nomre n9est ps dns l9intervlleF4AY

Ici, la condition ne sera jamais remplie, car je ne connais aucun nombre qui soit la fois plus petit et plus grand que 100 ! Reprenez le code prcdent et remplacez l'oprateur && par || 1 . l'excution du programme et aprs plusieurs tests de valeur pour i, vous pourrez vous apercevoir que tous les nombres remplissent cette condition, sauf 100.

La structure switch
Le switch est surtout utilis lorsque nous voulons des conditions  la carte . Prenons l'exemple d'une interrogation comportant deux questions : pour chacune d'elles, on peut obtenir uniquement 0 ou 10 points, ce qui nous donne au nal trois notes et donc trois apprciations possibles, comme ceci.  0/20 : tu peux revoir ce chapitre, petit Zro !  10/20 : je crois que tu as compris l'essentiel ! Viens relire ce chapitre l'occasion.  20/20 : bravo ! Dans ce genre de cas, on utilise un switch pour viter des else if rptition et pour allger un peu le code. Je vais vous montrer comment se construit une instruction switch ; puis nous allons l'utiliser tout de suite aprs.

Syntaxe
swith @GBrileBGA { se GBergumentBGX GBetionBGY rekY defultX GBetionBGY }

Voici les oprations qu'eectue cette expression.  La classe value l'expression gurant aprs le switch (ici /*Variable*/).  Si la premire languette ( case /*Valeur possible de la variable*/: ) correspond la valeur de /*Variable*/, l'instruction gurant dans celle-ci sera excute.
1. Petit rappel, il s'agit du ou.

43

CHAPITRE 4. LES CONDITIONS  Sinon, on passe la languette suivante, et ainsi de suite.  Si aucun des cas ne correspond, la classe va excuter ce qui se trouve dans l'instruction default:/*Action*/; . Voyez ceci comme une scurit. Notez bien la prsence de l'instruction break;. Elle permet de sortir du switch si une languette correspond 2 . Voici un exemple de switch que vous pouvez essayer :
int note a IHY GGyn imgine que l note mximle est PH swith @noteA { se HX ystemFoutFprintln@4yuh 34AY rekY se IHX ystemFoutFprintln@4ous vez juste l moyenneF4AY rekY se PHX ystemFoutFprintln@4rfit 34AY rekY defultX ystemFoutFprintln@4sl fut dvntge trvillerF4AY }

Je n'ai crit qu'une ligne de code par instruction empche d'en mettre plusieurs.

case,

mais rien ne vous

Si vous avez essay ce programme en supprimant l'instruction break;, vous avez d vous rendre compte que le switch excute le code contenu dans le case 10:, mais aussi dans tous ceux qui suivent ! L'instruction break; permet de sortir de l'opration en cours. Dans notre cas, on sort de l'instruction switch, mais nous verrons une autre utilit break; dans le chapitre suivant.

L'instruction switch ne prend que des entiers ou des caractres en paramtre. Il est important de le remarquer.

La condition ternaire
Les conditions ternaires sont assez complexes et relativement peu utilises. Je vous les prsente ici titre indicatif.
2. Pour mieux juger de l'utilit de cette instruction, enlevez tous les break; et compilez votre programme. Vous verrez le rsultat. . .

44

LA CONDITION TERNAIRE La particularit des conditions ternaires rside dans le fait que trois oprandes (c'est-dire des variables ou des constantes) sont mis en jeu, mais aussi que ces conditions sont employes pour aecter des donnes une variable. Voici quoi ressemble la structure de ce type de condition :
int x a IHD y a PHY int mx a @x ` yA c y X x Y GGwintenntD mx vut PH

Dcortiquons ce qu'il se passe.  Nous cherchons aecter une valeur notre variable max, mais de l'autre ct de l'oprateur d'aectation se trouve une condition ternaire. . .  Ce qui se trouve entre les parenthses est valu : x est-il plus petit que y ? Donc, deux cas de gure se prolent l'horizon :  si la condition renvoie true (vrai), qu'elle est vrie, la valeur qui se trouve aprs le ? sera aecte ;  sinon, la valeur se trouvant aprs le symbole : sera aecte.  L'aectation est eective : vous pouvez utiliser votre variable max. Vous pouvez galement faire des calculs (par exemple) avant d'aecter les valeurs :
int x a IHD y a PHY int mx a @x ` yA c y B P X x B P Y GGsiD mx vut P B PH don RH

N'oubliez pas que la valeur que vous allez aecter votre variable doit tre du mme type que votre variable. Sachez aussi que rien ne vous empche d'insrer une condition ternaire dans une autre condition ternaire :
int x a IHD y a PHY int mx a @x ` yA c @y ` IHA c y 7 IH X y B P X x Y GGwx vut RH GGs trs file lireFFF GGous pouvez entourer votre deuxime instrution ternire GGde prenthses pour mieux voir mx a @x ` yA c @@y ` IHA c y 7 IH X y B PA X x Y GGwx vut RH

En rsum
 Les conditions vous permettent de n'excuter que certains morceaux de code.  Il existe plusieurs sortes de structures conditionnelles :  la structure if... elseif... else ;  la structure switch... case... default ;  la structure ? :.  Si un bloc d'instructions contient plus d'une ligne, vous devez l'entourer d'accolades an de bien en dlimiter le dbut et la n.  Pour pouvoir mettre une condition en place, vous devez comparer des variables l'aide d'oprateurs logiques. 45

CHAPITRE 4. LES CONDITIONS  Vous pouvez mettre autant de comparaisons renvoyant un boolean que vous le souhaitez dans une condition.  Pour la structure switch, pensez mettre les instructions break; si vous ne souhaitez excuter qu'un seul bloc case.

46

Chapitre

5
Dicult :

Les boucles

e rle des boucles est de rpter un certain nombre de fois les mmes oprations. Tous les programmes, ou presque, ont besoin de ce type de fonctionnalit. Nous utiliserons les boucles pour permettre un programme de recommencer depuis le dbut, pour attendre une action prcise de l'utilisateur, parcourir une srie de donnes, etc. Une boucle s'excute tant qu'une condition est remplie. Nous rutiliserons donc des notions du chapitre prcdent !

47

CHAPITRE 5. LES BOUCLES

La boucle while
Dcortiquons prcisment ce qui se passe dans une boucle. Pour ce faire, nous allons voir comment elle se construit. Une boucle commence par une dclaration : ici while. Cela veut dire, peu de chose prs,  tant que . Puis nous avons une condition : c'est elle qui permet la boucle de s'arrter. Une boucle n'est utile que lorsque nous pouvons la contrler, et donc lui faire rpter une instruction un certain nombre de fois. C'est a que servent les conditions. Ensuite nous avons une ou plusieurs instructions : c'est ce que va rpter notre boucle 1 !
while @GB gondition BGA { GGsnstrutions rpter }

Un exemple concret tant toujours le bienvenu, en voici un. . . D'abord, rchissons  comment notre boucle va travailler . Pour cela, il faut dterminer notre exemple. Nous allons acher  Bonjour, <un prnom> , prnom qu'il faudra taper au clavier ; puis nous demanderons si l'on veut recommencer. Pour cela, il nous faut une variable qui va recevoir le prnom, donc dont le type sera String, ainsi qu'une variable pour rcuprer la rponse. Et l, plusieurs choix s'orent nous : soit un caractre, soit une chane de caractres, soit un entier. Ici, nous prendrons une variable de type char. C'est parti !
GGne vrile vide tring prenomY GGyn initilise elleEi y pour oui hr reponse a 9y9Y GGxotre ojet nnerD n9ouliez ps l9import de jvFutilFnner 3 nner s a new nner@ystemFinAY GGnt que l rponse donne est gle ouiFFF while @reponse aa 9y9A { GGyn ffihe une instrution ystemFoutFprintln@4honnez un prnom X 4AY GGyn rupre le prnom sisi prenom a sFnextvine@AY GGyn ffihe notre phrse ve le prnom ystemFoutFprintln@4fonjour 4 CprenomC 4D omment vsEtu c4AY GGyn demnde si l personne veut fire un utre essi ystemFoutFprintln@4oulezEvous ressyer c @yGxA4AY GGyn rupre l rponse de l9utilisteur reponse a sFnextvine@AFhret@HAY }

1. Il peut mme y avoir des boucles dans une boucle.

48

LA BOUCLE WHILE

ystemFoutFprintln@4eu revoirFFF4AY GGpin de l oule

Vous avez d cligner des yeux en lisant  reponse = sc.nextLine().charAt(0); . Rappelez-vous comment on rcupre un char avec l'objet Scanner : nous devons rcuprer un objet String et ensuite prendre le premier caractre de celui-ci ! Eh bien cette syntaxe est une contraction de ce que je vous avais fait voir auparavant. Dtaillons un peu ce qu'il se passe. Dans un premier temps, nous avons dclar et initialis nos variables. Ensuite, la boucle value la condition qui nous dit : tant que la variable reponse contient  O , on excute la boucle. Celle-ci contient bien le caractre  O , donc nous entrons dans la boucle. Puis l'excution des instructions suivant l'ordre dans lequel elles apparaissent dans la boucle a lieu. la n, c'est--dire l'accolade fermante de la boucle, le compilateur nous ramne au dbut de la boucle.

Cette boucle n'est excute que lorsque la condition est remplie : ici, nous avons initialis la variable reponse  O  pour que la boucle s'excute. Si nous ne l'avions pas fait, nous n'y serions jamais entrs. Normal, puisque nous testons la condition avant d'entrer dans la boucle !
Voil. C'est pas mal, mais il faudrait forcer l'utilisateur ne taper que  O  ou  N . Comment faire ? C'est trs simple : avec une boucle ! Il sut de forcer l'utilisateur entrer soit  N  soit  O  avec un while ! Attention, il nous faudra rinitialiser la variable reponse  ' '  2 . Il faudra donc rpter la phase  Voulez-vous ressayer ?  tant que la rponse donne n'est pas  O  ou  N  : voil, tout y est. Voici notre programme dans son intgralit :
tring prenomY hr reponse a 9y9Y nner s a new nner@ystemFinAY while @reponse aa 9y9A { ystemFoutFprintln@4honnez un prnom X 4AY prenom a sFnextvine@AY ystemFoutFprintln@4fonjour 4 CprenomC 4D omment vsEtu c4AY GGns D nous n9entrerions ps dns l deuxime oule reponse a 9 9Y GGnt que l rponse n9est ps y ou xD on repose l question while@reponse 3a 9y9 88 reponse 3a 9x9A { GGyn demnde si l personne veut fire un utre essi ystemFoutFprintln@4oulezEvous ressyer c @yGxA4AY reponse a sFnextvine@AFhret@HAY

2. Caractre vide.

49

CHAPITRE 5. LES BOUCLES


} } ystemFoutFprintln@4eu revoirFFF4AY

Copier ce code Code web : 856542  Vous pouvez tester ce code (c'est d'ailleurs vivement conseill) : vous verrez que si vous n'entrez pas la bonne lettre, le programme vous posera sans cesse sa question (gure 5.1) !

Figure

5.1  Test de la boucle

Attention crire correctement vos conditions et bien vrier vos variables dans vos while, et dans toutes vos boucles en gnral. Sinon c'est le drame ! Essayez d'excuter le programme prcdent sans la rinitialisation de la variable reponse, et vous verrez le rsultat. . . On n'entre jamais dans la deuxime boucle, car reponse = 'O' (puisque initialise ainsi au dbut du programme). L, vous ne pourrez jamais changer sa valeur. . . le programme ne s'arrtera donc jamais ! On appelle a une boucle innie, et en voici un autre exemple.
int a ID a ISY while @ ` A { ystemFoutFprintln@4ouou 4 CC 4 fois 334AY }

Si vous lancez ce programme, vous allez voir une quantit astronomique de coucou 1 fois !!. Nous aurions d ajouter une instruction dans le bloc d'instructions de notre while pour changer la valeur de a chaque tour de boucle, comme ceci :
int a ID a ISY while @ ` A

50

LA BOUCLE WHILE
{ }

ystemFoutFprintln@4ouou 4 CC 4 fois 334AY CCY

Ce qui nous donnerait comme rsultat la gure 5.2.

Figure

5.2  Correction de la boucle innie

Une petite astuce : lorsque vous n'avez qu'une instruction dans votre boucle, vous pouvez enlever les accolades, car elles deviennent superues, tout comme pour les instructions if, else if ou else.
Vous auriez aussi pu utiliser cette syntaxe :
int a ID a ISY while @CC ` A ystemFoutFprintln@4ouou 4 CC 4 fois 334AY

Souvenez-vous de ce dont je vous parlais au chapitre prcdent sur la priorit des oprateurs. Ici, l'oprateur  <  a la priorit sur l'oprateur d'incrmentation  ++ . Pour faire court, la boucle while teste la condition et ensuite incrmente la variable a. Par contre, essayez ce code :
int a ID a ISY while @CC ` A ystemFoutFprintln@4ouou 4 CC 4 fois 334AY

Vous devez remarquer qu'il y a un tour de boucle en moins ! Eh bien avec cette syntaxe, l'oprateur d'incrmentation est prioritaire sur l'oprateur d'ingalit (ou d'galit), c'est--dire que la boucle incrmente la variable a, et ce n'est qu'aprs l'avoir fait qu'elle teste la condition ! 51

CHAPITRE 5. LES BOUCLES

La boucle do... while


Puisque je viens de vous expliquer comment fonctionne une boucle while, je ne vais pas vraiment m'attarder sur la boucle do... while. En eet, ces deux boucles ne sont pas cousines, mais plutt surs. Leur fonctionnement est identique deux dtails prs.
do{ GGllllllll }while@ ` AY

Premire dirence
La boucle do... while s'excutera au moins une fois, contrairement sa sur. C'est--dire que la phase de test de la condition se fait la n, car la condition se met aprs le while.

Deuxime dirence
C'est une dirence de syntaxe, qui se situe aprs la condition du while. Vous voyez la dirence ? Oui ? Non ? Il y a un  ;  aprs le while. C'est tout ! Ne l'oubliez cependant pas, sinon le programme ne compilera pas. Mis part ces deux lments, ces boucles fonctionnent exactement de la mme manire. D'ailleurs, refaisons notre programme prcdent avec une boucle do... while.
tring prenom a new tring@AY GGs esoin d9initiliser X on entre u moins une fois dns l oule 3 hr reponse a 9 9Y nner s a new nner@ystemFinAY do{ ystemFoutFprintln@4honnez un prnom X 4AY prenom a sFnextvine@AY ystemFoutFprintln@4fonjour 4 CprenomC 4D omment vsEtu c4AY do{ ystemFoutFprintln@4oulezEvous ressyer c @yGxA4AY reponse a sFnextvine@AFhret@HAY }while@reponse 3a 9y9 88 reponse 3a 9x9AY }while @reponse aa 9y9AY ystemFoutFprintln@4eu revoirFFF4AY

Vous voyez donc que ce code ressemble beaucoup celui utilis avec la boucle while, 52

LA BOUCLE FOR mais il comporte une petite subtilit : ici, plus besoin de rinitialiser la variable reponse, puisque de toute manire, la boucle s'excutera au moins une fois !

La boucle for
Cette boucle est un peu particulire puisqu'elle prend tous ses attributs dans sa condition et agit en consquence. Je m'explique : jusqu'ici, nous avions fait des boucles avec :  dclaration d'une variable avant la boucle ;  initialisation de cette variable ;  incrmentation de celle-ci dans la boucle. Eh bien on met tout a dans la condition de la boucle for 3 , et c'est tout. Mais je sais bien qu'un long discours ne vaut pas un exemple, alors voici une boucle for sous vos yeux bahis :
for@int i a IY i `a IHY iCCA { ystemFoutFprintln@4oii l ligne 4CiAY }

Ce qui donne la gure 5.3.

Figure

5.3  Test de boucle for

Vous aurez srement remarqu la prsence des  ;  dans la condition pour la sparation des champs. Ne les oubliez surtout pas, sinon le programme ne compilera pas. Nous pouvons aussi inverser le sens de la boucle, c'est--dire qu'au lieu de partir de 0 pour aller 10, nous allons commencer 10 pour atteindre 0 :
for@int i a IHY i ba HY iEEA ystemFoutFprintln@4sl reste 4CiC4 ligne@sA rire4AY

3. Il existe une autre syntaxe pour la boucle for depuis le JDK 1.5. Nous la verrons lorsque nous aborderons les tableaux.

53

CHAPITRE 5. LES BOUCLES On obtient la gure 5.4.

Figure

5.4  Boucle for avec dcrmentation

Pour simplier, la boucle for est un peu le condens d'une boucle while dont le nombre de tours se dtermine via un incrment. Nous avons un nombre de dpart, une condition qui doit tre remplie pour excuter une nouvelle fois la boucle et une instruction de n de boucle qui incrmente notre nombre de dpart. Remarquez que rien ne nous empche de cumuler les dclarations, les conditions et les instructions de n de boucle :
for@int i a HD j a PY @i ` IH 88 j ` TAY iCCD jCaPA{ ystemFoutFprintln@4i a 4 C i C 4D j a 4 C jAY }

Ici, cette boucle n'eectuera que deux tours puisque la condition (i < 10 && j < 6) est remplie ds le deuxime tour, la variable j commenant 2 et tant incrmente de deux chaque tour de boucle.

En rsum
 Les boucles vous permettent simplement d'eectuer des tches rptitives.  Il existe plusieurs sortes de boucles :  la boucle while(condition){...} value la condition puis excute ventuellement un tour de boucle (ou plus) ;  la boucle do{...}while(condition); fonctionne exactement comme la prcdente, mais eectue un tour de boucle quoi qu'il arrive ;  la boucle for permet d'initialiser un compteur, une condition et un incrment dans sa dclaration an de rpter un morceau de code un nombre limit de fois.  Tout comme les conditions, si une boucle contient plus d'une ligne de code excuter, vous devez l'entourer d'accolades an de bien en dlimiter le dbut et la n.

54

Chapitre

6
Dicult :

TP : conversion Celsius - Fahrenheit

oil un trs bon petit TP qui va vous permettre de mettre en uvre toutes les notions que vous avez vues jusqu'ici :  les variables ;  les conditions ;  les boucles ;  votre gnial cerveau. Accrochez-vous, car je vais vous demander de penser des tonnes de choses, et vous serez tout seuls. Lchs dans la nature. . . Mais non je plaisante, je vais vous guider un peu. ;-)

55

CHAPITRE 6. TP : CONVERSION CELSIUS - FAHRENHEIT

laboration
Voici le programme que nous allons devoir raliser :  le programme demande quelle conversion nous souhaitons eectuer, Celsius vers Fahrenheit ou l'inverse ;  on n'autorise que les modes de conversion dnis dans le programme (un simple contrle sur la saisie fera l'aaire) ;  enn, on demande la n l'utilisateur s'il veut faire une nouvelle conversion, ce qui signie que l'on doit pouvoir revenir au dbut du programme ! Avant de vous lancer dans la programmation proprement parler, je vous conseille fortement de rchir votre code. . . sur papier. Rchissez ce qu'il vous faut comme nombre de variables, les types de variables, comment va se drouler le programme, les conditions et les boucles utilises. . . toutes ns utiles, voici la formule de conversion pour passer des degrs Celsius en 9 degrs Fahrenheit : F = 5 C + 32 ; pour l'opration inverse, c'est comme ceci : (F 32)5 . C= 9 Voici un aperu de ce que je vous demande (gure 6.1).

Figure

6.1  Rendu du TP

Je vais galement vous donner une fonction toute faite qui vous permettra ventuellement d'arrondir vos rsultats. Je vous expliquerai le fonctionnement des fonctions dans deux chapitres. Tant qu' prsent, c'est facultatif, vous pouvez trs bien ne pas vous en servir. Pour ceux qui souhaitent tout de mme l'utiliser, la voici :
puli stti doule rrondi@doule eD int fA { return @douleA @ @intA @e B wthFpow@IHD fA C FSAA G wthFpow@IHD fAY }

56

CORRECTION Elle est placer entre les deux accolades fermantes de votre classe (gure 6.2).

Figure

6.2  Emplacement de la fonction

Voici comment utiliser cette fonction : imaginez que vous avez la variable faren arrondir, et que le rsultat obtenu est enregistr dans une variable arrondFaren ; vous procderez comme suit :
rrondpren a rrondi@frenDIAY GGour un hiffre prs l virgule rrondpren a rrondi@frenD PAYGGour deux hiffres prs l virguleD etF

Quelques dernires recommandations : essayez de bien indenter votre code ! Prenez votre temps. Essayez de penser tous les cas de gure. . . Maintenant vos papiers, crayons, neurones, claviers. . . et bon courage !

Correction
C'est ni ! Il est temps de passer la correction de ce premier TP. a va ? Pas trop mal la tte ? Je me doute qu'il a d y avoir quelques tubes d'aspirine vids. . . Vous allez voir qu'en dnitive, ce TP n'tait pas si compliqu que a. Surtout, n'allez pas croire que ma correction est parole d'vangile. . . Il y avait direntes manires d'obtenir le mme rsultat. Voici tout de mme une des solutions possibles.
Stop !

import jvFutilFnnerY lss dzI { puli stti void min@tring rgsA { GGxotre ojet nner nner s a new nner@ystemFinAY

57

CHAPITRE 6. TP : CONVERSION CELSIUS - FAHRENHEIT

GGinitilistion des vriles doule gonvertirD onvertitaHY hr reponsea9 9D mode a 9 9Y ystemFoutFprintln@4gyxisi hiq givs i hiq perixris4AY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY do{GGtnt que reponse a yGGoule priniple do{GGtnt que reponse n9est ps y ou x mode a 9 9Y ystemFoutFprintln@4ghoisissez le mode de onversion X 4AY ystemFoutFprintln@4I E gonvertisseur gelsius E phrenheit4AY ystemFoutFprintln@4P E gonvertisseur phrenheit E gelsius 4AY mode a sFnextvine@AFhret@HAY if@mode 3a 9I9 88 mode 3a 9P9A ystemFoutFprintln@4wode inonnuD veuillez ritrer votre hoixF4AY }while @mode 3a 9I9 88 mode 3a 9P9AY GGsisie de l temprture onvertir ystemFoutFprintln@4emprture onvertir X4AY gonvertir a sFnexthoule@AY GGensez vider l ligne lue sFnextvine@AY GGelon le modeD on lule diffremment et on ffihe le rsultt if@mode aa 9I9A{ onvertit a @@WFHGSFHA B gonvertirA C QPFHY ystemFoutFprint@gonvertir C 4 g orrespond X 4AY ystemFoutFprintln@rrondi@onvertitD PA C 4 pF4AY } else{ onvertit a @@gonvertir E QPA B SA G WY ystemFoutFprint@gonvertir C 4 p orrespond X 4AY ystemFoutFprintln@rrondi@onvertitD PA C 4 gF4AY } GGyn invite l9utilisteur reommener ou quitter do{ ystemFoutFprintln@4ouhitezEvous onvertir une utre temprture c@yGxA4AY reponse a sFnextvine@AFhret@HAY }while@reponse 3a 9y9 88 reponse 3a 9x9AY }while@reponse aa 9y9AY ystemFoutFprintln@4eu revoir 34AY

58

CORRECTION

GGpin de progrmme } puli stti doule rrondi@doule eD int fA { return @douleA @ @intA @e B wthFpow@IHD fA C FSAA G wthFpow@IHD fAY }

Copier la correction Code web : 499371 

Expliquons un peu ce code


 Tout programme commence par une phase de dclaration des variables.  Nous achons le titre de notre programme.  Ensuite, vous voyez 2 do{ conscutifs correspondant deux conditions vrier :  la volont de l'utilisateur d'eectuer une nouvelle conversion ;  la vrication du mode de conversion.  Nous achons les renseignements l'cran, et rcuprons la temprature convertir pour la stocker dans une variable.  Selon le mode slectionn, on convertit la temprature et on ache le rsultat.  On invite l'utilisateur recommencer.  Fin du programme ! Ce programme n'est pas parfait, loin de l. La vocation de celui-ci tait de vous faire utiliser ce que vous avez appris, et je pense qu'il remplit bien sa fonction. J'espre que vous avez apprci ce TP. Je sais qu'il n'tait pas facile, mais avouez-le : il vous a bien fait utiliser tout ce que vous avez vu jusqu'ici !

59

CHAPITRE 6. TP : CONVERSION CELSIUS - FAHRENHEIT

60

Chapitre

7
Dicult :

Les tableaux

omme tout langage de programmation qui se respecte, Java travaille avec des tableaux. Vous verrez que ceux-ci s'avrent bien pratiques. . . Vous vous doutez (je suppose) que les tableaux dont nous parlons n'ont pas grand-chose voir avec ceux que vous connaissez ! En programmation, un tableau n'est rien d'autre qu'une variable un peu particulire. Nous allons en eet pouvoir lui aecter plusieurs valeurs ordonnes squentiellement que nous pourrons appeler au moyen d'un indice (ou d'un compteur, si vous prfrez). Il nous sura d'introduire l'emplacement du contenu dsir dans notre variable tableau pour la sortir, travailler avec, l'acher. . . Assez bavard : mettons-nous joyeusement au travail !

61

CHAPITRE 7. LES TABLEAUX

Tableau une dimension


Je viens de vous expliquer grosso modo ce qu'est un tableau en programmation. Si maintenant, je vous disais qu'il y a autant de types de tableaux que de types de variables ? Je crois voir quelques gouttes de sueur perler sur vos fronts. . . Pas de panique ! C'est trs logique : comme nous l'avons vu auparavant, une variable d'un type donn ne peut contenir que des lments de ce type : une variable de type int ne peut pas recevoir une chane de caractres. Il en va de mme pour les tableaux. Voyons tout de suite comment ils se dclarent :
<type du tableau> <nom du tableau> [] = { <contenu du tableau>};

La dclaration ressemble beaucoup celle d'une variable quelconque, si ce n'est la prsence de crochets [] aprs le nom de notre tableau et d'accolades {} encadrant l'initialisation de celui-ci. Dans la pratique, a nous donnerait quelque chose comme ceci :
int tleuintier a {HDIDPDQDRDSDTDUDVDW}Y doule tleuhoule a {HFHDIFHDPFHDQFHDRFHDSFHDTFHDUFHDVFHDWFH}Y hr tleugrtere a {99D99D99D9d9D9e9D9f9D9g9}Y tring tleughine a {4hineI4D 4hineP4D 4hineQ4 D 4hineR4}Y

Vous remarquez bien que la dclaration et l'initialisation d'un tableau se font comme avec une variable ordinaire : il faut utiliser des ' ' pour initialiser un tableau de caractres, des " " pour initialiser un tableau de String, etc. Vous pouvez aussi dclarer un tableau vide, mais celui-ci devra imprativement contenir un nombre de cases bien dni. Par exemple, si vous voulez un tableau vide de six entiers :
int tleuintier a new intTY GGyu enore int tleuintierP a new intTY

Cette opration est trs simple, car vraiment ressemblante ce que vous faisiez avec vos variables ; je vous propose donc tout de suite de nous pencher sur une belle variante de ces tableaux. . .

Les tableaux multidimensionnels


Ici, les choses se compliquent un peu, car un tableau multidimensionnel n'est rien d'autre qu'un tableau contenant au minimum deux tableaux. . . Je me doute bien que cette notion doit en erayer plus d'un, mais en ralit, elle n'est pas si dicile que a apprhender. Comme tout ce que je vous apprends en gnral ! Je ne vais pas vous faire de grand laus sur ce type de tableau, puisque je pense sincrement qu'un exemple vous en fera beaucoup mieux comprendre le concept. Imaginez un tableau avec deux lignes : la premire contiendra les premiers nombres pairs, et le deuxime contiendra les premiers nombres impairs. 62

UTILISER ET RECHERCHER DANS UN TABLEAU Ce tableau s'appellera premiersNombres. Voil ce que cela donnerait :
int premiersxomres a { {HDPDRDTDV}D{IDQDSDUDW} }Y

Nous voyons bien ici les deux lignes de notre tableau symbolises par les doubles crochets [][]. Et comme je l'ai dit plus haut, ce genre de tableau est compos de plusieurs tableaux. Ainsi, pour passer d'une ligne l'autre, nous jouerons avec la valeur du premier crochet. Exemple : premiersNombres[0][0] correspondra au premier lment de la ligne paire, et premiersNombres[1][0] correspondra au premier lment de la ligne impaire. Voici un petit schma en guise de synthse (gure 7.1).

Figure

7.1  Comprendre un tableau bidimensionnel

Maintenant, je vais vous proposer de vous amuser un peu avec les tableaux. . .

Utiliser et rechercher dans un tableau


Avant d'attaquer, je dois vous dire quelque chose de primordial : un tableau dbute toujours l'indice 0 ! Je m'explique : prenons l'exemple du tableau de caractres contenant les lettres de l'alphabet dans l'ordre qui a t donn plus haut. Si vous voulez acher la lettre  a  l'cran, vous devrez taper cette ligne de code :
ystemFoutFprintln@tleugrtereHAY

Cela implique qu'un tableau contenant 4 lments aura comme indices possibles 0, 1, 2 ou 3. Le 0 correspond au premier lment, le 1 correspond au 2 e lment, le 2 correspond au 3e lment et le 3 correspond au 4 e lment.

Une trs grande partie des erreurs sur les tableaux sont souvent dues un mauvais indice dans celui-ci. Donc prenez garde. . .
Ce que je vous propose, c'est tout simplement d'acher un des tableaux prsents ci-dessus dans son intgralit. Sachez qu'il existe une instruction qui retourne la taille d'un tableau : grce elle, nous pourrons arrter notre boucle (car oui, nous allons utiliser une boucle). Il s'agit de l'instruction <mon tableau>.length. Notre boucle for pourrait donc ressembler ceci : 63

CHAPITRE 7. LES TABLEAUX


hr tleugrtere a {99D99D99D9d9D9e9D9f9D9g9}Y for@int i a HY i ` tleugrtereFlengthY iCCA { ystemFoutFprintln@4e l9emplement 4 C i C4 du tleu nous vons a 4 C tleugrtereiAY }

Cela achera :
A A A A A A A l'emplacement l'emplacement l'emplacement l'emplacement l'emplacement l'emplacement l'emplacement 0 1 2 3 4 5 6 du du du du du du du tableau tableau tableau tableau tableau tableau tableau nous nous nous nous nous nous nous avons avons avons avons avons avons avons = = = = = = = a b c d e f g

Maintenant, nous allons essayer de faire une recherche dans un de ces tableaux. En gros, il va falloir eectuer une saisie clavier et regarder si celle-ci est prsente dans le tableau. . . Gardez la partie de code permettant de faire plusieurs fois la mme action ; ensuite, faites une boucle de recherche incluant la saisie clavier, un message si la saisie est trouve dans le tableau, et un autre message si celle-ci n'est pas trouve. Ce qui nous donne :
hr tleugrtere a {99D 99D 99D 9d9D 9e9D 9f9D 9g9}Y int i a HD emplement a HY hr reponse a 9 9Dr a 9 9Y nner s a new nner@ystemFinAY do {GGfoule priniple do {GGyn rpte ette oule tnt que l9utilisteur n9 ps rentr une lettre figurnt dns le tleu i a HY ystemFoutFprintln@4entrez une lettre en minusuleD 4AY r a sFnextvine@AFhret@HAY GGfoule de reherhe dns le tleu while@i ` tleugrtereFlength 88 r 3a tleugrtereiA iCCY GGi i ` U 9est que l oule n9 ps dpss le nomre de ses du tleu if @i ` tleugrtereFlengthA ystemFoutFprintln@4 v lettre 4 CrC 4 se trouve ien dns le tleu 34AY else GGinon ystemFoutFprintln@4 v lettre 4 CrC 4 ne se trouve ps dns le tleu 34AY

64

UTILISER ET RECHERCHER DANS UN TABLEAU


}while@i ba tleugrtereFlengthAY GGnt que l lettre de l9utilisteur GGne orrespond ps une lettre du tleu do{ ystemFoutFprintln@4oulezEvous essyer nouveu c @yGxA4AY reponse a sFnextvine@AFhret@HAY }while@reponse 3a 9x9 88 reponse 3a 9y9AY }while @reponse aa 9y9AY ystemFoutFprintln@4eu revoir 34AY

Le rsultat de ce code est sur la gure 7.2.

Figure

7.2  Rsultat de la recherche

Explicitons un peu ce code, et plus particulirement la recherche


Dans notre while, il y a deux conditions. La premire correspond au compteur : tant que celui-ci est infrieur ou gal au nombre d'lments du tableau, on l'incrmente pour regarder la valeur suivante. Nous passons ainsi en revue tout ce qui se trouve dans notre tableau. Si nous n'avions mis que cette condition, la boucle n'aurait fait que parcourir le tableau, sans voir si le caractre saisi correspond bien un caractre de notre tableau, d'o la deuxime condition. La deuxime correspond la comparaison entre le caractre saisi et la recherche dans le tableau. Grce elle, si le caractre saisi se trouve dans le tableau, la boucle prend n, et donc i a une valeur infrieure 7. ce stade, notre recherche est termine. Aprs cela, les conditions coulent de source ! Si nous avons trouv une correspondance entre le caractre saisi et notre tableau, i 65

CHAPITRE 7. LES TABLEAUX prendra une valeur infrieure 7 (vu qu'il y a 7 lments dans notre tableau, l'indice maximum tant 7-1, soit 6). Dans ce cas, nous achons un message conrmant la prsence de l'lment recherch. Dans le cas contraire, c'est l'instruction du else qui s'excutera.

Vous avez d remarquer la prsence d'un i = 0; dans une boucle. Ceci est primordial, sinon, lorsque vous reviendrez au dbut de celle-ci, i ne vaudra plus 0, mais la dernire valeur laquelle il aura t aect aprs les direntes incrmentations. Si vous faites une nouvelle recherche, vous commencerez par l'indice contenu dans i ; ce que vous ne voulez pas, puisque le but est de parcourir l'intgralit du tableau, donc depuis l'indice 0.
En travaillant avec les tableaux, vous serez confronts, un jour ou l'autre, au message suivant : java.lang.ArrayIndexOutOfBoundsException . Ceci signie qu'une erreur a t rencontre, car vous avez essay de lire (ou d'crire dans) une case qui n'a pas t dnie dans votre tableau ! Voici un exemple 1 :
tring str a new tringIHY GGv9instrution suivnte v dlenher une exeption GGr vous essyez d9rire l se II de votre tleu GGlors que eluiEi n9en ontient que IH @ ommene H 3A strIH a 4ne exeption4Y

Nous allons maintenant travailler sur le tableau bidimensionnel mentionn prcdemment. Le principe est vraiment identique celui d'un tableau simple, sauf qu'ici, il y a deux compteurs. Voici un exemple de code permettant d'acher les donnes par ligne, c'est--dire l'intgralit du sous-tableau de nombres pairs , puis le sous-tableau de nombres impairs :

Avec une boucle while


int premiersxomres a { {HDPDRDTDV}D{IDQDSDUDW} }D i a HD j a HY while @i ` PA { j a HY while@j ` SA { ystemFoutFprint@premiersxomresijAY jCCY } ystemFoutFprintln@44AY iCCY }

Et voil le rsultat (gure 7.3).


1. Nous verrons les exceptions lorsque nous aborderons la programmation oriente objet.

66

UTILISER ET RECHERCHER DANS UN TABLEAU

Figure

7.3  Achage du tableau

Dtaillons un peu ce code


 Dans un premier temps, on initialise les variables.  On entre ensuite dans la premire boucle (qui s'excutera deux fois, donc i vaut 0 la premire fois, et vaudra 1 pendant la deuxime), et on initialise j 0.  On entre ensuite dans la deuxime boucle, o j vaudra successivement 0, 1, 2, 3 et 4 pour acher le contenu du tableau d'indice 0 (notre premier i).  On sort de cette boucle ; notre i est ensuite incrment et passe 1.  On reprend le dbut de la premire boucle : initialisation de j 0.  On entre nouveau dans la deuxime boucle, o le processus est le mme que prcdemment (mais l, i vaut 1).  Enn, nous sortons des boucles et le programme termine son excution.

Le mme rsultat avec une boucle for


int premiersxomres a { {HDPDRDTDV}D{IDQDSDUDW} }Y for@int i a HY i ` PY iCCA { for@int j a HY j ` SY jCCA { ystemFoutFprint@premiersxomresijAY } ystemFoutFprintln@44AY }

Je vous avais parl d'une nouvelle syntaxe pour cette boucle, la voici :
tring t a {4toto4D 4titi4D 4tutu4D 4tete4D 4tt4}Y for@tring str X tA ystemFoutFprintln@strAY

Ceci signie qu' chaque tour de boucle, la valeur courante du tableau est mise dans la variable str. Vous constaterez que cette forme de boucle for est particulirement adapte aux parcours de tableaux ! Attention cependant, il faut imprativement que la variable passe en premier paramtre de la boucle for soit de mme type que la valeur de retour du tableau 2 .
2. Une variable de type String pour un tableau de String, un int pour un tableau d'int. . .

67

CHAPITRE 7. LES TABLEAUX Concernant les tableaux deux dimensions, que va retourner l'instruction de la premire boucle for ? Un tableau. Nous devrons donc faire une deuxime boucle an de parcourir ce dernier ! Voici un code qui permet d'acher un tableau deux dimensions de faon conventionnelle et selon la nouvelle version du JDK 1.5 3 :
tring ta{{4toto4D 4titi4D 4tutu4D 4tete4D 4tt4}D {4I4D 4P4D 4Q4D 4R4}}Y int i a HD j a HY for@tring sous X tA { i a HY for@tring str X sousA { ystemFoutFprintln@4v vleur de l nouvelle oule est X 4 C strAY ystemFoutFprintln@4v vleur du tleu l9indie 4CjC44CiC4 est X 4 C tjiAY iCCY } jCCY }

Je vous laisse le soin d'essayer ce code. Vous pourrez voir que nous rcuprons un tableau au cours de la premire boucle et parcourons ce mme tableau an de rcuprer les valeurs de celui-ci dans la deuxime. Simple, non ? En tout cas, je prfre nettement cette syntaxe ! Aprs, c'est vous de voir. . .

En rsum
 Un tableau est une variable contenant plusieurs donnes d'un mme type.  Pour dclarer un tableau, il faut ajouter des crochets [] la variable ou son type de dclaration.  Vous pouvez ajouter autant de dimensions votre tableau que vous le souhaitez, ceci en cumulant des crochets la dclaration.  Le premier lment d'un tableau est l'lment 0.  Vous pouvez utiliser la syntaxe du JDK 1.5 de la boucle for pour parcourir vos tableaux : for(String str : monTableauDeString) .

3. Cette syntaxe ne fonctionnera pas sur les versions antrieures JDK 1.5.

68

Chapitre

8
Dicult :

Les mthodes de classe

aintenant que vous commencez crire de vrais programmes, vous vous rendez srement compte qu'il y a certaines choses que vous eectuez souvent. Plutt que de recopier sans arrt les mmes morceaux de code, vous pouvez crire une mthode. . . Ce chapitre aura pour but de vous faire dcouvrir la notion de mthode (on l'appelle  fonction  dans d'autres langages). Vous en avez peut-tre dj utilis une lors du premier TP, vous vous en souvenez ? Vous avez pu voir qu'au lieu de retaper le code permettant d'arrondir un nombre dcimal, vous pouviez l'inclure dans une mthode et appeler celle-ci. Le principal avantage des mthodes est de pouvoir factoriser le code : grce elles, vous n'avez qu'un seul endroit o eectuer des modications lorsqu'elles sont ncessaires. J'espre que vous comprenez mieux l'intrt de tout cela, car c'est ce que nous allons aborder ici. Cependant, ce chapitre ne serait pas drle si nous ne nous amusions pas crer une ou deux mthodes pour le plaisir. . . Et l, vous aurez beaucoup de choses retenir !

69

CHAPITRE 8. LES MTHODES DE CLASSE

Quelques mthodes utiles


Vous l'aurez compris, il existe normment de mthodes dans le langage Java, prsentes dans des objets comme String : vous devrez les utiliser tout au long de cet ouvrage (et serez mme amens en modier le comportement). ce point du livre, vous pouvez catgoriser les mthodes en deux  familles  : les natives et les vtres.

Des mthodes concernant les chanes de caractres


toLowerCase()

Cette mthode permet de transformer tout caractre alphabtique en son quivalent minuscule. Elle n'a aucun eet sur les chires : ce ne sont pas des caractres alphabtiques. Vous pouvez donc l'utiliser sans problme sur une chane de caractres comportant des nombres. Elle s'emploie comme ceci :
tring hine a new tring@4gygy y vi wyxhi 34AD hineP a new tring@AY hineP a hineFtovowergse@AY GGhonne 4ouou tout le monde 34

toUpperCase()

Celle-l est simple, puisqu'il s'agit de l'oppos de la prcdente. Elle transforme donc une chane de caractres en capitales, et s'utilise comme suit :
tring hine a new tring@4ouou ouou4AD hineP a new tring@AY hineP a hineFtoppergse@AY GGhonne 4gygy gygy4

length()

Celle-ci renvoie la longueur d'une chane de caractres (en comptant les espaces).
tring hine a new tring@4ouou 3 4AY int longueur a HY longueur a hineFlength@AY GGenvoie W

equals() Cette mthode permet de vrier (donc de tester) si deux chanes de ca-

ractres sont identiques. C'est avec cette fonction que vous eectuerez vos tests de condition sur les String. Exemple concret :
tring strI a new tring@4ouou4AD strP a new tring@4toutou4AY if @strIFequls@strPAA ystemFoutFprintln@4ves deux hnes sont identiques 34AY else ystemFoutFprintln@4ves deux hnes sont diffrentes 34AY

Vous pouvez aussi demander la vrication de l'ingalit grce l'oprateur de ngation. . . Vous vous en souvenez ? Il s'agit de  ! . Cela nous donne : 70

QUELQUES MTHODES UTILES


tring strI a new tring@4ouou4AD strP a new tring@4toutou4AY if @3strIFequls@strPAA ystemFoutFprintln@4ves deux hnes sont diffrentes 34AY else ystemFoutFprintln@4ves deux hnes sont identiques 34AY

Ce genre de condition fonctionne de la mme faon pour les boucles. Dans l'absolu, cette fonction retourne un boolen, c'est pour cette raison que nous pouvons y recourir dans les tests de condition.
charAt()

Le rsultat de cette mthode sera un caractre : il s'agit d'une mthode d'extraction de caractre. Elle ne peut s'oprer que sur des String ! Par ailleurs, elle prsente la mme particularit que les tableaux, c'est--dire que, pour cette mthode, le premier caractre sera le numro 0. Cette mthode prend un entier comme argument.
tring nre a new tring@4IPQRSTU4AY hr r a nreFhret@RAY GGenverr ii le rtre S

substring()

Cette mthode extrait une partie d'une chane de caractres. Elle prend deux entiers en arguments : le premier dnit le premier caractre ( inclus) de la sous-chane extraire, le second correspond au dernier caractre ( exclu) extraire. L encore, le premier caractre porte le numro 0.
tring hine a new tring@4l pix nihe4AD hineP a new tring@AY hineP a hineFsustring@QDIQAY GGermet d9extrire 4pix nihe4

indexOf()  lastIndexOf() indexOf() explore une chane de caractres la recherche d'une suite donne de ca-

ractres, et renvoie la position (ou l'index) de la sous-chane passe en argument. indexOf() explore partir du dbut de la chane, lastIndexOf() explore en partant de la n, mais renvoie l'index partir du dbut de la chane. Ces deux mthodes prennent un caractre ou une chane de caractres comme argument, et renvoient un int. Tout comme charAt() et substring(), le premier caractre porte le numro 0. Je crois qu'ici, un exemple s'impose, plus encore que pour les autres fonctions :
tring mot a new tring@4ntionstitutionnellement4AY int n a HY n n n n n a a a a a motFindexyf@9t9AY motFlstsndexyf@9t9AY motFindexyf@4ti4AY motFlstsndexyf@4ti4AY motFindexyf@9x9AY GGn GGn GGn GGn GGn vut vut vut vut vut P PR P IP EI

71

CHAPITRE 8. LES MTHODES DE CLASSE

Des mthodes concernant les mathmatiques


Les mthodes listes ci-dessous ncessitent la classe Math, prsente dans java.lang. Elle fait donc partie des fondements du langage. Par consquent, aucun import particulier n'est ncessaire pour utiliser la classe Math qui regorge de mthodes utiles :
doule a HFHY a wthFrndom@AY GGetourne un nomre ltoire GGompris entre H et ID omme HFHHHIQVSURTQPWQUIHSV doule sin a wthFsin@IPHAY GGv fontion sinus doule os a wthFos@IPHAY GGv fontion osinus doule tn a wthFtn@IPHAY GGv fontion tngente doule s a wthFs@EIPHFPSAY GGv fontion vleur solue @retourne le nomre sns le signeA doule d a PY doule exp a wthFpow@dD PAY GGv fontion exposnt GGsiD on initilise l vrile exp ve l vleur de d leve u rr GGv mthode pow@A prend don une vleur en premier prmtreD GGet un exposnt en seond

Ces mthodes retournent toutes un nombre de type double. Je ne vais pas vous faire un rcapitulatif de toutes les mthodes prsentes dans Java, sinon j'y serai encore dans mille ans. . . Toutes ces mthodes sont trs utiles, croyezmoi. Cependant, les plus utiles sont encore celles que nous crivons nous-mmes ! C'est tellement mieux quand cela vient de nous. . .

Crer sa propre mthode


Voici un exemple de mthode que vous pouvez crire :
puli stti doule rrondi@doule eD int fA { return @douleA @ @intA @e B wthFpow@IHD fA C FSAA G wthFpow@IHD fAY }

Dcortiquons un peu cela


 Tout d'abord, il y a le mot cl public. C'est ce qui dnit la porte de la mthode, nous y reviendrons lorsque nous programmerons des objets.  Ensuite, il y a static. Nous y reviendrons aussi.  Juste aprs, nous voyons double. Il s'agit du type de retour de la mthode. Pour faire simple, ici, notre mthode va renvoyer un double !  Vient ensuite le nom de la mthode. C'est avec ce nom que nous l'appellerons.  Puis arrivent les arguments de la mthode . Ce sont en fait les paramtres dont la mthode a besoin pour travailler. Ici, nous demandons d'arrondir le double A avec B chires derrire la virgule. 72

CRER SA PROPRE MTHODE  Finalement, vous pouvez voir une instruction return l'intrieur de la mthode. C'est elle qui eectue le renvoi de la valeur, ici un double. Nous verrons dans ce chapitre les dirents types de renvoi ainsi que les paramtres que peut accepter une mthode. Vous devez savoir deux choses concernant les mthodes :  elles ne sont pas limites en nombre de paramtres ;  il en existe trois grands types :  les mthodes qui ne renvoient rien. Les mthodes de ce type n'ont pas d'instruction return, et elles sont de type void ;  les mthodes qui retournent des types primitifs ( double, int. . .). Elles sont de type double, int, char. . . Celles-ci possdent une instruction return ;  les mthodes qui retournent des objets. Par exemple, une mthode qui retourne un objet de type String. Celles-ci aussi comportent une instruction return. Jusque-l, nous n'avons crit que des programmes comportant une seule classe, ne disposant elle-mme que d'une mthode : la mthode main. Le moment est donc venu de crer vos propres mthodes. Que vous ayez utilis ou non la mthode arrondi dans votre TP, vous avez d voir que celle-ci se place l'extrieur de la mthode main, mais tout de mme dans votre classe ! Pour rappel, jetez un il la capture d'cran du TP 1 sur la gure 8.1.

Figure

8.1  Emplacement des mthodes


main

Si vous placez une de vos mthodes l'intrieur de la mthode l'extrieur de votre classe, le programme ne compilera pas.

ou

Puisque nous venons d'tudier les tableaux, nous allons crer des mthodes pour eux. Vous devez certainement vous souvenir de la faon de parcourir un tableau. . . Et si 73

CHAPITRE 8. LES MTHODES DE CLASSE nous faisions une mthode qui permet d'acher le contenu d'un tableau sans que nous soyons obligs de retaper la portion de code contenant la boucle ? Je me doute que vous n'en voyez pas l'intrt maintenant, car exception faite des plus courageux d'entre vous, vous n'avez utilis qu'un ou deux tableaux dans votre main du chapitre prcdent. Si je vous demande de dclarer vingt-deux tableaux et que je vous dis :  Allez, bande de Zros ! Parcourez-moi tout a ! , vous n'allez tout de mme pas crire vingt-deux boucles for ! De toute faon, je vous l'interdis. Nous allons crire une mthode. Celle-ci va :  prendre un tableau en paramtre ;  parcourir le tableau notre place ;  eectuer tous les System.out.println() ncessaires ;  ne rien renvoyer. Avec ce que nous avons dni, nous savons que notre mthode sera de type void et qu'elle prendra un tableau en paramtre. Voici un exemple de code complet :
puli lss dzI { puli stti void min@tring rgsA { tring t a {4toto4D 4tt4D 4titi4D 4tete4}Y prourirleu@tAY } stti void prourirleu@tring tfisA { for@tring str X tfisA ystemFoutFprintln@strAY }

Je sais que cela vous trouble encore, mais sachez que les mthodes ajoutes dans la classe main doivent tre dclares static. Fin du mystre dans la partie sur la programmation oriente objet !
Bon. Vous voyez que la mthode parcourt le tableau pass en paramtre. Si vous crez plusieurs tableaux et appelez la mthode sur ces derniers, vous vous apercevrez que la mthode ache le contenu de chaque tableau ! Voici un exemple ayant le mme eet que la mthode parcourirTableau, la dirence que celle-ci retourne une valeur : ici, ce sera une chane de caractres.
puli lss dzI { puli stti void min@tring rgsA { tring t a {4toto4D 4tt4D 4titi4D 4tete4}Y

74

LA SURCHARGE DE MTHODE
prourirleu@tAY ystemFoutFprintln@totring@tAAY

stti void prourirleu@tring tA { for@tring str X tA ystemFoutFprintln@strAY } stti tring totring@tring tA { ystemFoutFprintln@4wthode totring@A 3nEEEEEEEEEE4AY tring retour a 44Y for@tring str X tA retour Ca str C 4n4Y } return retourY

Vous voyez que la deuxime mthode retourne une chane de caractres, que nous devons acher l'aide de l'instruction System.out.println() . Nous achons la valeur renvoye par la mthode toString(). La mthode parcourirTableau, quant elle, crit au fur et mesure le contenu du tableau dans la console. Notez que j'ai ajout une ligne d'criture dans la console au sein de la mthode toString(), an de vous montrer o elle tait appele. Il nous reste un point important aborder. Imaginez un instant que vous ayez plusieurs types d'lments parcourir : des tableaux une dimension, d'autres deux dimensions, et mme des objets comme des ArrayList (nous les verrons plus tard, ne vous inquitez pas). Sans aller aussi loin, vous n'allez pas donner un nom dirent la mthode parcourirTableau pour chaque type primitif ! Vous avez d remarquer que la mthode que nous avons cre ne prend qu'un tableau de String en paramtre. Pas un tableau d' int ou de long, par exemple. Si seulement nous pouvions utiliser la mme mthode pour dirents types de tableaux. . . C'est l qu'entre en jeu ce qu'on appelle la surcharge.

La surcharge de mthode
La surcharge de mthode consiste garder le nom d'une mthode (donc un type de traitement faire : pour nous, lister un tableau) et changer la liste ou le type de ses paramtres. Dans le cas qui nous intresse, nous voulons que notre mthode parcourirTableau 75

CHAPITRE 8. LES MTHODES DE CLASSE puisse parcourir n'importe quel type de tableau. Nous allons donc surcharger notre mthode an qu'elle puisse aussi travailler avec des int, comme le montre cet exemple :
stti void prourirleu@tring tA { for@tring str X tA ystemFoutFprintln@strAY } stti void prourirleu@int tA { for@int str X tA ystemFoutFprintln@strAY }

Avec ces mthodes, vous pourrez parcourir de la mme manire :  les tableaux d'entiers ;  les tableaux de chanes de caractres. Vous pouvez faire de mme avec les tableaux deux dimensions. Voici quoi pourrait ressembler le code d'une telle mthode (je ne rappelle pas le code des deux mthodes ci-dessus) :
stti void prourirleu@tring tA { for@tring tP X tA { for@tring str X tPA ystemFoutFprintln@strAY } }

La surcharge de mthode fonctionne galement en ajoutant des paramtres la mthode. Cette mthode est donc valide :
stti void prourirleu@tring tD int iA { for@tring tP X tA { for@tring str X tPA ystemFoutFprintln@strAY } }

En fait, c'est la JVM qui va se charger d'invoquer l'une ou l'autre mthode : vous pouvez donc crer des mthodes ayant le mme nom, mais avec des paramtres dirents, en nombre ou en type. La machine virtuelle fait le reste. Ainsi, si vous avez bien dni toutes les mthodes ci-dessus, ce code fonctionne : 76

LA SURCHARGE DE MTHODE
tring ttr a {4toto4D 4titi4D 4tt4}Y int tsnt a {ID PD QD R}Y tring ttrP a {{4I4D 4P4D 4Q4D 4R4}D {4toto4D 4titi4D 4tt4}}Y GGv mthode ve un tleu de tring ser invoque prourirleu@ttrAY GGv mthode ve un tleu d9int ser invoque prourirleu@tsntAY GGv mthode ve un tleu de tring deux dimensions ser invoque prourirleu@ttrPAY

Vous venez de crer une mthode qui vous permet de centraliser votre code an de ne pas avoir retaper sans arrt les mmes instructions. Dans la partie suivante, vous apprendrez crer vos propres objets. Elle sera trs riche en informations, mais ne vous inquitez pas : nous apprendrons tout partir de zro. ;-)

En rsum
 Une mthode est un morceau de code rutilisable qui eectue une action bien dnie.  Les mthodes se dnissent dans une classe.  Les mthodes ne peuvent pas tre imbriques. Elles sont dclares les unes aprs les autres.  Une mthode peut tre surcharge en modiant le type de ses paramtres, leur nombre, ou les deux.  Pour Java, le fait de surcharger une mthode lui indique qu'il s'agit de deux, trois ou X mthodes direntes, car les paramtres d'appel sont dirents. Par consquent, Java ne se trompe jamais d'appel de mthode, puisqu'il se base sur les paramtres passs cette dernire.

77

CHAPITRE 8. LES MTHODES DE CLASSE

78

Deuxime partie
Java et la Programmation Oriente Objet

79

Chapitre

9
Dicult :

Votre premire classe

ans la premire partie de cet ouvrage sur la programmation en Java, nous avons travaill avec une seule classe. Vous allez apprendre qu'en faisant de la programmation oriente objet, nous travaillerons en fait avec de nombreuses classes. Rappelez-vous la premire partie : vous avez dj utilis des objets. . . Oui ! Lorsque vous faisiez ceci : String str = new String("tiens... un objet String"); Ici str est un objet String. Vous avez utilis un objet de la classe String : on dit que vous avez cr une instance de la classe String(). Le moment est venu pour vous de crer vos propres classes.

81

CHAPITRE 9. VOTRE PREMIRE CLASSE Commenons par une dnition. Une classe est une structure informatique reprsentant les principales caractristiques d'un lment du monde rel grce :  des variables, qui reprsentent les divers attributs de l'lment que vous souhaitez utiliser ;  des mthodes, qui permettent de dnir les comportements de vos lments. Une classe contient donc des variables et des mthodes, qui forment un tout. Voyons comment en crer une de toutes pices !

Structure de base
Une classe peut tre compare un moule qui, lorsque nous le remplissons, nous donne un objet ayant la forme du moule ainsi que toutes ses caractristiques. Comme quand vous tiez enfants, lorsque vous vous amusiez avec de la pte modeler. Si vous avez bien suivi la premire partie de ce livre, vous devriez savoir que notre classe contenant la mthode main ressemble ceci :
lss glssewin{ puli stti void min@tring rgsA{ GGos donnesD vrilesD diffrents tritementsFFF }GGpin de l mthode min }GGpin de votre lsse

Crez cette classe et cette mthode main (vous savez le faire, maintenant). Puisque nous allons faire de la POO 1 , nous allons crer une seconde classe dans ce fameux projet ! Crons sans plus tarder une classe Ville. Allez dans File/New/Class ou utilisez le raccourci dans la barre d'outils, comme sur la gure 9.1.

Figure

9.1  Nouvelle classe Java

Nommez votre classe : Ville 2 . Cette fois, vous ne devez pas y crer la mthode main.

Il ne peut y avoir qu'une seule mthode main active par projet ! Souvenezvous que celle-ci est le point de dpart de votre programme. Pour tre tout fait prcis, plusieurs mthodes main peuvent cohabiter dans votre projet, mais une seule sera considre comme le point de dpart de votre programme !
Au nal, vous devriez avoir le rendu de la gure 9.2.
1. Programmation Oriente Objet. 2. Avec un  V  : convention de nommage oblige !

82

LES CONSTRUCTEURS

Figure

9.2  Classe Ville

Ici, notre classe Ville est prcde du mot cl public. Vous devez savoir que lorsque nous crons une classe comme nous l'avons fait, Eclipse nous facilite la tche en ajoutant automatiquement ce mot cl, qui correspond la porte de la classe 3 . En programmation, la porte dtermine qui peut faire appel une classe, une mthode ou une variable. Vous avez dj rencontr la porte public : cela signie que tout le monde peut faire appel l'lment 4 . Nous allons ici utiliser une autre porte : private. Elle signie que notre mthode ne pourra tre appele que depuis l'intrieur de la classe dans laquelle elle se trouve ! Les mthodes dclares private correspondent souvent des mcanismes internes une classe que les dveloppeurs souhaitent  cacher  ou simplement ne pas rendre accessibles de l'extrieur de la classe. . .

Il en va de mme pour les variables. Nous allons voir que nous pouvons protger des variables grce au mot cl private. Le principe sera le mme que pour les mthodes. Ces variables ne seront alors accessibles que dans la classe o elles seront nes. . .
Bon. Toutes les conditions sont runies pour commencer activement la programmation oriente objet ! Et si nous allions crer notre premire ville ?

Les constructeurs
Vu que notre objectif dans ce chapitre est de construire un objet Ville, il va falloir dnir les donnes qu'on va lui attribuer. Nous dirons qu'un objet Ville possde :  un nom, sous la forme d'une chane de caractres ;  un nombre d'habitants, sous la forme d'un entier ;  un pays apparent, sous la forme d'une chane de caractres. Nous allons faire ceci en mettant des variables d'instance 5 dans notre classe. Celleci va contenir une variable dont le rle sera de stocker le nom, une autre stockera le
3. Retenez pour l'instant que public class UneClasse{} et class UneClasse{} sont presque quivalents ! 4. Ici dans le cas qui nous intresse il s'agit d'une mthode. Une mthode marque comme public peut donc tre appele depuis n'importe quel endroit du programme. 5. Ce sont de simples variables identiques celles que vous manipulez habituellement.

83

CHAPITRE 9. VOTRE PREMIRE CLASSE nombre d'habitants et la dernire se chargera du pays ! Voici quoi ressemble notre classe Ville prsent :
puli lss ille{ tring nomilleY tring nomysY int nreritntsY }

Contrairement aux classes, les variables d'instance prsentes dans une classe sont public si vous ne leur spciez pas de porte. Alors, on parle de variable d'instance, parce que dans nos futures classes Java qui dniront des objets, il y aura plusieurs types de variables (nous approfondirons ceci dans ce chapitre). Pour le moment, sachez qu'il y a trois grands types de variables dans une classe objet.  Les variables d'instance : ce sont elles qui dniront les caractristiques de notre objet.  Les variables de classe : celles-ci sont communes toutes les instances de votre classe.  Les variables locales : ce sont des variables que nous utiliserons pour travailler dans notre objet. Dans l'immdiat, nous allons travailler avec des variables d'instance an de crer des objets dirents. Il ne nous reste plus qu' crer notre premier objet, pour ce faire, nous allons devoir utiliser ce qu'on appelle des constructeurs. Un constructeur est une mthode d'instance qui va se charger de crer un objet et, le cas chant, d'initialiser ses variables de classe ! Cette mthode a pour rle de signaler la JVM 6 qu'il faut rserver de la mmoire pour notre futur objet et donc, par extension, d'en rserver pour toutes ses variables. Notre premier constructeur sera ce qu'on appelle communment un constructeur par dfaut, c'est--dire qu'il ne prendra aucun paramtre, mais permettra tout de mme d'instancier un objet, et vu que nous sommes perfectionnistes, nous allons y initialiser nos variables d'instance. Voici votre premier constructeur :
puli lss ille{ GGtoke le nom de notre ville tring nomilleY GGtoke le nom du pys de notre ville tring nomysY GGtoke le nomre d9hitnts de notre ville int nreritntsY GGgonstruteur pr dfut puli ille@A{ ystemFoutFprintln@4grtion d9une ville 34AY nomille a 4snonnu4Y nomys a 4snonnu4Y

6. Java Virtual Machine.

84

LES CONSTRUCTEURS
nreritnts a HY

Vous avez remarqu que le constructeur est en fait une mthode qui n'a aucun type de retour (void, double. . .) et qui porte le mme nom que notre classe ! Ceci est une rgle immuable : le (les) constructeur(s) d'une classe doit (doivent) porter le

mme nom que la classe !

Son corollaire est qu'un objet peut avoir plusieurs constructeurs. Il s'agit de la mme mthode, mais surcharge ! Dans notre premier constructeur, nous n'avons pass aucun paramtre, mais nous allons bientt en mettre. Vous pouvez d'ores et dj crer une instance de Ville. Cependant, commencez par vous rappeler qu'une instance d'objet se fait grce au mot cl new, comme lorsque vous crez une variable de type String. Maintenant, vu que nous allons crer des objets Ville, nous allons procder comme avec les String. Vrions que l'instanciation s'effectue comme il faut. Allons dans notre classe contenant la mthode main et instancions un objet Ville. Je suppose que vous avez devin que le type de notre objet sera Ville !
puli lss dzI{ puli stti void min@tring rgsA{ ille ville a new ille@AY } }

Excutez ce code, vous devriez avoir l'quivalent de la gure 9.3 sous les yeux.

Figure

9.3  Cration d'un objet Ville

Maintenant, nous devons mettre des donnes dans notre objet, ceci an de pouvoir commencer travailler. . . Le but sera de parvenir une dclaration d'objet se faisant comme ceci : 85

CHAPITRE 9. VOTRE PREMIRE CLASSE


ille villeI a new ille@4wrseille4D IPQRSTUVWD 4prne4AY

Vous avez remarqu qu'ici, les paramtres sont renseigns : eh bien il sut de crer une mthode qui rcupre ces paramtres et initialise les variables de notre objet, ce qui achvera notre constructeur d'initialisation. Voici le constructeur de notre objet Ville, celui qui permet d'avoir des objets avec des paramtres dirents :
puli lss ille { GGtoke le nom de notre ville tring nomilleY GGtoke le nom du pys de notre ville tring nomysY GGtoke le nomre d9hitnts de notre ville int nreritntsY GGgonstruteur pr dfut puli ille@A{ ystemFoutFprintln@4grtion d9une ville 34AY nomille a 4snonnu4Y nomys a 4snonnu4Y nreritnts a HY } GGgonstruteur ve prmtres GGt9i jout un  p en premire lettre des prmtresF GGge n9est ps une onventionD mis peut tre un on moyen de les reprerF puli ille@tring pxomD int pxreD tring pysA { ystemFoutFprintln@4grtion d9une ville ve des prmtres 34AY nomille a pxomY nomys a pysY nreritnts a pxreY }

Copier ce code Code web : 215266  Dans ce cas, l'exemple de dclaration et d'initialisation d'un objet Ville que je vous ai montr un peu plus haut fonctionne sans aucun souci ! Mais il vous faudra respecter scrupuleusement l'ordre des paramtres passs lors de l'initialisation de votre objet : sinon, c'est l'erreur de compilation coup sr ! Ainsi :
GGv9ordre est respet uun soui ille villeI a new ille@4wrseille4D IPQRSTUVWD 4prne4AY GGirreur dns l9ordre des prmtres erreur de ompiltion u finl ille villeP a new ille@IPRSTD 4prne4D 4ville4AY

86

LES CONSTRUCTEURS Par contre, notre objet prsente un gros dfaut : les variables d'instance qui le caractrisent sont accessibles dans votre classe contenant votre main ! Ceci implique que vous pouvez directement modier les attributs de la classe. Testez ce code et vous verrez que le rsultat est identique la gure 9.4 :
puli lss dzI { puli stti void min@tring rgsA { ille ville a new ille@AY ystemFoutFprintln@villeFnomilleAY villeFnomille a 4l tte toto 3 3 3 34Y ystemFoutFprintln@villeFnomilleAY ille villeP a new ille@4wrseille4D IPQRSTUVWD 4prne4AY villePFnomys a 4v tte tutu 3 3 3 3 4Y ystemFoutFprintln@villePFnomysAY

} }

Figure

9.4  Modication des donnes de notre objet

Vous constatez que nous pouvons accder aux variables d'instance en utilisant le  . , comme lorsque vous appelez la mthode subString() de l'objet String. C'est trs risqu, et la plupart des programmeurs Java vous le diront. Dans la majorit des cas, nous allons contrler les modications des variables de classe, de manire ce qu'un code extrieur ne fasse pas n'importe quoi avec nos objets ! En plus de a, imaginez que vous souhaitiez faire quelque chose chaque fois qu'une valeur change ; si vous ne protgez pas vos donnes, ce sera impossible raliser. . . C'est pour cela que nous protgeons nos variables d'instance en les dclarant private, comme ceci :
puli lss ille { privte tring nomilleY privte tring nomysY privte int nreritntsY

87

CHAPITRE 9. VOTRE PREMIRE CLASSE


GG FFF

Dsormais, ces attributs ne sont plus accessibles en dehors de la classe o ils sont dclars ! Nous allons maintenant voir comment accder tout de mme nos donnes.

Accesseurs et mutateurs
Un accesseur est une mthode qui va nous permettre d'accder aux variables de nos objets en lecture, et un mutateur nous permettra d'en faire de mme en criture ! Grce aux accesseurs, vous pourrez acher les variables de vos objets, et grce aux mutateurs, vous pourrez les modier :
puli lss ille { GGves vriles et les onstruteurs n9ont ps hngFFF GGBBBBBBBBBBBBB eggii BBBBBBBBBBBBB

GGetourne le nom de l ville puli tring getxom@A { return nomilleY } GGetourne le nom du pys puli tring getxomys@A { return nomysY } GG etourne le nomre d9hitnts puli int getxomreritnts@A { return nreritntsY } GGBBBBBBBBBBBBB wei BBBBBBBBBBBBB GGhfinit le nom de l ville puli void setxom@tring pxomA { nomille a pxomY } GGhfinit le nom du pys puli void setxomys@tring pysA { nomys a pysY } GGhfinit le nomre d9hitnts puli void setxomreritnts@int nreA {

88

ACCESSEURS ET MUTATEURS
nreritnts a nreY

Nos accesseurs sont bien des mthodes, et elles sont public pour que vous puissiez y accder depuis une autre classe que celle-ci : depuis le main, par exemple. Les accesseurs sont du mme type que la variable qu'ils doivent retourner. Les mutateurs sont, par contre, de type void. Ce mot cl signie  rien  ; en eet, ces mthodes ne retournent aucune valeur, elles se contentent de les mettre jour.

Je vous ai fait faire la dirence entre accesseurs et mutateurs, mais gnralement, lorsqu'on parle d'accesseurs, ce terme inclut galement les mutateurs. Autre chose : il s'agit ici d'une question de convention de nommage. Les accesseurs commencent par get et les mutateurs par set, comme vous pouvez le voir ici. On parle d'ailleurs parfois de Getters et de Setters.
prsent, essayez ce code dans votre mthode main :
ille v a new ille@AY ille vI a new ille@4wrseille4D IPQRSTD 4prne4AY ille vP a new ille@4io4D QPITSRD 4frsil4AY ystemFoutFprintln@4n v a 4CvFgetxom@AC4 ville de 4CvFgetxomreritnts@AC 4 hitnts se situnt en 4CvFgetxomys@AAY ystemFoutFprintln@4 vI a 4CvIFgetxom@AC4 ville de 4CvIFgetxomreritnts@AC 4 hitnts se situnt en 4CvIFgetxomys@AAY ystemFoutFprintln@4 vP a 4CvPFgetxom@AC4 ville de 4CvPFgetxomreritnts@AC 4 hitnts se situnt en 4CvPFgetxomys@AC4nn4AY GB xous llons interhnger les illes vI et vP tout pr l9intermdiire d9un utre ojet illeF

BG ille temp a new ille@AY temp a vIY vI a vPY vP a tempY

ystemFoutFprintln@4 vI a 4CvIFgetxom@AC4 ville de 4CvIFgetxomreritnts@AC 4 hitnts se situnt en 4CvIFgetxomys@AAY ystemFoutFprintln@4 vP a 4CvPFgetxom@AC4 ville de 4CvPFgetxomreritnts@AC 4 hitnts se situnt en 4CvPFgetxomys@AC4nn4AY GB xous llons mintennt interhnger leurs noms ette fois pr le iis de leur esseursF BG vIFsetxom@4rong uong4AY

89

CHAPITRE 9. VOTRE PREMIRE CLASSE


vPFsetxom@4hjiouti4AY ystemFoutFprintln@4 vI a 4CvIFgetxom@AC4 4CvIFgetxomreritnts@AC 4 hitnts ystemFoutFprintln@4 vP a 4CvPFgetxom@AC4 4CvPFgetxomreritnts@AC 4 hitnts 4CvPFgetxomys@AC4nn4AY ville de se situnt en 4CvIFgetxomys@AAY ville de se situnt en

la compilation, vous devriez obtenir la gure 9.5.

Figure

9.5  Essai des accesseurs

Vous voyez bien que les constructeurs ont fonctionn, que les accesseurs tournent merveille et que vous pouvez commencer travailler avec vos objets Ville. Par contre, pour acher le contenu, on pourrait faire plus simple, comme par exemple crer une mthode qui se chargerait de faire tout ceci. . . Je sais ce que vous vous dites :  Mais les accesseurs, ce ne sont pas des mthodes ? . Bien sr que si, mais il vaut mieux bien distinguer les dirents types de mthodes dans un objet :  les constructeurs mthodes servant crer des objets ;  les accesseurs mthodes servant accder aux donnes des objets ;  les mthodes d'instance mthodes servant la gestion des objets. Avec nos objets Ville, notre choix est un peu limit par le nombre de mthodes possibles, mais nous pouvons tout de mme en faire une ou deux pour l'exemple :  faire un systme de catgories de villes par rapport leur nombre d'habitants ( <1000 A, <10 000 B. . .). Ceci est dtermin la construction ou la rednition du nombre d'habitants : ajoutons donc une variable d'instance de type char notre classe et appelons-la categorie. Pensez ajouter le traitement aux bons endroits ;  faire une mthode de description de notre objet Ville ;  une mthode pour comparer deux objets par rapport leur nombre d'habitants.

Nous voulons que la classe Ville gre la faon de dterminer la catgorie ellemme, et non que cette action puisse tre opre de l'extrieur. La mthode qui fera ceci sera donc dclare private.
90

ACCESSEURS ET MUTATEURS Par contre, un problme va se poser ! Vous savez dj qu'en Java, on appelle les mthodes d'un objet comme ceci : monString.subString(0,4); . Cependant, vu qu'il va falloir qu'on travaille depuis l'intrieur de notre objet, vous allez encore avoir un mot cl retenir. . . Cette fois, il s'agit du mot cl this. Voici tout d'abord le code de notre classe Ville en entier, c'est--dire comportant les mthodes dont on vient de parler :


La classe Ville Code web : 570853 

puli lss ille { privte privte privte privte tring nomilleY tring nomysY int nreritntsY hr tegorieY

puli ille@A{ ystemFoutFprintln@4grtion d9une ville 34AY nomille a 4snonnu4Y nomys a 4snonnu4Y nreritnts a HY thisFsetgtegorie@AY } puli ille@tring pxomD int pxreD tring pysA { ystemFoutFprintln@4grtion d9une ville ve des prmtres 34AY nomille a pxomY nomys a pysY nreritnts a pxreY thisFsetgtegorie@AY } GGetourne le nom de l ville puli tring getxom@A { return nomilleY } GGetourne le nom du pys puli tring getxomys@A { return nomysY } GG etourne le nomre d9hitnts puli int getxomreritnts@A { return nreritntsY } GGetourne l tgorie de l ville puli hr getgtegorie@A

91

CHAPITRE 9. VOTRE PREMIRE CLASSE


{ }

return tegorieY

GGhfinit le nom de l ville puli void setxom@tring pxomA { nomille a pxomY } GGhfinit le nom du pys puli void setxomys@tring pysA { nomys a pysY } GGhfinit le nomre d9hitnts puli void setxomreritnts@int nreA { nreritnts a nreY thisFsetgtegorie@AY } GGhfinit l tgorie de l ville privte void setgtegorie@A { int ornesuperieures a {HD IHHHD IHHHHD IHHHHHD SHHHHHD IHHHHHHD SHHHHHHD IHHHHHHH}Y hr tegories a {9c9D 9e9D 9f9D 9g9D 9h9D 9i9D 9p9D 9q9D 9r9}Y int i a HY while @i ` ornesuperieuresFlength 88 thisFnreritnts ba ornesuperieuresiA iCCY } thisFtegorie a tegoriesiY ville est une ville de 4CthisFnomysC X 4CthisFnreritntsC elle est don de tgorie X 4CthisFtegorieY

GGetourne l desription de l puli tring derisoi@A{ return 4t4CthisFnomilleC4 4D elle omporte 4 hitnt@sA ab }

GGetourne une hne de rtres selon le rsultt de l omprison puli tring omprer@ille vIA{ tring str a new tring@AY if @vIFgetxomreritnts@A b thisFnreritntsA str a vIFgetxom@AC4 est une ville plus peuple que 4CthisFnomilleY

92

ACCESSEURS ET MUTATEURS

else

str a thisFnomilleC4 est une ville plus peuple que 4CvIFgetxom@AY

return strY

Pour simplier, this 7 fait rfrence l'objet courant !


Pour expliciter le fonctionnement du mot cl this, prenons l'exemple de la mthode comparer(Ville V1). La mthode va s'utiliser comme suit :
ille a new ille@4vyon4D TSRD 4prne4AY ille P a new ille@4ville4D IPQD 4prne4AY Fomprer@PAY

Dans cette mthode, nous voulons comparer le nombre d'habitants de chacun des deux objets Ville. Pour accder la variable nbreHabitants de l'objet V2, il sut d'utiliser la syntaxe V2.getNombreHabitants() ; nous ferons donc rfrence la proprit nbreHabitants de l'objet V2. Mais l'objet V, lui, est l'objet appelant de cette mthode. Pour se servir de ses propres variables, on utilise alors this.nbreHabitants, ce qui a pour eet de faire appel la variable nbreHabitants de l'objet excutant la mthode comparer(Ville V). Explicitons un peu les trois mthodes qui ont t dcrites prcdemment.

La mthode categorie()
Elle ne prend aucun paramtre, et ne renvoie rien : elle se contente de mettre la variable de classe categorie jour. Elle dtermine dans quelle tranche se trouve la ville grce au nombre d'habitants de l'objet appelant, obtenu au moyen du mot cl this. Selon le nombre d'habitants, le caractre renvoy changera. Nous l'appelons lorsque nous construisons un objet Ville (que ce soit avec ou sans paramtre), mais aussi lorsque nous rednissons le nombre d'habitants : de cette manire, la catgorie est automatiquement mise jour, sans qu'on ait besoin de faire appel la mthode.

La mthode decrisToi()
Celle-ci nous renvoie un objet de type String. Elle fait rfrence aux variables qui composent l'objet appelant la mthode, toujours grce this, et nous renvoie donc
7. Bien que la traduction anglaise exacte soit  ceci , il faut comprendre  moi . l'intrieur d'un objet, ce mot cl permet de dsigner une de ses variables ou une de ses mthodes.

93

CHAPITRE 9. VOTRE PREMIRE CLASSE une chane de caractres qui nous dcrit l'objet en numrant ses composants.

La mthode comparer(Ville V1)


Elle prend une ville en paramtre, pour pouvoir comparer les variables nbreHabitants de l'objet appelant la mthode et de celui pass en paramtre pour nous dire quelle ville est la plus peuple ! Et si nous faisions un petit test ?
ille v a new ille@AY ille vI a new ille@4wrseille4D IPQTD 4prne4AY ille vP a new ille@4io4D QPITSRD 4frsil4AY ystemFoutFprintln@4nn4CvIFderisoi@AAY ystemFoutFprintln@vFderisoi@AAY ystemFoutFprintln@vPFderisoi@AC4nn4AY ystemFoutFprintln@vIFomprer@vPAAY

Ce qui devrait donner le rsultat de la gure 9.6.

Figure

9.6  Test des mthodes

Je viens d'avoir une ide : et si nous essayions de savoir combien de villes nous avons cres ? Comment faire ? Avec une variable de classe !

Les variables de classes


Comme je vous le disais au dbut de ce chapitre, il y a plusieurs types de variables dans une classe. Nous avons vu les variables d'instance qui forment la carte d'identit d'un objet ; maintenant, voici les variables de classe. Celles-ci peuvent s'avrer trs utiles. Dans notre exemple, nous allons compter le nombre d'instances de notre classe Ville, mais nous pourrions les utiliser pour bien d'autres choses (un taux de TVA dans une classe qui calcule le prix TTC, par exemple). La particularit de ce type de variable, c'est qu'elles seront communes toutes les instances de la classe ! Crons sans plus attendre notre compteur d'instances. Il s'agira d'une variable de type int que nous appellerons nbreInstance, et qui sera public ; nous mettrons aussi son homologue en private en place et l'appellerons nbreInstanceBis (il sera ncessaire de mettre un accesseur en place pour cette variable). An qu'une variable soit une 94

LES VARIABLES DE CLASSES variable de classe, elle doit tre prcde du mot cl static. Cela donnerait dans notre classe Ville :
puli lss ille { GGriles puliques qui omptent les instnes puli stti int nresnstnes a HY GGrile prive qui ompter ussi les instnes privte stti int nresnstnesfis a HY GGves utres vriles n9ont ps hng puli ille@A{ GGyn inrmente nos vriles hque ppel ux onstruteurs nresnstnesCCY nresnstnesfisCCY GGve reste ne hnge psF } puli ille@tring pxomD int pxreD tring pysA { GGyn inrmente nos vriles hque ppel ux onstruteurs nresnstnesCCY nresnstnesfisCCY GGve reste ne hnge ps } puli stti int getxomresnstnesfis@A { return nresnstnesfisY } GGve reste du ode est le mme qu9vnt

Vous avez d remarquer que l'accesseur de notre variable de classe dclare prive est aussi dclar static : ceci est une rgle ! Toutes les mthodes de classe n'utilisant que des variables de classe doivent tre dclares static. On les appelle des mthodes de classe, car il n'y en a qu'une pour toutes vos instances. Par contre ce n'est plus une mthode de classe si celle-ci utilise des variables d'instance en plus de variables de classe. . . prsent, si vous testez le code suivant, vous allez constater l'utilit des variables de classe :
ille v a new ille@AY ystemFoutFprintln@4ve nomre d9instnes de l lsse ille est X 4 C illeFnresnstnesAY ystemFoutFprintln@4ve nomre d9instnes de l lsse ille est X 4 C illeFgetxomresnstnesfis@AAY ille vI a new ille@4wrseille4D IPQTD 4prne4AY

95

CHAPITRE 9. VOTRE PREMIRE CLASSE


ystemFoutFprintln@4ve nomre d9instnes de l lsse ille est X 4 C illeFnresnstnesAY ystemFoutFprintln@4ve nomre d9instnes de l lsse ille est X 4 C illeFgetxomresnstnesfis@AAY ille vP a new ille@4io4D QPITSRD 4frsil4AY ystemFoutFprintln@4ve nomre d9instnes de l lsse ille est X 4 C illeFnresnstnesAY ystemFoutFprintln@4ve nomre d9instnes de l lsse ille est X 4 C illeFgetxomresnstnesfis@AAY

Le rsultat en gure 9.7 montre que le nombre augmente chaque instanciation.

Figure

9.7  Utilisation de variables de classe

Lorsque vous avez vu les mthodes, vous les avez dclares public. Vous auriez galement pu les dclarer private, mais attention, dans les deux cas, il faut aussi qu'elles soient static, car elles sont excutes dans un contexte static : la mthode main.

Le principe d'encapsulation
Voil, vous venez de construire votre premier objet  maison . Cependant, sans le savoir, vous avez fait plus que a : vous avez cr un objet dont les variables sont protges de l'extrieur. En eet, depuis l'extrieur de la classe, elles ne sont accessibles que via les accesseurs et mutateurs que nous avons dni. C'est le principe d'encapsulation ! En fait, lorsqu'on procde de la sorte, on s'assure que le fonctionnement interne l'objet est intgre, car toute modication d'une donne de l'objet est matrise. Nous avons dvelopp des mthodes qui s'assurent qu'on ne modie pas n'importe comment les variables. Prenons l'exemple de la variable nbreHabitants. L'encapsuler nous permet, lors de son aectation, de dduire automatiquement la catgorie de l'objet Ville, chose qui n'est pas facilement faisable sans encapsulation. Par extension, si vous avez besoin d'eectuer des oprations dtermines lors de l'aectation du nom d'une ville par exemple, vous n'aurez pas passer en revue tous les codes source utilisant l'objet Ville : vous n'aurez qu' modier l'objet (ou la mthode) en question, et le tour sera jou. Si vous vous demandez l'utilit de tout cela, dites-vous que vous ne serez peut-tre pas seuls dvelopper vos logiciels, et que les personnes utilisant vos classes n'ont pas 96

LE PRINCIPE D'ENCAPSULATION savoir ce qu'il s'y passe : seules les fonctionnalits qui leurs sont oertes comptent. Vous le verrez en continuant la lecture de cet ouvrage, Java est souple parce qu'il ore beaucoup de fonctionnalits pouvant tre retravailles selon les besoins, mais gardez l'esprit que certaines choses vous seront volontairement inaccessibles, pour viter que vous ne  cassiez  quelque chose.

En rsum
 Une classe permet de dnir des objets. Ceux-ci ont des attributs (variables d'instance) et des mthodes (mthodes d'instance + accesseurs).  Les objets permettent d'encapsuler du code et des donnes.  Le ou les constructeurs d'une classe doivent porter le mme nom que la classe et n'ont pas de type de retour.  L'ordre des paramtres passs dans le constructeur doit tre respect.  Il est recommand de dclarer ses variables d'instance private, pour les protger d'une mauvaise utilisation par le programmeur.  On cre des accesseurs et mutateurs (mthodes getters et setters) pour permettre une modication sre des variables d'instance.  Dans une classe, on accde aux variables de celle-ci grce au mot cl this.  Une variable de classe est une variable devant tre dclare static.  Les mthodes n'utilisant que des variables de classe doivent elles aussi tre dclares static.  On instancie un nouvel objet grce au mot cl new.

97

CHAPITRE 9. VOTRE PREMIRE CLASSE

98

Chapitre

10
Dicult :

L'hritage

e vous arrte tout de suite, vous ne toucherez rien. Pas de rapport d'argent entre nous. . . :-) Non, la notion d'hritage en programmation est dirente de celle que vous connaissez, bien qu'elle en soit tout de mme proche. C'est l'un des fondements de la programmation oriente objet ! Imaginons que, dans le programme ralis prcdemment, nous voulions crer un autre type d'objet : des objets Capitale. Ceux-ci ne seront rien d'autre que des objets Ville avec un paramtre en plus. . . disons un monument. Vous n'allez tout de mme pas recoder tout le contenu de la classe Ville dans la nouvelle classe ! Dj, ce serait vraiment contraignant, mais en plus, si vous aviez modier le fonctionnement de la catgorisation de nos objets Ville, vous auriez aussi eectuer la modication dans la nouvelle classe. . . Ce n'est pas terrible. Heureusement, l'hritage permet des objets de fonctionner de la mme faon que d'autres.

99

CHAPITRE 10. L'HRITAGE

Le principe de l'hritage
Comme je vous l'ai dit dans l'introduction, la notion d'hritage est l'un des fondements de la programmation oriente objet. Grce elle, nous pourrons crer des classes hrites 1 de nos classes mres 2 . Nous pourrons crer autant de classes drives, par rapport notre classe de base, que nous le souhaitons. De plus, nous pourrons nous servir d'une classe drive comme d'une classe de base pour laborer encore une autre classe drive. Reprenons l'exemple dont je vous parlais dans l'introduction. Nous allons crer une nouvelle classe, nomme Capitale, hrite de Ville. Vous vous rendrez vite compte que les objets Capitale auront tous les attributs et toutes les mthodes associs aux objets Ville !
lss gpitle extends ille { }

C'est le mot cl extends qui informe Java que la classe Capitale est hrite de Ville. Pour vous le prouver, essayez ce morceau de code dans votre main :
gpitle p a new gpitle@AY ystemFoutFprintln@pFderisoi@AAY

Vous devriez avoir la gure 10.1 en guise de rendu.

Figure

10.1  Objet Capitale

C'est bien la preuve que notre objet Capitale possde les proprits de notre objet Ville. Les objets hrits peuvent accder toutes les mthodes public 3 de leur classe mre, dont la mthode decrisToi() dans le cas qui nous occupe. En fait, lorsque vous dclarez une classe, si vous ne spciez pas de constructeur, le compilateur 4 crera, au moment de l'interprtation, le constructeur par dfaut. En revanche, ds que vous avez cr un constructeur, n'importe lequel, la JVM ne cre plus le constructeur par dfaut. Notre classe Capitale hrite de la classe Ville, par consquent, le constructeur de notre objet appelle, de faon tacite, le constructeur de la classe mre. C'est pour cela que les variables d'instance ont pu tre initialises ! Par contre, essayez ceci dans votre classe :
1. 2. 3. 4. Les classes hrites sont aussi appeles classes drives. Les classes mres sont aussi appeles classes de base. Ce n'est pas tout fait vrai. . . Nous le verrons avec le mot cl protected. Le compilateur est le programme qui transforme vos codes sources en byte code.

100

LE PRINCIPE DE L'HRITAGE
puli lss gpitle extends ille{ puli gpitle@A{ thisFnomille a 4toto4Y } }

Vous allez avoir une belle erreur de compilation ! Dans notre classe Capitale, nous ne pouvons pas utiliser directement les attributs de la classe Ville. Pourquoi cela ? Tout simplement parce les variables de la classe Ville sont dclares private. C'est ici que le nouveau mot cl protected fait son entre. En fait, seules les mthodes et les variables dclares public ou protected peuvent tre utilises dans une classe hrite ; le compilateur rejette votre demande lorsque vous tentez d'accder des ressources prives d'une classe mre ! Remplacer private par protected dans la dclaration de variables ou de mthodes de la classe Ville aura pour eet de les protger des utilisateurs de la classe tout en permettant aux objets enfants d'y accder. Donc, une fois les variables et mthodes prives de la classe mre dclares en protected, notre objet Capitale aura accs celles-ci ! Ainsi, voici la dclaration de nos variables dans notre classe Ville revue et corrige :
puli lss ille { puli stti int nresnstnes a HY proteted stti int nresnstnesfis a HY proteted tring nomilleY proteted tring nomysY proteted int nreritntsY proteted hr tegorieY } GGout le reste est identiqueF

Notons un point important avant de continuer. Contrairement au C++, Java ne gre pas les hritages multiples : une classe drive 5 ne peut hriter que d'une seule classe mre ! Vous n'aurez donc jamais ce genre de classe :
lss egrfeusefionique extends egrfeuseeirgomprimeD egrfeusewnuelle{ }

La raison est toute simple : si nous admettons que nos classes AgrafeuseAirComprime et AgrafeuseManuelle ont toutes les deux une mthode agrafer() et que vous ne rednissez pas cette mthode dans l'objet AgrafeuseBionique, la JVM ne saura pas quelle mthode utiliser et, plutt que de forcer le programmeur grer les cas d'erreur, les concepteurs du langage ont prfr interdire l'hritage multiple.
5. Je rappelle qu'une classe drive est aussi appele classe lle.

101

CHAPITRE 10. L'HRITAGE prsent, continuons la construction de notre objet hrit : nous allons agrmenter notre classe Capitale. Comme je vous l'avais dit, ce qui direnciera nos objets Capitale de nos objets Ville sera la prsence d'un nouveau champ : le nom d'un monument. Cela implique que nous devons crer un constructeur par dfaut et un constructeur d'initialisation pour notre objet Capitale. Avant de foncer tte baisse, il faut que vous sachiez que nous pouvons faire appel aux variables de la classe mre dans nos constructeurs grce au mot cl super. Cela aura pour eet de rcuprer les lments de l'objet de base, et de les envoyer notre objet hrit. Dmonstration :
lss gpitle extends ille { privte tring monumentY GGgonstruteur pr dfut puli gpitle@A{ GGge mot l ppelle le onstruteur de l lsse mre super@AY monument a 4uun4Y }

Si vous essayez nouveau le petit exemple que je vous avais montr un peu plus haut, vous vous apercevrez que le constructeur par dfaut fonctionne toujours. . . Et pour cause : ici, super() appelle le constructeur par dfaut de l'objet Ville dans le constructeur de Capitale. Nous avons ensuite ajout un monument par dfaut. Cependant, la mthode decrisToi() ne prend pas en compte le nom d'un monument. . . Eh bien le mot cl super() fonctionne aussi pour les mthodes de classe, ce qui nous donne une mthode decrisToi() un peu dirente, car nous allons lui ajouter le champ president pour notre description :
lss gpitle extends ille { privte tring monumentY puli gpitle@A{ GGge mot l ppelle le onstruteur de l lsse mre super@AY monument a 4uun4Y } puli tring derisoi@A{ tring str a superFderisoi@A C 4n t aabb4 C thisFmonumentC 4 en est un monument4Y ystemFoutFprintln@4snvotion de superFderisoi@A4AY ystemFoutFprintln@superFderisoi@AAY return strY }

102

LE PRINCIPE DE L'HRITAGE Si vous relancez les instructions prsentes dans le main depuis le dbut, vous obtiendrez quelque chose comme sur la gure 10.2.

Figure

10.2  Utilisation de super

J'ai ajout les instructions System.out.println an de bien vous montrer comment les choses se passent. Bon, d'accord : nous n'avons toujours pas fait le constructeur d'initialisation de Capitale. Eh bien ? Qu'attendons-nous ?
puli lss gpitle extends ille { privte tring monumentY GGgonstruteur pr dfut puli gpitle@A{ GGge mot l ppelle le onstruteur de l lsse mre super@AY monument a 4uun4Y } GGgonstruteur d9initilistion de pitle puli gpitle@tring nomD int hD tring pysD tring monumentA{ super@nomD hD pysAY thisFmonument a monumentY } GBB B hesription d9une pitle B dreturn tring retourne l desription de l9ojet BG puli tring derisoi@A{ tring str a superFderisoi@A C 4n t aabb4 C thisFmonument C 4en est un monument4Y return strY } GBB B dreturn le nom du monument BG puli tring getwonument@A { return monumentY } GGhfinit le nom du monument

103

CHAPITRE 10. L'HRITAGE


puli void setwonument@tring monumentA { thisFmonument a monumentY }

Copier ce code Code web : 403242 

Les commentaires que vous pouvez voir sont ce que l'on appelle des commentaires JavaDoc 6 : ils permettent de crer une documentation pour votre code. Vous pouvez faire le test avec Eclipse en allant dans le menu Project/Generate JavaDoc .
Dans le constructeur d'initialisation de notre Capitale, vous remarquez la prsence de super(nom, hab, pays); . Dicile de ne pas le voir. . . Cette ligne de code joue le mme rle que celui que nous avons prcdemment vu avec le constructeur par dfaut. Sauf qu'ici, le constructeur auquel super fait rfrence prend trois paramtres : ainsi, super doit prendre ces paramtres. Si vous ne lui mettez aucun paramtre, super() renverra le constructeur par dfaut de la classe Ville. Testez le code ci-dessous, il aura pour rsultat la gure 10.3.
gpitle p a new gpitle@4ris4D TSRWVUD 4prne4D 4l tour iiffel4AY ystemFoutFprintln@4n4CpFderisoi@AAY

Figure

10.3  Classe Capitale avec constructeur

Je vais vous interpeller une fois de plus : vous venez de faire de la mthode decrisToi() une mthode polymorphe, ce qui nous conduit sans dtour ce qui suit.

Le polymorphisme
Voici encore un des concepts fondamentaux de la programmation oriente objet : le polymorphisme. Ce concept complte parfaitement celui de l'hritage, et vous allez voir que le polymorphisme est plus simple qu'il n'y parat. Pour faire court, nous pouvons le dnir en disant qu'il permet de manipuler des objets sans vraiment connatre leur type.
6. Souvenez-vous, je vous en ai parl dans le tout premier chapitre de ce livre.

104

LE POLYMORPHISME Dans notre exemple, vous avez vu qu'il susait d'utiliser la mthode decrisToi() sur un objet Ville ou sur un objet Capitale. On pourrait construire un tableau d'objets et appeler decrisToi() sans se soucier de son contenu : villes, capitales, ou les deux. D'ailleurs, nous allons le faire. Essayez ce code :
GGhfinition d9un tleu de villes null ille tleu a new illeTY GGhfinition d9un tleu de noms de villes et un utre de nomres d9hitnts tring t a {4wrseille4D 4lille4D 4en4D 4lyon4D 4pris4D 4nntes4}Y int tP a {IPQRSTD UVRSTD TSRWVUD USVQPITSD ISWRD PIQ}Y GGves trois premiers lments du tleu seront des villesD GGet le resteD des pitles for@int i a HY i ` TY iCCA{ if @i `QA{ ille a new ille@tiD tPiD 4frne4AY tleui a Y } else{ gpitle g a new gpitle@tiD tPiD 4frne4D 4l tour iiffel4AY tleui a gY }

GGsl ne nous reste plus qu9 drire tout notre tleu 3 for@ille v X tleuA{ ystemFoutFprintln@vFderisoi@AC4n4AY }

Copier ce code Code web : 269087  Rsultat : la gure 10.4. Nous crons un tableau de villes contenant des villes et des capitales 7 grce notre premire boucle for. Dans la seconde, nous achons la description de ces objets. . . et vous voyez que la mthode polymorphe decrisToi() fait bien son travail ! Vous aurez sans doute remarqu que je n'utilise que des objets Ville dans ma boucle : on appelle ceci la covariance des variables ! Cela signie qu'une variable objet peut contenir un objet qui hrite du type de cette variable. Dans notre cas, un objet de type Ville peut contenir un objet de type Capitale. Dans ce cas, on dit que Ville est la superclasse de Capitale. La covariance est ecace dans le cas o la classe hritant rednit certaines mthodes de sa superclasse.
7. Nous avons le droit de faire a, car les objets Capitale sont aussi des objets Ville.

105

CHAPITRE 10. L'HRITAGE

Figure

10.4  Test de polymorphisme

Attention ne pas confondre la surcharge de mthode avec une mthode polymorphe.


 Une mthode surcharge dire de la mthode originale par le nombre ou le type des paramtres qu'elle prend en entre.  Une mthode polymorphe a un squelette identique la mthode de base, mais traite les choses diremment. Cette mthode se trouve dans une autre classe et donc, par extension, dans une autre instance de cette autre classe. Vous devez savoir encore une chose sur l'hritage. Lorsque vous crez une classe ( Ville, par exemple), celle-ci hrite, de faon tacite, de la classe Object prsente dans Java. Toutes nos classes hritent donc des mthodes de la classe Object, comme equals() qui prend un objet en paramtre et qui permet de tester l'galit d'objets. Vous vous en tes d'ailleurs servis pour tester l'galit de String() dans la premire partie de ce livre. Donc, en rednissant une mthode de la classe Object dans la classe Ville, nous pourrions utiliser la covariance. La mthode de la classe Object la plus souvent rednie est toString() : elle retourne un String dcrivant l'objet en question (comme notre mthode decrisToi()). Nous allons donc copier la procdure de la mthode decrisToi() dans une nouvelle mthode de la classe Ville : toString(). Voici son code :
puli tring totring@A{ return 4t4CthisFnomilleC4 est une ville de 4CthisFnomysC 4D elle omporte X 4CthisFnreritntC 4 ab elle est don de tgorie X 4CthisFtegorieY }

Nous faisons de mme dans la classe Capitale :


puli tring totring@A{

106

LE POLYMORPHISME
tring str a superFtotring@A C 4n t aabb4 C thisFmonument C 4 en est un monument4Y return strY

Maintenant, testez ce code :


GGhfinition d9un tleu de villes null ille tleu a new illeTY GGhfinition d9un tleu de noms de illes et un utre de nomres d9hitnts tring t a {4wrseille4D 4lille4D 4en4D 4lyon4D 4pris4D 4nntes4}Y int tP a {IPQRSTD UVRSTD TSRWVUD USVQPITSD ISWRD PIQ}Y GGves trois premiers lments du tleu seront des illes GGet le reste des pitles for@int i a HY i ` TY iCCA{ if @i `QA{ ille a new ille@tiD tPiD 4frne4AY tleui a Y } else{ gpitle g a new gpitle@tiD tPiD 4frne4D 4l tour iiffel4AY tleui a gY }

GGsl ne nous reste plus qu9 drire tout notre tleu 3 for@yjet oj X tleuA{ ystemFoutFprintln@ojFtotring@AC4n4AY }

Vous pouvez constater qu'il fait exactement la mme chose que le code prcdent ; nous n'avons pas nous soucier du type d'objet pour acher sa description. Je pense que vous commencez entrevoir la puissance de Java !

Attention : si vous ne rednissez pas ou ne  polymorphez  pas la mthode d'une classe mre dans une classe lle (exemple de toString()), l'appel de celle-ci avec un objet lle, c'est la mthode de la classe mre qui sera invoque !
Une prcision s'impose : si vous avez un objet v de type Ville, par exemple, que vous n'avez pas redni la mthode toString() et que vous testez ce code :
ystemFoutFprintln@vAY

. . . vous appellerez automatiquement la mthode toString() de la classe Object ! Mais 107

CHAPITRE 10. L'HRITAGE ici, comme vous avez redni la mthode toString() dans votre classe Ville, ces deux instructions sont quivalentes :
ystemFoutFprintln@vFtotring@AAY GGist quivlent ystemFoutFprintln@vAY

Pour plus de clart, je conserverai la premire syntaxe, mais il est utile de connatre cette alternative. Pour clarier un peu tout a, vous avez accs aux mthodes public et protected de la classe Object ds que vous crez une classe objet (grce l'hritage tacite). Vous pouvez donc utiliser lesdites mthodes ; mais si vous ne les rednissez pas, l'invocation se fera sur la classe mre avec les traitements de la classe mre. Si vous voulez un exemple concret de ce que je viens de vous dire, vous n'avez qu' retirer la mthode toString() dans les classes Ville et Capitale : vous verrez que le code de la mthode main fonctionne toujours, mais que le rsultat n'est plus du tout pareil, car l'appel de la mthode toString(), la JVM va regarder si celle-ci existe dans la classe appelante et, comme elle ne la trouve pas, elle remonte dans la hirarchie jusqu' arriver la classe Object. . .

Vous devez savoir qu'une mthode n'est invocable par un objet que si celui-ci dnit ladite mthode.
Ainsi, ce code ne fonctionne pas :
puli lss dzI { puli stti void min@tring rgsA{ ille tleu a new illeTY tring t a {4wrseille4D 4lille4D 4en4D 4lyon4D 4pris4D 4nntes4}Y int tP a {IPQRSTD UVRSTD TSRWVUD USVQPITSD ISWRD PIQ}Y for@int i a HY i ` TY iCCA{ if @i `QA{ ille a new ille@tiD tPiD 4frne4AY tleui a Y } else{ gpitle g a new gpitle@tiD tPiD 4frne4D 4l tour iiffel4AY tleui a gY

GGsl ne nous reste plus qu9 drire tout notre tleu 3 for@yjet v X tleuA{

108

LE POLYMORPHISME
ystemFoutFprintln@vFderisoi@AC4n4AY

Pour qu'il fonctionne, vous devez dire la JVM que la rfrence de type Object est en fait une rfrence de type Ville, comme ceci : ((Ville)v).decrisToi(); . Vous transtypez la rfrence v en Ville par cette syntaxe. Ici, l'ordre des oprations s'eectue comme ceci :  vous transtypez la rfrence v en Ville ;  vous appliquez la mthode decrisToi() la rfrence appelante, c'est--dire, ici, une rfrence Object change en Ville. Vous voyez donc l'intrt des mthodes polymorphes : grce elles, vous n'avez plus vous soucier du type de variable appelante. Cependant, n'utilisez le type Object qu'avec parcimonie. Il y a deux autres mthodes qui sont trs souvent rednies :  public boolean equals(Object o) , qui permet de vrier si un objet est gal un autre ;  public int hashCode(), qui attribue un code de hashage un objet. En gros, elle donne un identiant un objet. Notez que cet identiant sert plus catgoriser votre objet qu' l'identier formellement.

Il faut garder en tte que ce n'est pas parce que deux objets ont un mme code de hashage qu'ils sont gaux 8 ; par contre, deux objets gaux ont forcment le mme code de hashage !
Voil quoi pourraient ressembler ces deux mthodes pour notre objet Ville :
puli int hshgode@A{ GGyn utilise ii l mthode hshgode de l9ojet tring return @thisFnomysFhshgode@ACthisFnomilleFhshgode@AAY } puli oolen equls@ille vA{ return @thisFhshgode@A aa vFhshgode@A 88 thisFgetxomreritnt@A aa vFgetxomreritnt@AAY }

Nous avons donc dni que le code de hashage de nos objets Ville est fonction du nom du pays et du nom de la ville, que la mthode equals doit prendre en paramtre des objets Ville 9 et que deux objets Ville sont gaux s'ils ont le mme code de hashage ainsi que le mme nombre d'habitants.
8. En eet, deux objets peuvent avoir la mme  catgorie  et tre dirents. . . 9. Elle peut galement recevoir des classes lles de Ville.

109

CHAPITRE 10. L'HRITAGE Il existe encore un type de mthodes dont je ne vous ai pas encore parl : le type final. Une mthode signe final est ge, vous ne pourrez jamais la rednir 10 .
puli finl int mwethode@A{ GGwthode ne pouvnt ps tre surhrge }

Il existe aussi des classes dclares final. Vous avez compris que ces classes sont immuables. . . Et vous ne pouvez donc pas faire hriter un objet d'une classe dclare final !

En rsum
 Une classe hrite d'une autre classe par le biais du mot cl extends.  Une classe ne peut hriter que d'une seule classe.  Si aucun constructeur n'est dni dans une classe lle, la JVM en crera un et appellera automatiquement le constructeur de la classe mre.  La classe lle hrite de toutes les proprits et mthodes public et protected de la classe mre.  Les mthodes et les proprits private d'une classe mre ne sont pas accessibles dans la classe lle.  On peut rednir une mthode hrite, c'est--dire qu'on peut changer tout son code.  On peut utiliser le comportement d'une classe mre par le biais du mot cl super.  Grce l'hritage et au polymorphisme, nous pouvons utiliser la covariance des variables.  Si une mthode d'une classe mre n'est pas rednie ou  polymorphe , l'appel de cette mthode par le biais d'un objet enfant, c'est la mthode de la classe mre qui sera utilise.  Vous ne pouvez pas hriter d'une classe dclare final.  Une mthode dclare final n'est pas rednissable.

10. La mthode getClass() de la classe Object est un exemple de ce type de mthode : vous ne pourrez pas la rednir.

110

Chapitre

11
Dicult :

Modliser ses objets grce UML

ans ce chapitre, nous allons dcouvrir le principe de modlisation d'objet. Le sigle UML signie Unied Modeling Language : traduisez par  langage de modlisation uni . Il ne s'agit pas d'un langage de programmation, mais plutt d'une mthode de modlisation. La mthode Merise, par exemple, en est une autre. En fait, lorsque vous programmez en orient objet, il vous sera sans doute utile de pouvoir schmatiser vos classes, leur hirarchie, leurs dpendances, leur architecture, etc. L'ide est de pouvoir, d'un simple coup d'il, vous reprsenter le fonctionnement de votre logiciel : imaginez UML un peu comme une partition de musique pour le musicien. Le but de ce chapitre n'est pas de vous transformer en experts UML, mais de vous donner susamment de bases pour mieux apprhender la modlisation et ensuite bien cerner certains concepts de la POO.

111

CHAPITRE 11. MODLISER SES OBJETS GRCE UML

Prsentation d'UML
Je sais que vous tes des Zros avertis en matire de programmation, ainsi qu'en informatique en gnral, mais mettez-vous dans la peau d'une personne totalement dnue de connaissances dans le domaine. Il fallait trouver un langage commun aux commerciaux, aux responsables de projets informatiques et aux dveloppeurs, an que tout ce petit monde se comprenne. Avec UML, c'est le cas. En fait, avec UML, vous pouvez modliser toutes les tapes du dveloppement d'une application informatique, de sa conception la mise en route, grce des diagrammes. Il est vrai que certains de ces diagrammes sont plus adapts pour les informaticiens, mais il en existe qui permettent de voir comment interagit l'application avec son contexte de fonctionnement. . . Et dans ce genre de cas, il est indispensable de bien connatre l'entreprise pour laquelle l'application est prvue. On recourt donc un mode de communication comprhensible par tous : UML. Il existe bien sr des outils de modlisation pour crer de tels diagrammes. En ce qui me concerne, j'utilise argoUML 1 . Tlcharger argoUML Code web : 547686 


Cependant, il en existe d'autres, comme :  boUML,  Together,  Poseidon,  Pyut. . . Avec ces outils, vous pouvez raliser les dirents diagrammes qu'UML vous propose :  le diagramme de use case 2 permet de dterminer les dirents cas d'utilisation d'un programme informatique ;  le diagramme de classes ; c'est de celui-l que nous allons nous servir. Il permet de modliser des classes ainsi que les interactions entre elles ;  les diagrammes de squences, eux, permettent de visualiser le droulement d'une application dans un contexte donn ;  et d'autres encore. . . La gure 11.1 reprsente un exemple de diagramme de classes. Vous avez d remarquer qu'il reprsente les classes que nous avons rencontres dans les chapitres prcdents. Je ne vous cache pas qu'il s'agit d'une version simplie. . . En eet, vous pouvez constater que je n'ai pas fait gurer les mthodes dclares public de la classe Object, ni celles des classes que nous avons codes. Je ne vais pas vous apprendre utiliser argoUML, mais plutt lire un diagramme. En eet, dans certains cas, il est utile de modliser les classes et l'interaction entre celles-ci, ne serait-ce que pour disposer de plus de recul sur son travail. Une autre raison cela est que certains concepts de programmation sont plus faciles expliquer avec un diagramme qu'avec
1. Il a le mrite d'tre gratuit et crit en Java. . . donc multi-plates-formes. 2. Cas d'utilisation.

112

MODLISER SES OBJETS

Figure

11.1  Exemple de diagramme de classes

de longs discours. . .

Modliser ses objets


prsent, nous allons apprendre lire un diagramme de classes. Vous avez devin qu'une classe est modlise sous la forme reprsente sur la gure 11.2.

Figure

11.2  Classe en UML

Voici une classe nomme ObjetA qui a comme attributs :  numero de type int ;  nom de type String ;  bool de type boolean. Ses mthodes sont :  getNom() qui retourne une chane de caractres ;  setNom() qui ne renvoie rien ;  afficher() qui renvoie galement une chane de caractres. La porte des attributs et des mthodes n'est pas reprsente ici. Vous voyez, la modlisation d'un objet est toute simple et trs comprhensible ! 113

CHAPITRE 11. MODLISER SES OBJETS GRCE UML Maintenant, intressons-nous aux interactions entre objets.

Modliser les liens entre les objets


Vous allez voir : les interactions sont, elles aussi, trs simples modliser. En fait, comme vous l'avez vu avec l'exemple, les interactions sont modlises par des ches de plusieurs sortes. Nous aborderons ici celles dont nous pouvons nous servir dans l'tat actuel de nos connaissances (au fur et mesure de la progression, d'autres ches apparatront). Regardez la gure 11.3.

Figure

11.3  Reprsentation de l'hritage

Sur ce diagramme, vous remarquez un deuxime objet qui dispose, lui aussi, de paramtres. Ne vous y trompez pas, ObjetB possde galement les attributs et les mthodes de la classe ObjetA. D'aprs vous, pourquoi ? C'est parce que la che qui relie nos deux objets signie  extends . En gros, vous pouvez lire ce diagramme comme suit : l'ObjetB hrite de l'ObjetA, ou encore ObjetB est un ObjetA. Nous allons voir une autre che d'interaction. Je sais que nous n'avons pas encore rencontr ce cas de gure, mais il est simple comprendre. De la mme faon que nous pouvons utiliser des objets de type String dans des classes que nous dveloppons, nous pouvons aussi utiliser comme variable d'instance, ou de classe, un objet que nous avons cod. La gure 11.4 modlise ce cas. Dans cet exemple simpliste, nous avons toujours notre hritage entre un objet A et un objet B, mais dans ce cas, l' ObjetA (et donc l'ObjetB) possde une variable de classe de type ObjetC, ainsi qu'une mthode dont le type de retour est ObjetC (car la mthode retourne un ObjetC). Vous pouvez lire ce diagramme comme suit : l' ObjetA a un ObjetC (donc une seule instance d'ObjetC est prsente dans ObjetA). Voici le code Java correspondant ce diagramme. 114

MODLISER LES LIENS ENTRE LES OBJETS

Figure

11.4  Reprsentation de l'appartenance

Fichier ObjetA.java
puli lss yjete{ proteted yjetg oj a new yjetg@AY puli yjetg getyjet@A{ return ojY }

Fichier ObjetB.java
puli lss yjetf extends yjete{ }

Fichier ObjetC.java
puli lss yjetg{ }

Il reste une dernire che que nous pouvons mentionner, car elle ne dire que lgrement de la premire. Un diagramme la mettant en uvre est reprsent sur la gure 11.5. Ce diagramme est identique au prcdent, l'exception de l' ObjetD. Nous devons le lire comme ceci : l'ObjetA est compos de plusieurs instances d' ObjetD. Vous pouvez d'ailleurs remarquer que la variable d'instance correspondante est de type tableau. . . Voici le code Java correspondant. 115

CHAPITRE 11. MODLISER SES OBJETS GRCE UML

Figure

11.5  Reprsentation de la composition

Fichier ObjetA.java
puli lss yjete{ proteted yjetg oj a new yjetg@AY proteted yjeth ojh a new yjethIHY puli yjetg getyjet@A{ return ojY } puli yjeth getyjeth@A{ return ojhY }

Fichier ObjetB.java
puli lss yjetf extends yjete{ }

Fichier ObjetC.java
puli lss yjetg{ }

Fichier ObjetD.java
puli lss yjeth{ }

Il est bien vident que ces classes ne font strictement rien. Je les ai utilises titre d'exemple pour la modlisation. . .
Voil, c'en est ni pour le moment. Attendez-vous donc rencontrer des diagrammes dans les prochains chapitres. . . 116

MODLISER LES LIENS ENTRE LES OBJETS

En rsum
     UML vous permet de reprsenter les liens entre vos classes. Vous pouvez y modliser leurs attributs et leurs mthodes. Vous pouvez reprsenter l'hritage avec une che signiant  est un . Vous pouvez reprsenter l'appartenance avec une che signiant  a un . Vous pouvez reprsenter la composition avec une che signiant  est compos de .

117

CHAPITRE 11. MODLISER SES OBJETS GRCE UML

118

Chapitre

12
Dicult :

Les packages

orsque nous avons t confronts pour la premire fois aux packages, c'tait pour importer la classe Scanner via l'instruction import java.util.Scanner; . Le fonctionnement des packages est simple comprendre : ce sont comme des dossiers permettant de ranger nos classes. Charger un package nous permet d'utiliser les classes qu'il contient. Il n'y aura rien de franchement compliqu dans ce chapitre si ce n'est que nous reparlerons un peu de la porte des classes Java.

119

CHAPITRE 12. LES PACKAGES

Cration d'un package


L'un des avantages des packages est que nous allons y gagner en lisibilit dans notre package par dfaut, mais aussi que les classes mises dans un package sont plus facilement transportables d'une application l'autre. Pour cela, il vous sut d'inclure le dossier de votre package dans un projet et d'y importer les classes qui vous intressent ! Pour crer un nouveau package, cliquez simplement sur cette icne 1 (gure 12.1).

Figure

12.1  Nouveau package

Une bote de dialogue va s'ouvrir et vous demander le nom de votre package (gure 12.2).

Figure

12.2  Nom du package

Il existe aussi une convention de nommage pour les packages :  ceux-ci doivent tre crits entirement en minuscules ;  les caractres autoriss sont alphanumriques (de a z, de 0 9) et peuvent contenir des points (.) ;  tout package doit commencer par com, edu, gov, mil, net, org ou les deux lettres identiant un pays 2 , fr correspond France, en correspond England. . .  aucun mot cl Java ne doit tre prsent dans le nom, sauf si vous le faites suivre d'un  _ , ainsi :  com.sdz.package n'est pas un nom de package valide,  com.sdz.package_ est un nom de package valide.
1. Vous pouvez aussi eectuer un clic droit puis New Package. 2. ISO Standard 3166, 1981.

120

DROITS D'ACCS ENTRE LES PACKAGES Comme cet ouvrage est la version papier du cours prsent sur le Site du Zro, j'ai pris le nom l'envers : sdz.com nous donne com.sdz. Autre exemple, mes packages ont tendance s'appeler com.cysboy.<nom>. Pour le cas qui nous occupe, appelons-le com.sdz.test. Cliquez sur  Finish  pour crer le package. Et voil : celui-ci est prt l'emploi.

Je vous invite aller voir dans le dossier o se trouvent vos codes sources : vous constaterez qu'il y a l'arborescence du dossier com/sdz/test dans votre dossier src.
Vous conviendrez que la cration d'un package est trs simple. Cependant, je ne peux pas vous laisser sans savoir que la porte de vos classes est aecte par les packages. . .

Droits d'accs entre les packages


Lorsque vous avez cr votre premire classe, vous avez vu qu'Eclipse met systmatiquement le mot cl  public  devant la dclaration de la classe. Je vous avais alors dit que public class Ville et class Ville taient sensiblement dirents et que le mot cl  public  inuait sur la porte de notre classe. En fait, une classe dclare avec le mot cl  public  sera visible mme l'extrieur de son package, les autres ne seront accessibles que depuis l'intrieur du package : on dit que leur porte est default. An de vous prouver mes dires, je vous invite crer un second package : je l'ai appel com.sdz.test2. Dans le premier package, com.sdz.test, crez une classe A de porte public et une classe B de porte default, comme ceci 3 :
pkge omFsdzFtestY lss f { puli tring str a44Y } pkge omFsdzFtestY puli lss e { puli f a new f@AY }

Vous aurez remarqu que les classes contenues dans un package ont en toute premire instruction la dclaration de ce package.
Maintenant que cela est fait, an de faire le test, crez une classe contenant la mthode main, toujours dans le mme package, comme ceci :
3. J'ai volontairement dclar les variables d'instance public an d'allger l'exemple.

121

CHAPITRE 12. LES PACKAGES


pkge omFsdzFtestY puli lss win { puli stti void min@tring rgsA{ e a new e@AY f a new f@AY GGeuun prolme ii } }

Ce code, bien qu'il ne fasse rien, fonctionne trs bien : aucun problme de compilation, entre autres. Maintenant, faites un copier-coller de la classe ci-dessus dans le package com.sdz.test2. Vous devriez avoir le rsultat reprsent sur la gure 12.3.

Figure

12.3  Problme de porte de classe

Vous pouvez constater qu'Eclipse n'aime ni l'instruction import com.sdz.test.B , ni l'instruction B b = new B(); : cela est d la dclaration de notre classe. J'irai mme plus loin : si vous essayez de modier la variable d'instance de l'objet A, vous aurez le mme problme. Donc, ceci : a.b.str = "toto"; n'est pas non plus autoris dans ce package ! La seule faon de corriger le problme est de dclarer la classe B public . Rappelez-vous que seule la classe A avait t dclare ainsi.

En rsum
 Un package est un ensemble de dossiers et de sous-dossiers.  Le nom du package est soumis une convention de nommage.  Si vous voulez utiliser un mot cl Java dans le nom de votre package, vous devez le faire suivre d'un  _ .  Les classes dclares public sont visibles depuis l'extrieur du package qui les contient.  Les classes n'ayant pas t dclares public ne sont pas visibles depuis l'extrieur du package qui les contient.  Si une classe dclare public dans son package a une variable d'un type ayant une porte default, cette dernire ne pourra pas tre modie depuis l'extrieur de son package. 122

Chapitre

13
Dicult :

Les classes abstraites et les interfaces

ous voil de retour avec deux fondements du langage Java. Je vais essayer de faire simple : derrire ces deux notions se cache la manire dont Java vous permet de structurer votre programme. Grce aux chapitres prcdents, vous vous rendez compte que vos programmes Java regorgeront de classes, avec de l'hritage, des dpendances, de la composition. . . An de bien structurer vos programmes (on parle d' architecture logicielle ), vous allez vous creuser les mninges pour savoir o ranger des comportements d'objets :  dans la classe mre ?  dans la classe lle ? Comment obtenir une structure assez souple pour pallier les problmes de programmation les plus courants ? La rponse est dans ce chapitre.

123

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES

Les classes abstraites


Une classe abstraite est quasiment identique une classe normale. Oui, identique aux classes que vous avez maintenant l'habitude de coder. Cela dit, elle a tout de mme une particularit : vous ne pouvez pas l'instancier ! Vous avez bien lu. Imaginons que nous ayons une classe A dclare abstraite. Voici un code qui ne compilera pas :
puli lss est{ puli stti void min@tring rgsA{ e oj a new e@AY GGirreur de ompiltion 3 } }

Pour bien en comprendre l'utilit, il vous faut un exemple de situation (de programme, en fait) qui le requiert. Imaginez que vous tes en train de raliser un programme qui gre dirents types d'animaux 1 . Dans ce programme, vous aurez des loups, des chiens, des chats, des lions et des tigres. Mais vous n'allez tout de mme pas faire toutes vos classes btement : il va de soi que tous ces animaux ont des points communs ! Et qui dit points communs dit hritage. Que pouvons-nous dnir de commun tous ces animaux ? Le fait qu'ils aient une couleur, un poids, un cri, une faon de se dplacer, qu'ils mangent et boivent quelque chose. Nous pouvons donc crer une classe mre : appelons-la Animal. Avec ce que nous avons dgag de commun, nous pouvons lui dnir des attributs et des mthodes. Voici donc ce quoi ressemblent nos classes tant qu' prsent (gure 13.1).

Figure

13.1  Classe Animal

Nous avons bien notre classe mre Animal et nos animaux qui en hritent. prsent, laissez-moi vous poser une question.
1. Oui, je sais : l'exemple est bte, mais il a le mrite d'tre simple comprendre.

124

LES CLASSES ABSTRAITES

Vu que notre classe Animal est public, qu'est cens faire un objet Animal ? Quel est son poids, sa couleur, que mange-t-il ?
Si nous avons un morceau de code qui ressemble ceci :
puli lss est{ puli stti void min@tring rgsA{ eniml ni a new eniml@AY @@voupAniAFmnger@AY GGue doitEil fire c } }

. . . personnellement, je ne sais pas ce que mange un objet Animal. . . Vous conviendrez

que toutes les classes ne sont pas bonnes tre instancies !

C'est l qu'entrent en jeu nos classes abstraites. En fait, ces classes servent dnir une superclasse : par l, vous pouvez comprendre qu'elles servent essentiellement crer un nouveau type d'objets. Voyons maintenant comment crer une telle classe.

Une classe

Animal

trs abstraite

En fait, il existe une rgle pour qu'une classe soit considre comme abstraite. Elle doit tre dclare avec le mot cl abstract. Voici un exemple illustrant mes dires :
strt lss eniml{ }

Une telle classe peut contenir la mme chose qu'une classe normale. Ses enfants pourront utiliser tous ses lments dclars 2 (attributs et mthodes). Cependant, ce type de classe permet de dnir des mthodes abstraites. . . mthodes qui prsentent une particularit : elle n'ont pas de corps ! En voici un exemple :
strt lss eniml{ strt void mnger@AY GGne mthode strite }

Vous voyez pourquoi on dit  mthode abstraite  : dicile de voir ce que cette mthode sait faire. . .

Retenez bien qu'une mthode abstraite n'est compose que de l'en-tte de la mthode suivie d'un point-virgule  ; .
2. lments dclars public ou protected, nous sommes d'accord.

125

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES Il faut que vous sachiez qu'une mthode abstraite ne peut exister que dans une classe abstraite. Si, dans une classe, vous avez une mthode dclare abstraite, vous devez dclarer cette classe comme tant abstraite . Voyons quoi cela peut servir. Vous avez vu les avantages de l'hritage et du polymorphisme. Eh bien nos classes enfants hriteront aussi des mthodes abstraites, mais tant donn que celles-ci n'ont pas de corps, nos classes enfants seront obliges de rednir ces mthodes ! Elles prsentent donc des mthodes polymorphes, ce qui implique que la covariance des variables pointe nouveau le bout de son nez :
puli lss est{ puli stti void min@tring rgsA{ eniml loup a new voup@AY eniml hien a new ghien@AY loupFmnger@AY hienFrier@AY } }

Attends ! Tu nous as dit qu'on ne pouvait pas instancier de classe abstraite !


Et je maintiens mes dires : nous n'avons pas instanci notre classe abstraite. Nous avons instanci un objet Loup que nous avons mis dans un objet de type Animal 3 . Vous devez vous rappeler que l'instance se cre avec le mot cl new. En aucun cas, le fait de dclarer une variable d'un type de classe donn  ici, Animal  n'est une instanciation ! Ici, nous instancions un Loup et un Chien. Vous pouvez aussi utiliser une variable de type Object comme rfrence un objet Loup, un objet Chien. . . Vous saviez dj que ce code fonctionne :
puli lss est{ puli stti void min@tring rgsA{ yjet oj a new voup@AY @@voupAojAFmnger@AY } }

En revanche, ceci pose problme :


puli stti void min@tring rgsA{ yjet oj a new voup@AY voup l a ojY GGrolme de rfrene }

3. Il en va de mme pour l'instanciation de la classe Chien.

126

LES CLASSES ABSTRAITES Eh oui ! Vous essayez de mettre une rfrence de type Object dans une rfrence de type Loup : pour avertir la JVM que la rfrence que vous voulez aecter votre objet de type Loup est un Loup, vous devez utiliser le transtypage ! Revoyons notre code :
puli stti void min@tring rgsA{ yjet oj a new voup@AY voup l a @voupAojY GGous prvenez l tw que l rfrene que vous pssez est de type voupF }

Vous pouvez bien videmment instancier directement un objet Loup, un objet Chien, etc.

Pour le moment, nous n'avons de code dans aucune classe ! Les exemples que je vous ai fournis ne font rien du tout, mais ils fonctionneront lorsque nous aurons ajout des morceaux de code nos classes.

toons notre exemple


Nous allons donc ajouter des morceaux de code nos classes. Tout d'abord, tablissons un bilan de ce que nous savons.  Nos objets seront probablement tous de couleur et de poids dirents. Nos classes auront donc le droit de modier ceux-ci.  Ici, nous partons du principe que tous nos animaux mangent de la viande. La mthode manger() sera donc dnie dans la classe Animal.  Idem pour la mthode boire(). Ils boiront tous de l'eau 4 .  Ils ne crieront pas et ne se dplaceront pas de la mme manire. Nous emploierons donc des mthodes polymorphes et dclarerons les mthodes deplacement() et crier() abstraites dans la classe Animal. La gure 13.2 reprsente le diagramme des classes de nos futurs objets. Ce diagramme permet de voir si une classe est abstraite : son nom est alors en italique. Nous voyons bien que notre classe Animal est dclare abstraite et que nos classes lles hritent de celle-ci. De plus, nos classes lles ne rednissent que deux mthodes sur quatre, on en conclut donc que ces deux mthodes doivent tre abstraites. Nous ajouterons deux constructeurs nos classes lles : un par dfaut et un autre comprenant les deux paramtres d'initialisation. cela, nous ajouterons aussi les accesseurs d'usage. Mais dites donc. . . nous pouvons amliorer un peu cette architecture, sans pour autant rentrer dans les dtails ! Vu les animaux prsents, nous aurions pu faire une sous-classe Carnivore, ou encore AnimalDomestique et AnimalSauvage. . . Ici, nous allons nous contenter de faire deux sous-classes : Canin et Felin, qui hriteront d'Animal et dont nos objets eux-mmes hriteront !
4. Je vous voyais venir. . .

127

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES

Figure

13.2  Hirarchie de nos classes

Nous allons rednir la mthode deplacement() dans cette classe, car nous allons partir du principe que les flins se dplacent d'une certaine faon et les canins d'une autre. Avec cet exemple, nous rviserons le polymorphisme. . . La gure 13.3 correspond notre diagramme mis jour 5 .

Figure

13.3  Nouvelle architecture des classes


Voici les codes Java correspondants.




Copier ces classes Code web : 571397 

5. Vous avez remarqu ? J'ai ajout une mthode toString().

128

LES CLASSES ABSTRAITES

Animal.java
strt lss eniml { proteted tring ouleurY proteted int poidsY proteted void mnger@A{ ystemFoutFprintln@4te mnge de l vindeF4AY } proteted void oire@A{ ystemFoutFprintln@4te ois de l9eu 34AY } strt void deplement@AY strt void rier@AY puli tring totring@A{ tring str a 4te suis un ojet de l 4 C thisFgetglss@A C 4D je suis 4 C thisFouleur C 4D je pse 4 C thisFpoidsY return strY }

Felin.java
puli strt lss pelin extends eniml { void deplement@A { ystemFoutFprintln@4te me dple seul 34AY } }

Canin.java
puli strt lss gnin extends eniml { void deplement@A { ystemFoutFprintln@4te me dple en meute 34AY } }

Chien.java
puli lss ghien extends gnin { puli ghien@A{

129

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES


} puli ghien@tring ouleurD int poidsA{ thisFouleur a ouleurY thisFpoids a poidsY } void rier@A { ystemFoutFprintln@4t9oie sns rison 34AY }

Loup.java
puli lss voup extends gnin { puli voup@A{ } puli voup@tring ouleurD int poidsA{ thisFouleur a ouleurY thisFpoids a poidsY } void rier@A { ystemFoutFprintln@4te hurle l vune en fisnt ouhouh 34AY }

Lion.java
puli lss vion extends pelin { puli vion@A{ } puli vion@tring ouleurD int poidsA{ thisFouleur a ouleurY thisFpoids a poidsY } void rier@A { ystemFoutFprintln@4te rugis dns l svne 34AY }

130

LES CLASSES ABSTRAITES

Tigre.java
puli lss igre extends pelin { puli igre@A{ } puli igre@tring ouleurD int poidsA{ thisFouleur a ouleurY thisFpoids a poidsY } void rier@A { ystemFoutFprintln@4te grogne trs fort 34AY }

Chat.java
puli lss ght extends pelin { puli ght@A{ } puli ght@tring ouleurD int poidsA{ thisFouleur a ouleurY thisFpoids a poidsY } void rier@A { ystemFoutFprintln@4te miule sur les toits 34AY }

Dis donc ! Une classe abstraite ne doit-elle pas comporter une mthode abstraite ?
Je n'ai jamais dit a ! Une classe dclare abstraite n'est pas instanciable, mais rien ne l'oblige comprendre des mthodes abstraites. En revanche, une classe contenant une mthode abstraite doit tre dclare abstraite ! Je vous invite maintenant faire des tests :
puli lss est { puli stti void min@tring rgsA { voup l a new voup@4qris leut4D PHAY lFoire@AY lFmnger@AY

131

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES


lFdeplement@AY lFrier@AY ystemFoutFprintln@lFtotring@AAY

Le jeu d'essai de ce code correspond la gure 13.4.

Figure

13.4  Test d'une classe abstraite

Dans la mthode toString() de la classe Animal, j'ai utilis la mthode getClass() qui  je vous le donne en mille  se trouve dans la classe Object. Celle-ci retourne  class <nom de la classe> .
Dans cet exemple, nous pouvons constater que nous avons un objet Loup.  l'appel de la mthode boire() : l'objet appelle la mthode de la classe Animal.  l'appel de la mthode manger() : idem.  l'appel de la mthode toString() : idem.  l'appel de la mthode deplacement() : c'est la mthode de la classe Canin qui est invoque ici.  l'appel de la mthode crier() : c'est la mthode de la classe Loup qui est appele. Remplacez le type de rfrence (ici, Loup) par Animal, essayez avec des objets Chien, etc. Vous verrez que tout fonctionne. 132

LES INTERFACES

Les interfaces
L'un des atouts majeurs  pour ne pas dire l'atout majeur  de la programmation oriente objet est la rutilisabilit de vos objets. Il est trs commode d'utiliser un objet (voire une architecture) que nous avons dj cr pour une nouvelle application. Admettons que l'architecture que nous avons dveloppe dans les chapitres prcdents forme une bonne base. Que se passerait-il si un autre dveloppeur vous demandait d'utiliser vos objets dans un autre type d'application ? Ici, nous ne nous sommes occups que de l'aspect gnrique des animaux que nous avons crs. Cependant, la personne qui vous a contact, elle, dveloppe une application pour un chenil. La contrainte principale, c'est que vos chiens devront apprendre faire de nouvelles choses telles que :  faire le beau ;  faire des clins ;  faire une  lchouille .

Je ne vois pas le problme. . . Tu n'as qu' ajouter ces mthodes dans la classe Animal !
Ouh l ! Vous vous rendez compte que vous obtiendrez des lions qui auront la possibilit de faire le beau ? Dans ce cas, on n'a qu' mettre ces mthodes dans la classe Chien, mais j'y vois deux problmes :  vous allez devoir mettre en place une convention de nommage entre le programmeur qui va utiliser vos objets et vous. . . Vous ne pourrez pas utiliser la mthode faireCalin(), alors que le programmeur oui ;  si vous faites cela, adieu le polymorphisme ! Vous ne pourrez pas appeler vos objets par le biais d'un supertype. Pour pouvoir accder ces mthodes, vous devrez obligatoirement passer par une rfrence un objet Chien. Pas terrible, tout a. . .

Tu nous as dit que pour utiliser au mieux le polymorphisme, nous devions dnir les mthodes au plus haut niveau de la hirarchie. Alors du coup, il faut rednir un supertype pour pouvoir utiliser le polymorphisme !
Oui, et je vous rappelle que l'hritage multiple est interdit en Java. Et quand je dis interdit, je veux dire que Java ne le gre pas ! Il faudrait pouvoir dvelopper un nouveau supertype et s'en servir dans nos classes Chien. Eh bien nous pouvons faire cela avec des interfaces. En fait, les interfaces permettent de crer un nouveau supertype ; on peut mme en ajouter autant que l'on le veut dans une seule classe ! Quant l'utilisation de nos objets, la convention est toute trouve. . . Pourquoi ? Parce qu'une interface n'est rien d'autre qu'une classe 100 % abstraite ! Allez : venons-en aux faits ! 133

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES

Votre premire interface


Pour dnir une interface, au lieu d'crire :
puli lss e{ }

. . . il vous sut de faire :


puli interfe s{ }

Voil : vous venez d'apprendre dclarer une interface. Vu qu'une interface est une classe 100 % abstraite, il ne vous reste qu' y ajouter des mthodes abstraites, mais sans le mot cl abstract. Voici des exemples d'interfaces :
puli interfe s{ puli void e@AY puli tring f@AY } puli interfe sP{ puli void g@AY puli tring h@AY }

Et pour faire en sorte qu'une classe utilise une interface, il sut d'utiliser le mot cl implements. Ce qui nous donnerait :
puli lss implements s{ puli void e@A{ GGFFFFFFF } puli tring f@A{ GGFFFFFFF } }

C'est tout. On dit que la classe X implmente l'interface I . Comme je vous le disais, vous pouvez implmenter plusieurs interfaces, et voil comment a se passe :
puli lss implements sD sP{ puli void e@A{ GGFFFFFFF } puli tring f@A{ GGFFFFFFF } puli void g@A{

134

LES INTERFACES
GGFFFFFFF } puli tring h@A{ GGFFFFFFF }

Par contre, lorsque vous implmentez une interface, vous devez obligatoirement rednir les mthodes de l'interface ! Ainsi, le polymorphisme vous permet de faire ceci :
puli stti void min@tring rgsA{ GGeve ette rfreneD vous pouvez utiliser les mthodes de l9interfe s s vr a new @AY GGeve ette rfreneD vous pouvez utiliser les mthodes de l9interfe sP sP vrP a new @AY vrFe@AY vrPFg@AY }

Implmentation de l'interface
Voil o nous en sommes

Rintintin

 Nous voulons que nos chiens puissent tre amicaux.  Nous voulons dnir un supertype pour utiliser le polymorphisme.  Nous voulons pouvoir continuer utiliser nos objets comme avant. Comme le titre de cette sous-partie le stipule, nous allons crer l'interface Rintintin pour ensuite l'implmenter dans notre objet Chien. Sous Eclipse, vous pouvez faire File New Interface, ou simplement cliquer sur la che noire ct du  C  pour la cration de classe, et choisir interface (gure 13.5). Voici son code :
puli interfe intintin{ puli void fireglin@AY puli void firevehouille@AY puli void firevefeu@AY }

prsent, il ne nous reste plus qu' implmenter l'interface dans notre classe Chien :
puli lss ghien extends gnin implements intintin {

135

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES

Figure

13.5  Cration d'une nouvelle interface

puli ghien@A{ } puli ghien@tring ouleurD int poidsA{ thisFouleur a ouleurY thisFpoids a poidsY } void rier@A { ystemFoutFprintln@4t9oie sns rison 34AY } puli void fireglin@A { ystemFoutFprintln@4te te fis un qy gvsx4AY } puli void firevefeu@A { ystemFoutFprintln@4te fis le eu 34AY } puli void firevehouille@A { ystemFoutFprintln@4te fis de grosses lhouillesFFF4AY }

L'ordre des dclarations est primordial. Vous devez mettre l'expression d'hritage avant l'expression d'implmentation, sinon votre code ne compilera pas.
Voici un code que vous pouvez utiliser pour tester le polymorphisme de notre implmentation :
puli lss est { puli stti void min@tring rgsA { GGves mthodes d9un hien ghien a new ghien@4qris leut4D PHAY Foire@AY Fmnger@AY Fdeplement@AY Frier@AY ystemFoutFprintln@Ftotring@AAY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY

136

LE PATTERN STRATEGY
GGves mthodes de l9interfe Ffireglin@AY Ffirevefeu@AY Ffirevehouille@AY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY GGtilisons le polymorphisme de notre interfe intintin r a new ghien@AY rFfirevefeu@AY rFfireglin@AY rFfirevehouille@AY } }

Objectif atteint ! Nous sommes parvenus dnir deux superclasses an de les utiliser comme supertypes et de jouir pleinement du polymorphisme. Dans la suite de ce chapitre, nous verrons qu'il existe une faon trs intressante d'utiliser les interfaces grce une technique de programmation appele pattern strategy. Sa lecture n'est pas indispensable, mais cela vous permettra de dcouvrir travers un cas concret comment on peut faire voluer au mieux un programme Java.

Le pattern strategy
Nous allons partir du principe que vous avez un code qui fonctionne, c'est--dire un ensemble de classes lies par l'hritage, par exemple. Nous allons voir ici que, en dpit de la toute-puissance de l'hritage, celui-ci atteint ses limites lorsque vous tes amens modier la hirarchie de vos classes an de rpondre une demande (de votre chef, d'un client. . .). Le fait de toucher votre hirarchie peut amener des erreurs indsirables, voire des absurdits : tout cela parce que vous allez changer une structure qui fonctionne cause de contraintes que l'on vous impose. Pour remdier ce problme, il existe un concept simple (il s'agit mme d'un des fondements de la programmation oriente objet) : l'encapsulation ! Nous allons parler de cette solution en utilisant un design pattern 6 . Un design pattern est un patron de conception, une faon de construire une hirarchie des classes permettant de rpondre un problme. Nous aborderons le pattern strategy, qui va nous permettre de remdier la limite de l'hritage. En eet, mme si l'hritage ore beaucoup de possibilits, il a ses limites.

Posons le problme
Mettez-vous dans la peau de dveloppeurs jeunes et ambitieux d'une toute nouvelle socit qui cre des jeux vido. Le dernier titre en date, Z-Army, un jeu de guerre trs
6. Ou

modle de conception.
137

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES raliste, a t un succs international ! Votre patron est content et vous aussi. Vous vous tes bass sur une architecture vraiment simple an de crer et utiliser des personnages (gure 13.6).

Figure

13.6  Hirarchie des classes

Les guerriers savent se battre tandis que les mdecins soignent les blesss sur le champ de bataille ! Les ennuis commencent maintenant. . . Votre patron vous a con le projet Z-Army2  The return of the revenge  , et vous vous dites :  Yes ! Mon architecture fonctionne merveille, je la garde.  Un mois plus tard, votre patron vous convoque dans son bureau et vous dit :  Nous avons fait une tude de march, et il semblerait que les joueurs aimeraient se battre aussi avec les mdecins !  Vous trouvez l'ide sduisante et avez dj pens une solution : dplacer la mthode combattre() dans la superclasse Personnage, an de la rednir dans la classe Medecin et jouir du polymorphisme (gure 13.7) !

Figure

13.7  Dplacement de la mthode combattre()

la seconde tude de march, votre patron vous annonce que vous allez devoir crer des civils, des snipers, des chirurgiens. . . Toute une panoplie de personnages spcialiss dans leur domaine (gure 13.8) ! 138

LE PATTERN STRATEGY

Figure

13.8  Nouveaux personnages

Le code source de ces classes


Copier les classes Code web : 777033 


Personnage.java
puli strt lss ersonnge { GBB B wthode de dplement de personnge BG puli strt void sehepler@AY GBB B wthode que les omttnts utilisent BG puli strt void omttre@AY

Guerrier.java
puli lss querrier extends ersonnge { puli void omttre@A { ystemFoutFprintln@4pusilD pistoletD outeu 3 out e que tu veux 34AY } puli void sehepler@A { ystemFoutFprintln@4te me dple piedF4AY }

139

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES

Medecin.java
puli lss wedein extends ersonnge{ puli void omttre@A { ystemFoutFprintln@4ive le slpel 34AY } puli void sehepler@A { ystemFoutFprintln@4te me dple piedF4AY } puli void soigner@A{ ystemFoutFprintln@4te soigne les lessuresF4AY }

Civil.java
puli lss givil extends ersonnge{ puli void omttre@A { ystemFoutFprintln@4te ne omts e 34AY } puli void sehepler@A { ystemFoutFprintln@4te me dple piedF4AY }

Chirurgien.java
puli lss ghirurgien extends ersonnge{ puli void omttre@A { ystemFoutFprintln@4te ne omts e 34AY } puli void sehepler@A { ystemFoutFprintln@4te me dple piedF4AY } puli void soigner@A{ ystemFoutFprintln@4te fis des oprtionsF4AY }

Sniper.java
puli lss niper extends ersonnge{ puli void omttre@A {

140

LE PATTERN STRATEGY
ystemFoutFprintln@4te me sers de mon fusil lunette 34AY

puli void sehepler@A { ystemFoutFprintln@4te me dple piedF4AY }

ce stade, vous devriez remarquer que :  le code contenu dans la mthode seDeplacer() est dupliqu dans toutes les classes ; il est identique dans toutes celles cites ci-dessus ;  le code de la mthode combattre() des classes Chirurgien et Civil est lui aussi dupliqu ! La duplication de code est une chose qui peut gnrer des problmes dans le futur. . . Je m'explique. Pour le moment, votre chef ne vous a demand que de crer quelques classes supplmentaires. Qu'en serait-il si beaucoup de classes avaient ce mme code dupliqu ? Il ne manquerait plus que votre chef vous demande de modier nouveau la faon de se dplacer de ces objets, et vous courrez le risque d'oublier d'en modier un ! Et voil les incohrences qui pointeront le bout de leur nez. . .

No problemo ! Tu vas voir. . . Il sut de mettre un comportement par dfaut pour le dplacement et pour le combat dans la superclasse Personnage.
Eectivement, votre ide se tient. Donc, cela nous donne ce qui suit. . .

Personnage.java
puli strt lss ersonnge { puli void sehepler@A{ ystemFoutFprintln@4te me dple piedF4AY } puli void omttre@A{ ystemFoutFprintln@4te ne omts e 34AY }

Guerrier.java
puli lss querrier extends ersonnge { puli void omttre@A { ystemFoutFprintln@4pusilD pistoletD outeu 3 out e que tu veux 34AY } }

141

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES

Medecin.java
puli lss wedein extends ersonnge{ puli void omttre@A { ystemFoutFprintln@4ive le slpel 34AY } puli void soigner@A{ ystemFoutFprintln@4te soigne les lessuresF4AY }

Civil.java
puli lss givil extends ersonnge{ }

Chirurgien.java
puli lss ghirurgien extends ersonnge{ puli void soigner@A{ ystemFoutFprintln@4te fis des oprtionsF4AY } }

Sniper.java
puli lss niper extends ersonnge{ puli void omttre@A { ystemFoutFprintln@4te me sers de mon fusil lunette 34AY } }

Voici une classe contenant un petit programme an de tester nos classes :
puli stti void min@tring rgsA { ersonnge ters a {new querrier@AD new ghirurgien@AD new givil@AD new niper@AD new wedein@A}Y for@ersonnge p X tersA{ ystemFoutFprintln@4nsnstne de 4 C pFgetglss@AFgetxme@AAY ystemFoutFprintln@4BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY pFomttre@AY pFsehepler@AY } }

Et le rsultat correspond la gure 13.9. 142

LE PATTERN STRATEGY

Figure

13.9  Rsultat du code

Apparemment, ce code vous donne ce que vous voulez ! Plus de redondance. . . Mais une chose me chionne : vous ne pouvez pas utiliser les classes Medecin et Chirurgien de faon polymorphe, vu que la mthode soigner() leur est propre ! On pourrait dnir un comportement par dfaut (ne pas soigner) dans la superclasse Personnage, et le tour serait jou.
puli strt lss ersonnge { puli void sehepler@A{ ystemFoutFprintln@4te me dple piedF4AY } puli void omttre@A{ ystemFoutFprintln@4te ne omts e 34AY } puli void soigner@A{ ystemFoutFprintln@4te ne soigne psF4AY } }

Au mme moment, votre chef rentre dans votre bureau et vous dit :  Nous avons bien rchi, et il serait de bon ton que nos guerriers puissent administrer les premiers soins.  ce moment prcis, vous vous dlectez de votre capacit d'anticipation ! Vous savez que, maintenant, il vous sut de rednir la mthode soigner() dans la classe concerne, et tout le monde sera content ! 143

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES Seulement voil ! Votre chef n'avait pas ni son speech :  Au fait, il faudrait aecter un comportement nos personnages en fonction de leurs armes, leurs habits, leurs trousses de soin. . . Enn, vous voyez ! Les comportements gs pour des personnages de jeux, de nos jours. . . c'est un peu ringard !  Vous commencez voir ce dont il retourne : vous devrez apporter des modications votre code, encore et encore. . . Bon : pour des programmeurs, cela est le train-train quotidien, j'en conviens. Cependant, si nous suivons les consignes de notre chef et que nous continuons sur notre lance, les choses vont se compliquer. . . Voyons cela.

Un problme supplmentaire
Attelons-nous appliquer les modications dans notre programme. Selon les directives de notre chef, nous devons grer des comportements dirents selon les accessoires de nos personnages : il faut utiliser des variables d'instance pour appliquer l'un ou l'autre comportement.

An de simplier l'exemple, nous n'allons utiliser que des objets


La gure 13.10 correspond au diagramme des classes de notre programme.

String.

Figure

13.10  Modication de nos classes

Vous avez remarqu que nos personnages possderont des accessoires. Selon ceux-ci, nos personnages feront des choses direntes. Voici les recommandations de notre chef bien-aim :  le guerrier peut utiliser un couteau, un pistolet ou un fusil de sniper ;  le sniper peut utiliser son fusil de sniper ainsi qu'un fusil pompe ;  le mdecin a une trousse simple pour soigner, mais peut utiliser un pistolet ;  le chirurgien a une grosse trousse mdicale, mais ne peut pas utiliser d'arme ;  le civil, quant lui, peut utiliser un couteau seulement quand il en a un ; 144

LE PATTERN STRATEGY  tous les personnages hormis le chirurgien peuvent avoir des baskets pour courir. Il va nous falloir des accesseurs 7 pour ces variables, insrons-les dans la superclasse ! Bon ! Les modications sont faites, les caprices de notre cher et tendre chef sont satisfaits ? Voyons cela tout de suite.


Hirarchie des classes Code web : 959825 

Personnage.java
puli strt lss ersonnge { proteted tring rmes a 44D hussure a 44D sheoin a 44Y puli void sehepler@A{ ystemFoutFprintln@4te me dple piedF4AY } puli void omttre@A{ ystemFoutFprintln@4te ne omts e 34AY } puli void soigner@A{ ystemFoutFprintln@4te ne soigne psF4AY } proteted void setermes@tring rmesA { thisFrmes a rmesY } proteted void setghussure@tring hussureA { thisFhussure a hussureY } proteted void setheoin@tring sheoinA { thisFsheoin a sheoinY }

Guerrier.java
puli lss querrier extends ersonnge { puli void omttre@A { if@thisFrmesFequls@4pistolet4AA ystemFoutFprintln@4ettque u pistolet 34AY else if@thisFrmesFequls@4fusil de sniper4AA ystemFoutFprintln@4ettque u fusil de sniper 34AY

7. Inutile de mettre les mthodes de renvoi ( getXXX), nous ne nous servirons que des mutateurs !

145

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES


else } }

ystemFoutFprintln@4ettque u outeu 34AY

Sniper.java
puli lss niper extends ersonnge{ puli void omttre@A { if@thisFrmesFequls@4fusil pompe4AA ystemFoutFprintln@4ettque u fusil pompe 34AY else ystemFoutFprintln@4te me sers de mon fusil lunette 34AY } }

Civil.java
puli lss givil extends ersonnge{ puli void omttre@A{ if@thisFrmesFequls@4outeu4AA ystemFoutFprintln@4ettque u outeu 34AY else ystemFoutFprintln@4te ne omts e 34AY } }

Medecin.java
puli lss wedein extends ersonnge{ puli void omttre@A { if@thisFrmesFequls@4pistolet4AA ystemFoutFprintln@4ettque u pistolet 34AY else ystemFoutFprintln@4ive le slpel 34AY } puli void soigner@A{ if@thisFsheoinFequls@4petit s4AA ystemFoutFprintln@4te peux reoudre des lessuresF4AY else ystemFoutFprintln@4te soigne les lessuresF4AY }

146

LE PATTERN STRATEGY

Chirurgien.java
puli lss ghirurgien extends ersonnge{ puli void soigner@A{ if@thisFsheoinFequls@4gros s4AA ystemFoutFprintln@4te fis des merveillesF4AY else ystemFoutFprintln@4te fis des oprtionsF4AY } }

Voici un programme de test :


puli stti void min@tring rgsA { ersonnge ters a {new querrier@AD new ghirurgien@AD new givil@AD new niper@AD new wedein@A}Y tring termes a {4pistolet4D 4pistolet4D 4outeu4D 4fusil pompe4D 4outeu4}Y for@int i a HY i ` tersFlengthY iCCA{ ystemFoutFprintln@4nsnstne de 4 C tersiFgetglss@AF getxme@AAY ystemFoutFprintln@4BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY tersiFomttre@AY tersiFsetermes@termesiAY tersiFomttre@AY tersiFsehepler@AY tersiFsoigner@AY }

Le rsultat de ce test se trouve sur la gure 13.11. Vous constatez avec merveillement que votre code fonctionne trs bien. Les actions par dfaut sont respectes, les aectations d'actions aussi. Tout est parfait !

Vraiment ? Vous tes srs de cela ? Pourtant, je vois du code dupliqu dans certaines classes ! En plus, nous n'arrtons pas de modier nos classes. . . Dans le premier opus de Z-Army, celles-ci fonctionnaient pourtant trs bien ! Qu'est-ce qui ne va pas ? Je ne comprends pas.
L-dessus, votre patron rentre dans votre bureau pour vous dire :  Les actions de vos personnages doivent tre utilisables la vole et, en fait, les personnages peuvent trs bien apprendre au l du jeu. . .  Les changements s'accumulent, votre code devient de moins en moins lisible et rutilisable, bref c'est l'enfer sur Terre. Faisons un point de la situation :  du code dupliqu s'insinue dans votre code ; 147

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES

Figure

13.11  Rsultat du test d'accessoires

148

LE PATTERN STRATEGY  chaque modication du comportement de vos personnages, vous tes obligs de retoucher le code source de la (ou des) classe(s) concerne(s) ;  votre code perd en rutilisabilit et du coup, il n'est pas extensible du tout !

Une solution simple et robuste : le pattern strategy


Aprs toutes ces motions, vous allez enn disposer d'une solution ce problme de modication du code source ! Si vous vous souvenez de ce que j'ai dit, un des fondements de la programmation oriente objet est l'encapsulation. Le pattern strategy est bas sur ce principe simple. Bon, vous avez compris que le pattern strategy consiste crer des objets avec des donnes, des mthodes (voire les deux) : c'est justement ce qui change dans votre programme ! Le principe de base de ce pattern est le suivant : isolez ce qui varie dans votre programme et encapsulez-le ! Dj, quels sont les lments qui ne cessent de varier dans notre programme ?  La mthode combattre().  La mthode seDeplacer().  La mthode soigner().

Ce qui serait vraiment grandiose, ce serait d'avoir la possibilit de ne modier que les comportements et non les objets qui ont ces comportements !
L, je vous arrte un moment : vous venez de fournir la solution. Vous avez dit :  Ce qui serait vraiment grandiose, ce serait d'avoir la possibilit de ne modier que les comportements et non les objets qui ont ces comportements . Lorsque je vous ai prsent les diagrammes UML, je vous ai fourni une astuce pour bien direncier les liens entre les objets. Dans notre cas, nos classes hritant de Personnage hritent aussi de ses comportements et, par consquent, on peut dire que nos classes lles sont des Personnage. Les comportements de la classe mre semblent ne pas tre au bon endroit dans la hirarchie. Vous ne savez plus quoi en faire et vous vous demandez s'ils ont vraiment leur place dans cette classe ? Il vous sut de sortir ces comportements de la classe mre, de crer une classe abstraite ou une interface symbolisant ce comportement et d'ordonner votre classe Personnage d'avoir ces comportements . Le nouveau diagramme des classes se trouve sur la gure 13.12. Vous apercevez une nouvelle entit sur ce diagramme, l'interface, facilement reconnaissable, ainsi qu'une nouvelle che symbolisant l'implmentation d'interface entre une classe concrte et une interface. N'oubliez pas que votre code doit tre souple et robuste et que  mme si ce chapitre vous montre les limites de l'hritage  le polymorphisme est inhrent l'hritage 8 .
8. Ainsi qu'aux implmentations d'interfaces.

149

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES

Figure

13.12  Nouveau diagramme des classes

Il faut vous rendre compte qu'utiliser une interface de cette manire revient crer un supertype de variable ; du coup, nous pourrons utiliser les classes hritant de ces interfaces de faon polymorphe sans nous soucier de savoir la classe dont sont issus nos objets ! Dans notre cas, notre classe Personnage comprendra des objets de type EspritCombatif, Soin et Deplacement ! Avant de nous lancer dans le codage de nos nouvelles classes, vous devez observer que leur nombre a considrablement augment depuis le dbut. An de pouvoir gagner en clart, nous allons grer nos direntes classes avec dirents packages. Comme nous l'avons remarqu tout au long de ce chapitre, les comportements de nos personnages sont trop pars pour tre dnis dans notre superclasse Personnage. Vous l'avez dit vous-mmes : il faudrait que l'on ne puisse modier que les comportements et non les classes hritant de notre superclasse ! Les interfaces nous servent crer un supertype d'objet ; grce elles, nous utiliserons des objets de type :  EspritCombatif qui prsentent une mthode combat() ;  Soin qui prsentent une mthode soigne() ;  Deplacement qui prsentent une mthode deplace(). Dans notre classe Personnage, nous avons ajout une instance de chaque type de comportement, vous avez d les remarquer : il y a ces attributs dans notre schma ! Nous allons dvelopper un comportement par dfaut pour chacun d'entre eux et aecter cet objet dans notre superclasse. Les classes lles, elles, comprendront des instances direntes correspondant leurs besoins.

Du coup, que fait-on des mthodes de la superclasse Personnage ?


Nous les gardons, mais plutt que de rednir ces dernires, la superclasse va invoquer la mthode de comportement de chaque objet. Ainsi, nous n'avons plus rednir ou 150

LE PATTERN STRATEGY modier nos classes ! La seule chose qu'il nous reste faire, c'est d'aecter une instance de comportement nos objets. Vous comprendrez mieux avec un exemple. Voici quelques implmentations de comportements.  Exemple du pattern Strategy Code web : 292297 

Implmentations de l'interface EspritCombatif


pkge omFsdzFomportementY puli lss ifiste implements ispritgomtif { puli void omt@A { ystemFoutFprintln@4te ne omts ps 34AY } } pkge omFsdzFomportementY puli lss gomtistolet implements ispritgomtif{ puli void omt@A { ystemFoutFprintln@4te omts u pitolet 34AY } } pkge omFsdzFomportementY puli lss gomtgouteu implements ispritgomtif { puli void omt@A { ystemFoutFprintln@4te me ts u outeu 34AY } }

Implmentations de l'interface Deplacement


pkge omFsdzFomportementY puli lss wrher implements heplement { puli void depler@A { ystemFoutFprintln@4te me dple en mrhntF4AY } } pkge omFsdzFomportementY puli lss gourir implements heplement { puli void depler@A {

151

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES


ystemFoutFprintln@4te me dple en ourntF4AY

Implmentations de l'interface Soin


pkge omFsdzFomportementY puli lss remieroin implements oin { puli void soigne@A { ystemFoutFprintln@4te donne les premiers soinsF4AY } } pkge omFsdzFomportementY puli lss ypertion implements oin { puli void soigne@A { ystemFoutFprintln@4te prtique des oprtions 34AY } } pkge omFsdzFomportementY puli lss euunoin implements oin { puli void soigne@A { ystemFoutFprintln@4te ne donne egx soin 34AY } }

Voici ce que vous devriez avoir dans votre nouveau package (gure 13.13).

Figure

13.13  Package des comportements

152

LE PATTERN STRATEGY Maintenant que nous avons dni des objets de comportements, nous allons pouvoir remanier notre classe Personnage. Ajoutons les variables d'instance, les mutateurs et les constructeurs permettant d'initialiser nos objets :
import omFsdzFomportementFBY puli strt lss ersonnge { GGxos instnes de omportement proteted ispritgomtif espritgomtif a new ifiste@AY proteted oin soin a new euunoin@AY proteted heplement deplement a new wrher@AY GGgonstruteur pr dfut puli ersonnge@A{} GGgonstruteur ve prmtres puli ersonnge@ispritgomtif espritgomtifD oin soinD heplement deplementA { thisFespritgomtif a espritgomtifY thisFsoin a soinY thisFdeplement a deplementY } GGwthode de dplement de personnge puli void sehepler@A{ GGyn utilise les ojets de dplement de fon polymorphe deplementFdepler@AY } GG wthode que les omttnts utilisent puli void omttre@A{ GGyn utilise les ojets de dplement de fon polymorphe espritgomtifFomt@AY } GGwthode de soin puli void soigner@A{ GGyn utilise les ojets de dplement de fon polymorphe soinFsoigne@AY } GGedfinit le omportement u omt puli void setispritgomtif@ispritgomtif espritgomtifA { thisFespritgomtif a espritgomtifY } GGedfinit le omportement de oin puli void setoin@oin soinA { thisFsoin a soinY } GGedfinit le omportement de dplement puli void setheplement@heplement deplementA { thisFdeplement a deplementY }

153

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES


}

Que de changements depuis le dbut ! Maintenant, nous n'utilisons plus de mthodes dnies dans notre hirarchie de classes, mais des implmentations concrtes d'interfaces ! Les mthodes que nos objets appellent utilisent chacune un objet de comportement. Nous pouvons donc dnir des guerriers, des civils, des mdecins. . . tous personnalisables, puisqu'il sut de modier l'instance de leur comportement pour que ceux-ci changent instantanment. La preuve par l'exemple. Je ne vais pas vous donner les codes de toutes les classes. . . En voici seulement quelquesunes.

Guerrier.java
import omFsdzFomportementFBY puli lss querrier extends ersonnge { puli querrier@A{ thisFespritgomtif a new gomtistolet@AY } puli querrier@ispritgomtif espritD oin soinD heplement depA { super@espritD soinD depAY } }

Civil.java
import omFsdzFomportementFBY puli lss givil extends ersonnge{ puli givil@A {} puli givil@ispritgomtif espritD oin soinD heplement depA { super@espritD soinD depAY }

Medecin.java
import omFsdzFomportementFBY puli lss wedein extends ersonnge{ puli wedein@A { thisFsoin a new remieroin@AY } puli wedein@ispritgomtif espritD oin soinD heplement depA { super@espritD soinD depAY

154

LE PATTERN STRATEGY
}

Maintenant, voici un exemple d'utilisation :


lss est{ puli stti void min@tring rgsA { ersonnge ters a {new querrier@AD new givil@AD new wedein@A}Y for@int i a HY i ` tersFlengthY iCCA{ ystemFoutFprintln@4nsnstne de 4 C tersiFgetglss@AFgetxme@AAY ystemFoutFprintln@4BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY tersiFomttre@AY tersiFsehepler@AY tersiFsoigner@AY }

Le rsultat de ce code nous donne la gure 13.14.

Figure

13.14  Test du pattern strategy

Vous pouvez voir que nos personnages ont tous un comportement par dfaut qui leur convient bien ! Nous avons spci, dans le cas o cela s'avre ncessaire, le comportement par dfaut d'un personnage dans son constructeur par dfaut :  le guerrier se bat avec un pistolet ;  le mdecin soigne. 155

CHAPITRE 13. LES CLASSES ABSTRAITES ET LES INTERFACES Voyons maintenant comment indiquer nos personnages de faire autre chose. . . Eh oui, la faon dont nous avons arrang tout cela va nous permettre de changer dynamiquement le comportement de chaque Personnage. Que diriez-vous de faire faire une petite opration chirurgicale notre objet Guerrier ? Pour ce faire, vous pouvez rednir son comportement de soin avec son mutateur prsent dans la superclasse en lui passant une implmentation correspondante !
import omFsdzFomportementFBY lss est{ puli stti void min@tring rgsA { ersonnge pers a new querrier@AY persiFsoigner@AY persiFsetoin@new ypertion@AAY persiFsoigner@AY } }

En testant ce code, vous constaterez que le comportement de soin de notre objet a chang dynamiquement sans que nous ayons besoin de changer la moindre ligne de son code source ! Le plus beau dans le fait de travailler comme cela, c'est qu'il est tout fait possible d'instancier des objets Guerrier avec des comportements dirents.

En rsum
              Une classe est dnie comme abstraite avec le mot cl abstract. Les classes abstraites sont utiliser lorsqu'une classe mre ne doit pas tre instancie. Une classe abstraite ne peut donc pas tre instancie . Une classe abstraite n'est pas oblige de contenir de mthode abstraite. Si une classe contient une mthode abstraite, cette classe doit alors tre dclare abstraite. Une mthode abstraite n'a pas de corps. Une interface est une classe 100 % abstraite. Aucune mthode d'une interface n'a de corps. Une interface sert dnir un supertype et utiliser le polymorphisme. Une interface s'implmente dans une classe en utilisant le mot cl implements. Vous pouvez implmenter autant d'interfaces que vous voulez dans vos classes. Vous devez rednir toutes les mthodes de l'interface (ou des interfaces) dans votre classe. Le pattern strategy vous permet de rendre une hirarchie de classes plus souple. Prfrez encapsuler des comportements plutt que de les mettre d'oce dans l'objet concern.

156

Chapitre

14
Dicult :

Les exceptions

oici encore une notion trs importante en programmation. Une exception est une erreur se produisant dans un programme qui conduit le plus souvent l'arrt de celui-ci. Il vous est srement dj arriv d'obtenir un gros message ach en rouge dans la console d'Eclipse : eh bien, cela a t gnr par une exception. . . qui n'a pas t capture. Le fait de grer les exceptions s'appelle aussi la capture d'exception ! Le principe consiste reprer un morceau de code (par exemple, une division par zro) qui pourrait gnrer une exception, de capturer l'exception correspondante et enn de traiter celle-ci, c'est--dire d'acher un message personnalis et de continuer l'excution. Bon, vous voyez maintenant ce que nous allons aborder dans ce chapitre. . . Donc, allons-y !

157

CHAPITRE 14. LES EXCEPTIONS

Le bloc try{...} catch{...}


Pour vous faire comprendre le principe des exceptions, je dois tout d'abord vous informer que Java contient une classe nomme Exception dans laquelle sont rpertoris dirents cas d'erreur. La division par zro dont je vous parlais plus haut en fait partie ! Si vous crez un nouveau projet avec seulement la classe main et y mettez le code suivant :
int j a PHD i a HY ystemFoutFprintln@jGiAY ystemFoutFprintln@4ouou toi 34AY

. . . vous verrez apparatre un joli message d'erreur Java (en rouge) comme celui de la gure 14.1.

Figure

14.1  ArithmeticException

Mais surtout, vous devez avoir constat que lorsque l'exception a t leve, le programme s'est arrt ! D'aprs le message ach dans la console, le nom de l'exception qui a t dclenche est ArithmeticException. Nous savons donc maintenant qu'une division par zro est une ArithmeticException. Nous allons pouvoir la capturer, avec un bloc try{...}catch{...}, puis raliser un traitement en consquence. Ce que je vous propose maintenant, c'est d'acher un message personnalis lors d'une division par 0. Pour ce faire, tapez le code suivant dans votre main :
puli stti void min@tring rgsA { int j a PHD i a HY try { ystemFoutFprintln@jGiAY } th @erithmetiixeption eA { ystemFoutFprintln@4hivision pr zro 34AY } ystemFoutFprintln@4ouou toi 34AY

En excutant ce code, vous obtiendrez le rsultat consultable sur la gure 14.2. Voyons un peu ce qui se passe.  Nous initialisons deux variables de type int, l'une 0 et l'autre un nombre quelconque. 158

LE BLOC TRY{...} CATCH{...}

Figure

14.2  Capture d'exception

 Nous isolons le code susceptible de lever une exception : System.out.println(j/i); .  Une exception de type ArithmeticException est leve lorsque le programme atteint cette ligne.  Notre bloc catch contient justement un objet de type ArithmeticException en paramtre. Nous l'avons appel e.  L'exception tant capture, l'instruction du bloc catch s'excute !  Notre message d'erreur personnalis s'ache alors l'cran. Vous vous demandez srement quoi sert le paramtre de la clause catch. Il permet de connatre le type d'exception qui doit tre captur. Et l'objet  ici, e  peut servir prciser notre message grce l'appel de la mthode getMessage(). Faites nouveau ce test, en remplaant l'instruction du catch par celle-ci :
ystemFoutFprintln@4hivision pr zro 34 C eFgetwessge@AAY

Vous verrez que la fonction getMessage() de notre objet ArithmeticException nous prcise la nature de l'erreur. Je vous disais aussi que le principe de capture d'exception permettait de ne pas interrompre l'excution du programme. En eet, lorsque nous capturons une exception, le code prsent dans le bloc catch(){...} est excut, mais le programme suit son cours ! Avant de voir comment crer nos propres exceptions, sachez que le bloc permettant de capturer ces dernires ore une fonctionnalit importante. En fait, vous avez sans doute compris que lorsqu'une ligne de code lve une exception, l'instruction dans le bloc try est interrompue et le programme se rend dans le bloc catch correspondant l'exception leve. Prenons un cas de gure trs simple : imaginons que vous souhaitez eectuer une action, qu'une exception soit leve ou non 1 . Java vous permet d'utiliser une clause via le mot cl finally. Voyons ce que donne ce code :
puli stti void min@tring rgsA{ try { ystemFoutFprintln@4 ab4 C @IGHAAY } th @glssgstixeption eA { eFprinttkre@AY } finlly{

ci.

1. Nous verrons lorsque nous travaillerons avec les chiers qu'il faut systmatiquement fermer ceux-

159

CHAPITRE 14. LES EXCEPTIONS


ystemFoutFprintln@4tion fite systmtiquement4AY

Lorsque vous l'excutez, vous pouvez constater que, mme si nous tentons d'intercepter une ArithmeticException 2 , grce la clause finally, un morceau de code est excut quoi qu'il arrive. Cela est surtout utilis lorsque vous devez vous assurer d'avoir ferm un chier, clos votre connexion une base de donnes ou un socket 3 . Maintenant que nous avons vu cela, nous pouvons aller un peu plus loin dans la gestion de nos exceptions.

Les exceptions personnalises


Nous allons perfectionner un peu la gestion de nos objets Ville et Capitale. . . Je vous propose de mettre en uvre une exception de notre cru an d'interdire l'instanciation d'un objet Ville ou Capitale prsentant un nombre ngatif d'habitants. La procdure pour faire ce tour de force est un peu particulire. En eet, nous devons : 1. crer une classe hritant de la classe Exception : NombreHabitantException 4 ; 2. renvoyer l'exception leve notre classe NombreHabitantException ; 3. ensuite, grer celle-ci dans notre classe NombreHabitantException . Pour faire tout cela, je vais encore vous apprendre deux mots cls.  throws : ce mot cl permet de signaler la JVM qu'un morceau de code, une mthode, une classe. . . est potentiellement dangereux et qu'il faut utiliser un bloc try{...}catch{...}. Il est suivi du nom de la classe qui va grer l'exception.  throw : celui-ci permet tout simplement de lever une exception manuellement en instanciant un objet de type Exception (ou un objet hrit). Dans l'exemple de notre ArithmeticException, il y a quelque part dans les mandres de Java un throw new ArithmeticException() . Pour mettre en pratique ce systme, commenons par crer une classe qui va grer nos exceptions. Celle-ci, je vous le rappelle, doit hriter d' Exception :
lss xomreritntixeption extends ixeption{ puli xomreritntixeption@A{ ystemFoutFprintln@4ous essyez d9instnier une lsse ille ve un nomre d9hitnts ngtif 34AY } }

Reprenez votre projet avec vos classes Ville et Capitale et crez ensuite une classe NombreHabitantException , comme je viens de le faire. Maintenant, c'est dans le
2. Celle-ci se dclenche lors d'un problme de cast. 3. Une connexion rseau. 4. Par convention, les exceptions ont un nom se terminant par Exception.

160

LES EXCEPTIONS PERSONNALISES constructeur de nos objets que nous allons ajouter une condition qui, si elle est remplie, lvera une exception de type NombreHabitantException . En gros, nous devons dire notre constructeur de Ville :  si l'utilisateur cre une instance de Ville avec un nombre d'habitants ngatif, crer un objet de type NombreHabitantException . Voil quoi ressemble le constructeur de notre objet Ville prsent :
puli ille@tring pxomD int pxreD tring pysA throws xomreritntixeption { if@pxre ` HA throw new xomreritntixeption@AY else { nresnstneCCY nresnstnefisCCY nomille a pxomY nomys a pysY nreritnt a pxreY thisFsetgtegorie@AY

seigne sur le type de l'erreur en question. Elle indique aussi la JVM que le constructeur de notre objet Ville est potentiellement dangereux et qu'il faudra grer les exceptions possibles. Si la condition if(nbre < 0) est remplie, throw new NombreHabitantException(); instancie la classe NombreHabitantException . Par consquent, si un nombre d'habitants est ngatif, l'exception est leve. Maintenant que vous avez apport cette petite modication, retournez dans votre classe main, eacez son contenu, puis crez un objet Ville de votre choix. Vous devez tomber sur une erreur persistante (gure 14.3) ; c'est tout fait normal et d l'instruction throws.

throws NombreHabitantException nous indique que si une erreur est capture, celle-ci sera traite en tant qu'objet de la classe NombreHabitantException , ce qui nous ren-

Figure

14.3  Exception non gre

Cela signie qu' partir de maintenant, vu les changements dans le constructeur, il 161

CHAPITRE 14. LES EXCEPTIONS vous faudra grer les exceptions qui pourraient survenir dans cette instruction avec un bloc try{} catch{}. Ainsi, pour que l'erreur disparaisse, il nous faut entourer notre instanciation avec un bloc try{...}catch{...} (gure 14.4).

Figure

14.4  Correction du bug

Vous pouvez constater que l'erreur a disparu, que notre code peut tre compil et qu'il s'excute correctement. Attention, il faut que vous soyez prpars une chose : le code que j'ai utilis dans la gure 14.4 fonctionne trs bien, mais il y a un autre risque, l'instance de mon objet Ville a t dclare dans le bloc try{...}catch{...} et cela peut causer beaucoup de problmes. Ce code :
puli stti void min@tring rgsA { try { ille v a new ille@4ennes4D IPHHHD 4prne4AY } th @xomreritntixeption eA { } } ystemFoutFprintln@vFtotring@AAY

. . . ne fonctionnera pas, tout simplement parce que la dclaration de l'objet Ville est faite dans un sous-bloc d'instructions, celui du bloc try{...}. Et rappelez-vous : une variable dclare dans un bloc d'instructions n'existe que dans celui-ci ! 162

LES EXCEPTIONS PERSONNALISES Ici, la variable v n'existe pas en dehors de l'instruction try{...}. Pour pallier ce problme, il nous sut de dclarer notre objet en dehors du bloc try{...} et de l'instancier l'intrieur :
puli stti void min@tring rgsA { ille v a nullY try { v a new ille@4ennes4D IPHHHD 4prne4AY } th @xomreritntixeption eA { } } ystemFoutFprintln@vFtotring@AAY

Mais que se passera-t-il si nous dclarons une Ville avec un nombre d'habitants ngatif pour tester notre exception ? En remplaant  12000  par  -12000  dans l'instanciation de notre objet. . . C'est simple : en plus d'une exception leve pour le nombre d'habitants ngatif, vous obtiendrez aussi une NullPointerException . Voyons ce qu'il s'est pass.  Nous avons bien dclar notre objet en dehors du bloc d'instructions.  Au moment d'instancier celui-ci, une exception est leve et l'instanciation choue !  La clause catch{} est excute : un objet NombreHabitantException est instanci.  Lorsque nous arrivons sur l'instruction  System.out.println(v.toString()); , notre objet est null !  Une NullPointerException est donc leve ! Ce qui signie que si l'instanciation choue dans notre bloc try{}, le programme plante ! Pour rsoudre ce problme, on peut utiliser une simple clause finally avec, l'intrieur, l'instanciation d'un objet Ville par dfaut si celui-ci est null :
puli stti void min@tring rgsA { ille v a nullY try { v a new ille@4ennes4D IPHHHD 4prne4AY } th @xomreritntixeption eA { } finlly{ if@v aa nullA v a new ille@AY } ystemFoutFprintln@vFtotring@AAY }

Pas besoin de capturer une exception sur l'instanciation de notre objet ici : le code n'est considr comme dangereux que sur le constructeur avec paramtres. Maintenant que nous avons vu la cration d'une exception, il serait de bon ton de pouvoir rcolter plus de renseignements la concernant. Par exemple, il serait peut-tre intressant de racher le nombre d'habitants que l'objet a reu. 163

CHAPITRE 14. LES EXCEPTIONS Pour ce faire, nous n'avons qu' crer un deuxime constructeur dans notre classe NombreHabitantException qui prend un nombre d'habitants en paramtre :
puli xomreritntixeption@int nreA { ystemFoutFprintln@4snstnition ve un nomre d9hitnts ngtifF4AY ystemFoutFprintln@4t ab 4 C nreAY }

Il sut maintenant de modier le constructeur de la classe Ville en consquence :


puli ille@tring pxomD int pxreD tring pysA throws xomreritntixeption { if@pxre ` HA throw new xomreritntixeption@pxreAY else { GGve ode est identique prdemment } }

Et si vous excutez le mme code que prcdemment, vous pourrez voir le nouveau message de notre exception s'acher. Ce n'est pas mal, avouez-le ! Sachez galement que l'objet pass en paramtre de la clause catch a des mthodes hrites de la classe Exception : vous pouvez les utiliser si vous le voulez et surtout, si vous en avez l'utilit. Nous utiliserons certaines de ces mthodes dans les prochains chapitres. Je vais vous faire peur : ici, nous avons captur une exception, mais nous pouvons en capturer plusieurs. . . Pour nir, je vous propose de tlcharger tous ces morceaux de codes que nous venons de voir ensemble.  Copier les codes Code web : 842950 

La gestion de plusieurs exceptions


Bien entendu, ceci est valable pour toutes sortes d'exceptions, qu'elles soient personnalises ou inhrentes Java ! Supposons que nous voulons lever une exception si le nom de la ville fait moins de 3 caractres. Nous allons rpter les premires tapes vues prcdemment, c'est--dire crer une classe NomVilleException :
puli lss xomilleixeption extends ixeption { puli xomilleixeption@tring messgeA{ super@messgeAY

164

LA GESTION DE PLUSIEURS EXCEPTIONS


}

Vous avez remarqu que nous avons utilis super. Avec cette rednition, nous pourrons acher notre message d'erreur en utilisant la mthode getMessage(). Voyez plutt. Ajoutez une condition dans le constructeur Ville :
puli ille@tring pxomD int pxreD tring pysA throws xomreritntixeptionD xomilleixeption { if@pxre ` HA throw new xomreritntixeption@pxreAY if@pxomFlength@A ` QA throw new xomilleixeption@4le nom de l ville est infrieur Q rtres 3 nom a 4 C pxomAY else { nresnstneCCY nresnstnefisCCY nomille a pxomY nomys a pysY nreritnt a pxreY thisFsetgtegorie@AY

Vous remarquez que les direntes erreurs dans l'instruction throws sont spares par une virgule. Nous sommes maintenant pars pour la capture de deux exceptions personnalises. Regardez comment on gre deux exceptions sur une instruction :
ille v a nullY try { v a new ille@4e4D IPHHHD 4prne4AY } GGqestion de l9exeption sur le nomre d9hitnts th @xomreritntixeption eA { eFprinttkre@AY } GGqestion de l9exeption sur le nom de l ville th@xomilleixeption ePA{ ystemFoutFprintln@ePFgetwessge@AAY } finlly{ if@v aa nullA v a new ille@AY } ystemFoutFprintln@vFtotring@AAY

165

CHAPITRE 14. LES EXCEPTIONS Constatez qu'un deuxime bloc catch{} s'est gliss. . . Eh bien, c'est comme cela que nous grerons plusieurs exceptions ! Si vous mettez un nom de ville de moins de 3 caractres et un nombre d'habitants ngatif, c'est l'exception du nombre d'habitants qui sera leve en premier, et pour cause : il s'agit de la premire condition dans notre constructeur. Lorsque plusieurs exceptions sont gres par une portion de code, pensez bien mettre les blocs catch dans un ordre pertinent.

En rsum
 Lorsqu'un vnement que la JVM ne sait pas grer apparat, une exception est leve (exemple : division par zro). Une exception correspond donc une erreur.  La superclasse qui gre les exceptions s'appelle Exception.  Vous pouvez crer une classe d'exception personnalise : faites-lui hriter de la classe Exception.  L'instruction qui permet de capturer des exceptions est le bloc try{} catch{}.  Si une exception est leve dans le bloc try, les instructions gurant dans le bloc catch seront excutes pour autant que celui-ci capture la bonne exception leve.  Vous pouvez ajouter autant de blocs catch que vous le voulez la suite d'un bloc try, mais respectez l'ordre : du plus pertinent au moins pertinent .  Dans une classe objet, vous pouvez prvenir la JVM qu'une mthode est dite  risque  grce au mot cl throws.  Vous pouvez dnir plusieurs risques d'exceptions sur une mme mthode. Il sut de sparer les dclarations par une virgule.  Dans cette mthode, vous pouvez dnir les conditions d'instanciation d'une exception et lancer cette dernire grce au mot cl throw suivi de l'instanciation.  Une instanciation lance par le biais de l'instruction throw doit tre dclare avec throws au pralable !

166

Chapitre

15
Dicult :

Les ux d'entre/sortie

ne entre/sortie en Java consiste en un change de donnes entre le programme et une autre source, par exemple la mmoire, un chier, le programme lui-mme. . . Pour raliser cela, Java emploie ce qu'on appelle un stream (qui signie  ux ). Celui-ci joue le rle de mdiateur entre la source des donnes et sa destination. Nous allons voir que Java met notre disposition toute une panoplie d'objets permettant de communiquer de la sorte. Toute opration sur les entres/sorties doit suivre le schma suivant : ouverture, lecture, fermeture du ux. Je ne vous cache pas qu'il existe une foule d'objets qui ont chacun leur faon de travailler avec les ux. Sachez que Java a dcompos les objets traitant des ux en deux catgories :  les objets travaillant avec des ux d'entre ( in), lecture de ux ;  les objets travaillant avec des ux de sortie ( out), criture de ux.

167

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE

Utilisation de java.io
L'objet File
Avant de commencer, crez un chier avec l'extension que vous voulez pour le moment, et enregistrez-le la racine de votre projet Eclipse. Personnellement, je me suis fait un chier test.txt dont voici le contenu :
oii une ligne de testF oii une utre ligne de testF it omme je suis motivD en voii une troisime 3

Dans votre projet Eclipse, faites un clic droit sur le dossier de votre projet, puis New File. Vous pouvez nommer votre chier ainsi qu'y taper du texte ! Le nom du dossier contenant mon projet s'appelle  IO  et mon chier texte est cette adresse :  D :\Mes documents\Codage\SDZ\Java-SDZ\IO\test.txt . Nous allons maintenant voir ce dont l'objet File est capable. Vous remarquerez que cet objet est trs simple utiliser et que ses mthodes sont trs explicites.
GGkge importer fin d9utiliser l9ojet pile import jvFioFpileY puli lss win { puli stti void min@tring rgsA { GGgrtion de l9ojet pile pile f a new pile@4testFtxt4AY ystemFoutFprintln@4ghemin solu du fihier X 4 C fFgetesoluteth@AAY ystemFoutFprintln@4xom du fihier X 4 C fFgetxme@AAY ystemFoutFprintln@4istEe qu9il existe c 4 C fFexists@AAY ystemFoutFprintln@4istEe un rpertoire c 4 C fFishiretory@AAY ystemFoutFprintln@4istEe un fihier c 4 C fFispile@AAY ystemFoutFprintln@4effihge des leteurs l rine du g X 4AY for@pile file X fFlistoots@AA { ystemFoutFprintln@fileFgetesoluteth@AAY try { int i a IY GGyn prourt l liste des fihiers et rpertoires for@pile nom X fileFlistpiles@AA{ GG9il s9git d9un dossierD on joute un 4G4 ystemFoutFprint@4tt4 C @@nomFishiretory@AA c nomFgetxme@AC4G4 X nomFgetxme@AAAY if@@i7RA aa HA{ ystemFoutFprint@4n4AY } iCCY

168

UTILISATION DE JAVA.IO
ystemFoutFprintln@4n4AY } th @xullointerixeption eA { GGv9instrution peut gnrer une xullointerixeption GGs9il n9y ps de sousEfihier 3 }

Copier ce code Code web : 604161  Le rsultat est bluant (gure 15.1).

Figure

15.1  Test de l'objet File

Vous conviendrez que les mthodes de cet objet peuvent s'avrer trs utiles ! Nous venons d'en essayer quelques-unes et nous avons mme list les sous-chiers et sousdossiers de nos lecteurs la racine du PC. Vous pouvez aussi eacer le chier grce la mthode delete(), crer des rpertoires avec la mthode mkdir() 1 . . . Maintenant que vous en savez un peu plus sur cet objet, nous pouvons commencer travailler avec notre chier !

Les objets

FileInputStream

et FileOutputStream

C'est par le biais de ces objets que nous allons pouvoir :  lire dans un chier ;  crire dans un chier.
1. Le nom donn ce rpertoire ne pourra cependant pas contenir de point ( . ).

169

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE Ces classes hritent des classes abstraites InputStream et OutputStream, prsentes dans le package java.io. Comme vous l'avez sans doute devin, il existe une hirarchie de classes pour les traitements in et une autre pour les traitements out. Ne vous y trompez pas, les classes hritant d'InputStream sont destines la lecture et les classes hritant d' OutputStream se chargent de l'criture ! C'est bizarre, n'est-ce pas ? Vous auriez dit le contraire. . . Comme beaucoup de gens au dbut. Mais c'est uniquement parce que vous situez les ux par rapport vous, et non votre programme ! Lorsque ce dernier va lire des informations dans un chier, ce sont des informations qu'il reoit, et par consquent, elles s'apparentent une entre : in 2 . Au contraire, lorsqu'il va crire dans un chier 3 , par exemple, il va faire sortir des informations ; donc, pour lui, ce ux de donnes correspond une sortie : out. Nous allons enn commencer travailler avec notre chier. Le but est d'aller en lire le contenu et de le copier dans un autre, dont nous spcierons le nom dans notre programme, par le biais d'un programme Java. Ce code est assez compliqu, donc accrochez-vous vos claviers !
GGkges importer fin d9utiliser les ojets import jvFioFpileY import jvFioFpilesnputtremY import jvFioFpilexotpoundixeptionY import jvFioFpileyutputtremY import jvFioFsyixeptionY puli lss win { puli stti void min@tring rgsA { GGxous dlrons nos ojets en dehors du lo tryGth pilesnputtrem fis a nullY pileyutputtrem fos a nullY try { GGyn instnie nos ojets X GGfis v lire le fihier et GGfos v rire dns le nouveu 3 fis a new pilesnputtrem@new pile@4testFtxt4AAY fos a new pileyutputtrem@new pile@4testPFtxt4AAY GGyn re un tleu de yte GGpour indiquer le nomre de ytes GGlus hque tour de oule yte uf a new yteVY

2. Sachez tout de mme que lorsque vous tapez au clavier, cette action est considre comme un ux d'entre ! 3. Ou l'cran, souvenez-vous de System.out.println .

170

UTILISATION DE JAVA.IO
GGyn re une vrile de type int GGpour y ffeter le rsultt de l leture GGut EI qund 9est fini int n a HY GGnt que l9ffettion dns l vrile est possileD on oule GGvorsque l leture du fihier est termine GGl9ffettion n9est plus possile 3 GGyn sort don de l oule while@@n a fisFred@ufAA ba HA { GGyn rit dns notre deuxime fihier GGve l9ojet dqut fosFwrite@ufAY GGyn ffihe e qu9 lu notre oule GGu formt yte et u formt hr for@yte it X ufA ystemFoutFprint@4t4 C it C 4@4 C @hrAit C 4A4AY ystemFoutFprintln@44AY } ystemFoutFprintln@4gopie termine 34AY } th @pilexotpoundixeption eA { GGgette exeption est leve GGsi l9ojet pilesnputtrem ne trouve uun fihier eFprinttkre@AY } th @syixeption eA { GGgelleEi se produit lors d9une erreur GGd9riture ou de leture eFprinttkre@AY } finlly{ GGyn ferme nos flux de donnes dns un lo finlly GGpour s9ssurer que es instrutions seront exutes GGdns tous les s mme si une exeption est leve 3 try{ if@fis 3a nullA fisFlose@AY if@fos 3a nullA fosFlose@AY }th@syixeption eA{ eFprinttkre@AY } } }

Copier ce code Code web : 530777 

171

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE

Pour que l'objet FileInputStream fonctionne, le chier doit exister ! Sinon l'exception FileNotFoundException est leve. Par contre, si vous ouvrez un ux en criture ( FileOutputStream) vers un chier inexistant, celui-ci sera cr automatiquement !
Notez bien les imports pour pouvoir utiliser ces objets. Mais comme vous le savez dj, vous pouvez taper votre code et faire ensuite  CTRL + SHIFT + O  pour que les imports soient automatiques. l'excution de ce code, vous pouvez voir que le chier test2.txt a bien t cr et qu'il contient exactement la mme chose que test.txt ! De plus, j'ai ajout dans la console les donnes que votre programme va utiliser (lecture et criture). La gure 15.2 reprsente le rsultat de ce code.

Figure

15.2  Copie de chier

Le bloc finally permet de s'assurer que nos objets ont bien ferm leurs liens avec leurs chiers respectifs, ceci an de permette Java de dtruire ces objets pour ainsi librer un peu de mmoire votre ordinateur.

En eet, les objets utilisent des ressources de votre ordinateur que Java ne peut pas librer de lui-mme, vous devez tre sr que la vanne est ferme ! Ainsi, mme si une exception est leve, le contenu du bloc finally sera excut et nos ressources seront libres. Par contre, pour allger la lecture, je ne mettrai plus ces blocs dans les codes venir mais pensez bien les mettre dans vos codes.
Les objets FileInputStream et FileOutputStream sont assez rudimentaires, car ils travaillent avec un nombre dtermin d'octets lire. Cela explique pourquoi ma condition de boucle tait si tordue. . . 172

UTILISATION DE JAVA.IO

Voici un rappel important : lorsque vous voyez des caractres dans un chier ou
sur votre cran, ils ne veulent pas dire grand-chose pour votre PC, car il ne comprend que le binaire (vous savez, les suites de 0 et de 1). Ainsi, an de pouvoir acher et travailler avec des caractres, un systme d'encodage (qui a d'ailleurs fort volu) a t mis au point. Sachez que chaque caractre que vous saisissez ou que vous lisez dans un chier correspond un code binaire, et ce code binaire correspond un code dcimal. Voyez la table de correspondance 4 .


Table de correspondance Code web : 277885 

Cependant, au dbut, seuls les caractres de a z, de A Z et les chires de 0 9 (les 127 premiers caractres de la table ci-dessus) taient cods (UNICODE 1), correspondant aux caractres se trouvant dans la langue anglaise. Mais ce codage s'est rapidement avr trop limit pour des langues comportant des caractres accentus (franais, espagnol. . .). Un jeu de codage de caractres tendu a t mis en place an de pallier ce problme. Chaque code binaire UNICODE 1 est cod sur 8 bits, soit 1 octet. Une variable de type byte, en Java, correspond en fait 1 octet et non 1 bit ! Les objets que nous venons d'utiliser emploient la premire version d'UNICODE 1 qui ne comprend pas les caractres accentus, c'est pourquoi ces caractres ont un code dcimal ngatif dans notre chier. Lorsque nous dnissons un tableau de byte 8 entres, cela signie que nous allons lire 8 octets la fois. Vous pouvez voir qu' chaque tour de boucle, notre tableau de byte contient huit valeurs correspondant chacune un code dcimal qui, lui, correspond un caractre 5 . Vous pouvez voir que les codes dcimaux ngatifs sont inconnus, car ils sont reprsents par des  ?  ; de plus, il y a des caractres invisibles 6 dans notre chier :  les espaces : SP pour SPace, code dcimal 32 ;  les sauts de lignes : LF pour Line Feed, code dcimal 13 ;  les retours chariot : CR pour Carriage Return, code dcimal 10. Vous voyez que les traitements des ux suivent une logique et une syntaxe prcises ! Lorsque nous avons copi notre chier, nous avons rcupr un certain nombre d'octets dans un ux entrant que nous avons pass un ux sortant. chaque tour de boucle, les donnes lues dans le chier source sont crites dans le chier dni comme copie. Il existe prsent des objets beaucoup plus faciles utiliser, mais qui travaillent nanmoins avec les deux objets que nous venons d'tudier. Ces objets font galement partie de la hirarchie cite prcdemment. . . Seulement, il existe une superclasse qui les dnit.
4. On parle de la table ASCII. 5. Valeur entre parenthses ct du code dcimal. 6. Les 32 premiers caractres de la table ASCII sont invisibles !

173

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE

Les objets

FilterInputStream

et FilterOutputStream

Ces deux classes sont en fait des classes abstraites. Elles dnissent un comportement global pour leurs classes lles qui, elles, permettent d'ajouter des fonctionnalits aux ux d'entre/sortie ! La gure 15.3 reprsente un diagramme de classes schmatisant leur hirarchie.

Figure

15.3  Hirarchie des classes du package java.io

Vous pouvez voir qu'il existe quatre classes lles hritant de FilterInputStream (de mme pour FilterOutputStream 7 ).  DataInputStream : ore la possibilit de lire directement des types primitifs ( double, char, int) grce des mthodes comme readDouble(), readInt(). . .  BufferedInputStream : cette classe permet d'avoir un tampon disposition dans la lecture du ux. En gros, les donnes vont tout d'abord remplir le tampon, et ds que celui-ci est plein, le programme accde aux donnes.  PushbackInputStream : permet de remettre un octet dj lu dans le ux entrant.  LineNumberInputStream : cette classe ore la possibilit de rcuprer le numro de la ligne lue un instant T. Ces classes prennent en paramtre une instance drivant des classes InputStream(pour les classes hritant de FilterInputStream) ou de OutputStream (pour les classes hritant de FilterOutputStream). Puisque ces classes acceptent une instance de leur superclasse en paramtre, vous pouvez cumuler les ltres et obtenir des choses de ce genre :
7. Les classes drivant de FilterOutputStream ont les mmes fonctionnalits, mais en criture.

174

UTILISATION DE JAVA.IO
pilesnputtrem fis a new pilesnputtrem@new pile@4totoFtxt4AAY htsnputtrem dis a new htsnputtrem@fisAY fufferedsnputtrem is a new fufferedsnputtrem@disAY GGyu en ondens X fufferedsnputtrem is a new fufferredsnputtrem@ new htsnputtrem@ new pilesnputtrem@ new pile@4totoFtxt4AAAAY

An de vous rendre compte des amliorations apportes par ces classes, nous allons lire un norme chier texte (3,6 Mo) de faon conventionnelle avec l'objet vu prcdemment, puis grce un buer. Tlcharger le chier Code web : 588152  Rcuprez le chier compress grce un logiciel de compression/dcompression et remplacez le contenu de votre chier test.txt par le contenu de ce chier. Maintenant, voici un code qui permet de tester le temps d'excution de la lecture :
GGkges importer fin d9utiliser l9ojet pile import jvFioFfufferedsnputtremY import jvFioFhtsnputtremY import jvFioFpileY import jvFioFpilesnputtremY import jvFioFpilexotpoundixeptionY import jvFioFpileyutputtremY import jvFioFsyixeptionY puli lss win { puli stti void min@tring rgsA { GGxous dlrons nos ojets en dehors du lo tryGth pilesnputtrem fisY fufferedsnputtrem isY try { fis a new pilesnputtrem@new pile@4testFtxt4AAY is a new fufferedsnputtrem@new pilesnputtrem@new pile@4 testFtxt4AAAY yte uf a new yteVY GGyn rupre le temps du systme long strtime a ystemFurrentimewillis@AY GGsnutile d9effetuer des tritements dns notre oule while@fisFred@ufA 3a EIAY GGyn ffihe le temps d9exution ystemFoutFprintln@4emps de leture ve pilesnputtrem X 4 C @ystemFurrentimewillis@A E strtimeAAY GGyn rinitilise strtime a ystemFurrentimewillis@AY

175

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE


GGsnutile d9effetuer des tritements dns notre oule while@isFred@ufA 3a EIAY GGyn rffihe ystemFoutFprintln@4emps de leture ve fufferedsnputtrem X 4 C @ystemFurrentimewillis@A E strtimeAAY GGyn ferme nos flux de donnes fisFlose@AY isFlose@AY } th @pilexotpoundixeption eA { eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY }

Et le rsultat (gure 15.4) est encore une fois bluant.

Figure

15.4  Comparatif de lecture avec et sans ltre

La dirence de temps est vraiment norme : 1,578 seconde pour la premire mthode et 0,094 seconde pour la deuxime ! Vous conviendrez que l'utilisation d'un buer permet une nette amlioration des performances de votre code. Faisons donc sans plus tarder le test avec l'criture :
GGkges importer fin d9utiliser l9ojet pile import jvFioFfufferedsnputtremY import jvFioFfufferedyutputtremY import jvFioFpileY import jvFioFpilesnputtremY import jvFioFpilexotpoundixeptionY import jvFioFpileyutputtremY import jvFioFsyixeptionY puli lss win { puli stti void min@tring rgsA { GGxous dlrons nos ojets en dehors du lo tryGth pilesnputtrem fisY pileyutputtrem fosY fufferedsnputtrem isY fufferedyutputtrem osY

176

UTILISATION DE JAVA.IO
try {

testFtxt4AAAY

fis a new pilesnputtrem@new pile@4testFtxt4AAY fos a new pileyutputtrem@new pile@4testPFtxt4AAY is a new fufferedsnputtrem@new pilesnputtrem@new pile@4

os a new fufferedyutputtrem@new pileyutputtrem@new pile@4 testQFtxt4AAAY yte uf a new yteVY GGyn rupre le temps du systme long strtime a ystemFurrentimewillis@AY while@fisFred@ufA 3a EIA{ fosFwrite@ufAY } GGyn ffihe le temps d9exution ystemFoutFprintln@4emps de leture C riture ve pilesnputt rem et pileyutputtrem X 4 C @ystemFurrentimewillis@A E strtimeAAY GGyn rinitilise strtime a ystemFurrentimewillis@AY while@isFred@ufA 3a EIA{ osFwrite@ufAY } GGyn rffihe ystemFoutFprintln@4emps de leture C riture ve fufferedsn puttrem et fufferedyutputtrem X 4 C @ystemFurrentimewillis@A E strtimeAAY GGyn ferme nos flux de donnes fisFlose@AY isFlose@AY } th @pilexotpoundixeption eA { eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY }

L, la dirence est encore plus nette (gure 15.5). Si avec a, vous n'tes pas convaincus de l'utilit des buers. . . Je ne vais pas passer en revue tous les objets cits un peu plus haut, mais vu que vous risquez d'avoir besoin des objets Data(Input/Output)Stream , nous allons les aborder rapidement, puisqu'ils s'utilisent comme les objets BufferedInputStream. Je vous ai dit plus haut que ceux-ci ont des mthodes de lecture pour chaque type primitif : il faut cependant que le chier soit gnr par le biais d'un DataOutputStream pour que 177

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE

Figure

15.5  Comparatif d'criture avec et sans ltre

les mthodes fonctionnent correctement. Nous allons donc crer un chier de toutes pices pour le lire par la suite.
GGkges importer fin d9utiliser l9ojet pile import jvFioFfufferedsnputtremY import jvFioFfufferedyutputtremY import jvFioFhtsnputtremY import jvFioFhtyutputtremY import jvFioFpileY import jvFioFpilesnputtremY import jvFioFpilexotpoundixeptionY import jvFioFpileyutputtremY import jvFioFsyixeptionY puli lss win { puli stti void min@tring rgsA { GGxous dlrons nos ojets en dehors du lo tryGth htsnputtrem disY htyutputtrem dosY try { dos a new htyutputtrem@ new fufferedyutputtrem@ new pileyutputtrem@ new pile@4sdzFtxt4AAAAY GGxous llons rire hque type primitif dosFwritefoolen@trueAY dosFwritefyte@IHHAY dosFwriteghr@9g9AY dosFwritehoule@IPFHSAY dosFwriteplot@IHHFSPfAY dosFwritesnt@IHPRAY dosFwritevong@IPQRSTUVWTSRQPIvAY dosFwritehort@PAY dosFlose@AY GGyn rupre mintennt les donnes 3 dis a new htsnputtrem@ new fufferedsnputtrem@ new pilesnputtrem@ new pile@4sdzFtxt4AAAAY

178

UTILISATION DE JAVA.IO
ystemFoutFprintln@disFredfoolen@AAY ystemFoutFprintln@disFredfyte@AAY ystemFoutFprintln@disFredghr@AAY ystemFoutFprintln@disFredhoule@AAY ystemFoutFprintln@disFredplot@AAY ystemFoutFprintln@disFredsnt@AAY ystemFoutFprintln@disFredvong@AAY ystemFoutFprintln@disFredhort@AAY } th @pilexotpoundixeption eA { eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY }

La gure 15.6 correspond au rsultat de ce code.

Figure

15.6  Test avec les DataInputStream  DataOutputStream

Le code est simple, clair et concis. . . Vous avez pu constater que ce type d'objet ne manque pas de fonctionnalits ! Jusqu'ici, nous ne travaillions qu'avec des types primitifs, mais il est galement possible de travailler avec des objets !

Les objets

ObjectInputStream

et ObjectOutputStream

Vous devez savoir que lorsqu'on veut crire des objets dans des chiers, on appelle a la srialisation : c'est le nom que porte l'action de sauvegarder des objets ! Cela fait quelque temps dj que vous utilisez des objets et, j'en suis sr, vous avez dj souhait que certains d'entre eux soient rutilisables. . . Le moment est venu de sauver vos objets d'une mort certaine ! Pour commencer, nous allons voir comment srialiser un objet de notre composition. Voici la classe avec laquelle nous allons travailler :
GGkge importer import jvFioFerilizleY puli lss qme implements erilizle{ privte tring nomD styleY

179

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE


privte doule prixY puli qme@tring nomD tring styleD doule prixA { thisFnom a nomY thisFstyle a styleY thisFprix a prixY } puli tring totring@A{ return 4xom du jeu X 4 C thisFnom C 4ntyle de jeu X 4 C thisFstyle C 4nrix du jeu X 4 C thisFprix C 4n4Y }

Qu'est-ce que c'est que cette interface ? Tu n'as mme pas implment de mthode !
En fait, cette interface n'a pas de mthode rednir : l'interface Serializable est ce qu'on appelle une interface marqueur ! Rien qu'en implmentant cette interface dans un objet, Java sait que cet objet peut tre srialis ; et j'irai mme plus loin : si vous n'implmentez pas cette interface dans vos objets, ceux-ci ne pourront pas tre srialiss ! En revanche, si une superclasse implmente l'interface Serializable, ses enfants seront considrs comme srialisables. Voici ce que nous allons faire :  nous allons crer deux ou trois objets Game ;  nous allons les srialiser dans un chier de notre choix ;  nous allons ensuite les dsrialiser an de pouvoir les rutiliser. Vous avez srement dj senti comment vous allez vous servir de ces objets, mais travaillons tout de mme sur l'exemple que voici :
GGkges importer fin d9utiliser l9ojet pile import jvFioFfufferedsnputtremY import jvFioFfufferedyutputtremY import jvFioFhtsnputtremY import jvFioFhtyutputtremY import jvFioFpileY import jvFioFpilesnputtremY import jvFioFpilexotpoundixeptionY import jvFioFpileyutputtremY import jvFioFsyixeptionY import jvFioFyjetsnputtremY import jvFioFyjetyutputtremY puli lss win { puli stti void min@tring rgsA {

180

UTILISATION DE JAVA.IO
GGxous dlrons nos ojets en dehors du lo tryGth yjetsnputtrem oisY yjetyutputtrem oosY try { oos a new yjetyutputtrem@ new fufferedyutputtrem@ new pileyutputtrem@ new pile@4gmeFtxt4AAAAY GGxous llons rire hque ojet qme dns le fihier oosFwriteyjet@new qme@4essssin greed4D 4eventure4D RSFTWAAY oosFwriteyjet@new qme@4om ider4D 4lteforme4D PQFRSAAY oosFwriteyjet@new qme@4etris4D 4trtgie4D PFSHAAY GGxe ps oulier de fermer le flux 3 oosFlose@AY GGyn rupre mintennt les donnes 3 ois a new yjetsnputtrem@ new fufferedsnputtrem@ new pilesnputtrem@ new pile@4gmeFtxt4AAAAY try { ystemFoutFprintln@4effihge des jeux X4AY ystemFoutFprintln@4BBBBBBBBBBBBBBBBBBBBBBBBBn4AY ystemFoutFprintln@@@qmeAoisFredyjet@AAFtotring@AAY ystemFoutFprintln@@@qmeAoisFredyjet@AAFtotring@AAY ystemFoutFprintln@@@qmeAoisFredyjet@AAFtotring@AAY } th @glssxotpoundixeption eA { eFprinttkre@AY } oisFlose@AY } th @pilexotpoundixeption eA { eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY }

La dsrialisation d'un objet peut engendrer une ClassNotFoundException, pensez donc la capturer !
Et voyez le rsultat en gure 15.7. Ce qu'il se passe est simple : les donnes de vos objets sont enregistres dans le chier. 181

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE

Figure

15.7  Srialisation  dsrialisation

Mais que se passerait-il si notre objet Game avait un autre objet de votre composition en son sein ? Voyons a tout de suite. Crez la classe Notice comme suit :
puli lss xotie { privte tring lngue Y puli xotie@A{ thisFlngue a 4prnis4Y } puli xotie@tring lngA{ thisFlngue a lngY } puli tring totring@A { return 4t vngue de l notie X 4 C thisFlngue C 4n4Y } }

Nous allons maintenant implmenter une notice par dfaut dans notre objet Game. Voici notre classe modie :
import jvFioFerilizleY puli lss qme implements erilizle{ privte tring nomD styleY privte doule prixY privte xotie notieY puli qme@tring nomD tring styleD doule prixA { thisFnom a nomY thisFstyle a styleY thisFprix a prixY thisFnotie a new xotie@AY }

182

UTILISATION DE JAVA.IO
puli tring totring@A{ return 4xom du jeu X 4 C thisFnom C 4ntyle de jeu X 4 C thisFstyle C 4nrix du jeu X 4 C thisFprix C 4n4Y }

Ressayez votre code sauvegardant vos objets Game. La gure 15.8 nous montre le rsultat obtenu.

Figure

15.8  Erreur de srialisation

Eh non, votre code ne compile plus ! Il y a une bonne raison cela : votre objet Notice n'est pas srialisable, une erreur de compilation est donc leve. Maintenant, deux choix s'orent vous :  soit vous faites en sorte de rendre votre objet srialisable ;  soit vous spciez dans votre classe Game que la variable notice n'a pas tre srialise. Pour la premire option, c'est simple, il sut d'implmenter l'interface srialisable dans notre classe Notice. Pour la seconde, il sut de dclarer votre variable : transient. Comme ceci :
import jvFioFerilizleY puli lss qme implements erilizle{ privte tring nomD styleY privte doule prixY GGwintenntD ette vrile ne ser ps srilise GGille ser tout onnement ignore 3 privte trnsient xotie notieY puli qme@tring nomD tring styleD doule prixA { thisFnom a nomY thisFstyle a styleY thisFprix a prixY

183

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE


thisFnotie a new xotie@AY

puli tring totring@A{ return 4xom du jeu X 4 C thisFnom C 4ntyle de jeu X 4 C thisFstyle C 4nrix du jeu X 4 C thisFprix C 4n4Y }

Vous aurez sans doute remarqu que nous n'utilisons pas la variable notice dans la mthode toString() de notre objet Game. Si vous faites ceci, que vous srialisez puis dsrialisez vos objets, la machine virtuelle vous renverra l'exception NullPointerException l'invocation de ladite mthode. Eh oui ! L'objet Notice est ignor : il n'existe donc pas !

Les objets

CharArray(Writer/Reader)

et String(Writer/Reader)

Nous allons utiliser des objets :  CharArray(Writer/Reader) ;  String(Writer/Reader) . Ces deux types jouent quasiment le mme rle. De plus, ils ont les mmes mthodes que leur classe mre. Ces deux objets n'ajoutent donc aucune nouvelle fonctionnalit leur objet mre. Leur principale fonction est de permettre d'crire un ux de caractres dans un buer adaptatif : un emplacement en mmoire qui peut changer de taille selon les besoins 8 . Commenons par un exemple comment des objets CharArray(Writer/Reader) :
GGkges importer fin d9utiliser l9ojet pile import jvFioFghrerryederY import jvFioFghrerryriterY import jvFioFsyixeptionY puli lss win { puli stti void min@tring rgsA { ghrerryriter w a new ghrerryriter@AY ghrerryeder rY try { wFwrite@4gouou les ros4AY GGeppel l mthode totring

8. Nous n'en avons pas parl dans le chapitre prcdent an de ne pas l'alourdir, mais il existe des classes remplissant le mme rle que ces classes-ci : ByteArray(Input/Output)Stream .

184

UTILISATION DE JAVA.IO
GGde notre ojet de mnire tite ystemFoutFprintln@wAY GGwFlose@A n9 uun effet sur le flux GGeul wFreset@A peut tout effer wFlose@AY GGyn psse un tleu de rtres l9ojet GGqui v lire le tmpon r a new ghrerryeder@wFtoghrerry@AAY int iY GGyn remet tous les rtres lus dns un tring tring str a 44Y while@@ i a rFred@AA 3a EIA str Ca @hrA iY ystemFoutFprintln@strAY } th @syixeption eA { eFprinttkre@AY }

Je vous laisse le soin d'examiner ce code ainsi que son eet. Il est assez comment pour que vous en compreniez toutes les subtilits. L'objet String(Writer/Reader) fonctionne de la mme faon :
GGkges importer fin d9utiliser l9ojet pile import jvFioFsyixeptionY import jvFioFtringederY import jvFioFtringriterY puli lss win { puli stti void min@tring rgsA { tringriter sw a new tringriter@AY tringeder srY try { swFwrite@4gouou les ros4AY GGeppel l mthode totring GGde notre ojet de mnire tite ystemFoutFprintln@swAY GGwFlose@A n9 uun effet sur le flux GGeul wFreset@A peut tout effer swFlose@AY GGyn psse un tleu de rtres l9ojet GGqui v lire le tmpon

185

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE


sr a new tringeder@swFtotring@AAY int i Y GGyn remet tous les rtres lus dns un tring tring str a 44Y while@@ i a srFred@AA 3a EIA str Ca @hrA iY ystemFoutFprintln@strAY } th @syixeption eA { eFprinttkre@AY }

En fait, il s'agit du mme code, mais avec des objets dirents ! Vous savez prsent comment crire un ux de texte dans un tampon de mmoire. . . Je vous propose maintenant de voir comment traiter les chiers de texte avec des ux de caractres.

Les classes

File(Writer/Reader)

et Print(Writer/Reader)

Comme nous l'avons vu, les objets travaillant avec des ux utilisent des ux binaires. La consquence est que mme si vous ne mettez que des caractres dans un chier et que vous le sauvegardez, les objets tudis prcdemment traiteront votre chier de la mme faon que s'il contenait des donnes binaires ! Ces deux objets, prsents dans le package java.io, servent lire et crire des donnes dans un chier texte.
import import import import import jvFioFpileY jvFioFpilexotpoundixeptionY jvFioFpileederY jvFioFpileriterY jvFioFsyixeptionY

puli lss win { puli stti void min@tring rgsA { pile file a new pile@4testpileriterFtxt4AY pileriter fwY pileeder frY try { GGgrtion de l9ojet fw a new pileriter@fileAY tring str a 4fonjour tousD mis ros 3n4Y str Ca 4tgomment llezEvous c n4Y GGyn rit l hne fwFwrite@strAY GGyn ferme le flux

186

UTILISATION DE JAVA.NIO
fwFlose@AY GGgrtion de l9ojet de leture fr a new pileeder@fileAY str a 44Y int i a HY GGveture des donnes while@@i a frFred@AA 3a EIA str Ca @hrAiY GGeffihge ystemFoutFprintln@strAY } th @pilexotpoundixeption eA { eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY }

Vous pouvez voir que l'achage est bon et qu'un nouveau chier 9 vient de faire son apparition dans le dossier contenant votre projet Eclipse ! Depuis le JDK 1.4, un nouveau package a vu le jour, visant amliorer les performances des ux, buers, etc. traits par java.io. En eet, vous ignorez probablement que le package que nous explorons depuis le dbut existe depuis la version 1.1 du JDK. Il tait temps d'avoir une remise niveau an d'amliorer les rsultats obtenus avec les objets traitant les ux. C'est l que le package java.nio a vu le jour !

Utilisation de java.nio
Vous l'avez srement devin, nio signie New I/O. Comme je vous l'ai dit prcdemment, ce package a t cr an d'amliorer les performances sur le traitement des chiers, du rseau et des buers. Ce package permet de lire les donnes 10 d'une faon dirente. Vous avez constat que les objets du package java.io traitaient les donnes par octets. Les objets du package java.nio, eux, les traitent par blocs de donnes : la lecture est donc acclre ! Tout repose sur deux objets de ce nouveau package : les channels et les buers. Les channels sont en fait des ux, tout comme dans l'ancien package, mais ils sont amens travailler avec un buer dont vous dnissez la taille. Pour simplier au maximum, lorsque vous ouvrez un ux vers un chier avec un objet FileInputStream, vous pouvez rcuprer un canal vers ce chier. Celui-ci, comFileNotFoundException , et l'criture peut entraner une IOException.

9. Tout comme dans le chapitre prcdent, la lecture d'un chier inexistant entrane l'exception

10. Nous nous intresserons uniquement l'aspect chier.

187

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE bin un buer, vous permettra de lire votre chier encore plus vite qu'avec un BufferedInputStream ! Reprenez le gros chier que je vous ai fait crer dans la sous-section prcdente : nous allons maintenant le relire avec ce nouveau package en comparant le buer conventionnel et la nouvelle faon de faire.
GGkges importer fin d9utiliser l9ojet pile import jvFioFfufferedsnputtremY import jvFioFpileY import jvFioFpilesnputtremY import jvFioFpilexotpoundixeptionY import jvFioFsyixeptionY import jvFnioFfytefufferY import jvFnioFghrfufferY import jvFnioFhnnelsFpileghnnelY puli lss win { puli stti void min@tring rgsA { pilesnputtrem fisY fufferedsnputtrem isY pileghnnel fY try { GGgrtion des ojets fis a new pilesnputtrem@new pile@4testFtxt4AAY is a new fufferedsnputtrem@fisAY GGhmrrge du hrono long time a ystemFurrentimewillis@AY GGveture while@isFred@A 3a EIAY GGemps d9exution ystemFoutFprintln@4emps d9exution ve un uffer onventionnel X 4 C @ystemFurrentimewillis@A E timeAAY GGgrtion d9un nouveu flux de fihier fis a new pilesnputtrem@new pile@4testFtxt4AAY GGyn rupre le nl f a fisFgetghnnel@AY GGyn en dduit l tille int size a @intAfFsize@AY GGyn re un uffer GGorrespondnt l tille du fihier fytefuffer fuff a fytefufferFllote@sizeAY GGhmrrge du hrono time a ystemFurrentimewillis@AY GGhmrrge de l leture fFred@fuffAY GGyn prpre l leture ve l9ppel flip

188

UTILISATION DE JAVA.NIO
fuffFflip@AY GGeffihge du temps d9exution ystemFoutFprintln@4emps d9exution ve un nouveu uffer X 4 C @ystemFurrentimewillis@A E timeAAY GGuisque nous vons utilis un uffer de yte GGfin de ruprer les donnesD nous pouvons utiliser GGun tleu de yte GGv mthode rry retourne un tleu de yte yte tfyte a fuffFrry@AY } th @pilexotpoundixeption eA { eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY } }

La gure 15.9 vous montre le rsultat.

Figure

15.9  Test des objets du package java.nio

Vous constatez que les gains en performances ne sont pas ngligeables. . . Sachez aussi que ce nouveau package est le plus souvent utilis pour traiter les ux circulant sur les rseaux. Je ne m'attarderai pas sur le sujet, mais une petite prsentation est de mise. Ce package ore un buer par type primitif pour la lecture sur le channel, vous trouverez donc ces classes :  IntBuffer ;  CharBuffer ;  ShortBuffer ;  ByteBuffer ;  DoubleBuffer ;  FloatBuffer ;  LongBuffer. Je ne l'ai pas fait durant tout le chapitre an d'allger un peu les codes, mais si vous voulez tre srs que votre ux est bien ferm, utilisez la clause finally, comme je vous le disais lors du chapitre sur les exceptions. Par exemple, faites comme ceci :
GGkges importer fin d9utiliser l9ojet pile GGFFF

189

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE


puli lss win { puli stti void min@tring rgsA { GGxous dlrons nos ojets en dehors du lo try G th yjetsnputtrem oisY yjetyutputtrem oosY try { GGyn trville ve nos ojets

} th @pilexotpoundixeption eA { GGqestion des exeptions } th @syixeption eA { GGqestion des exeptions } finlly{ if@ois 3a nullAoisFlose@AY if@oos 3a nullAoosFlose@AY

Le pattern decorator
Vous avez pu remarquer que les objets de ce chapitre utilisent des instances d'objets de mme supertype dans leur constructeur. Rappelez-vous cette syntaxe :
htsnputtrem dis a new htsnputtrem@ new fufferedsnputtrem@ new pilesnputtrem@ new pile@4sdzFtxt4AAAAY

La raison d'agir de la sorte est simple : c'est pour ajouter de faon dynamique des fonctionnalits un objet. En fait, dites-vous qu'au moment de rcuprer les donnes de notre objet DataInputStream, celles-ci vont d'abord transiter par les objets passs en paramtre. Ce mode de fonctionnement suit une certaine structure et une certaine hirarchie de classes : c'est le pattern decorator. Ce pattern de conception permet d'ajouter des fonctionnalits un objet sans avoir modier son code source. An de ne pas trop vous embrouiller avec les objets tudis dans ce chapitre, je vais vous fournir un autre exemple, plus simple, mais gardez bien en tte que les objets du package java.io utilisent ce pattern. Le but du jeu est d'obtenir un objet auquel nous pourrons ajouter des choses an de le  dcorer . . . Vous allez travailler avec un objet Gateau qui hritera d'une classe 190

LE PATTERN DECORATOR abstraite Patisserie. Le but du jeu est de pouvoir ajouter des couches notre gteau sans avoir modier son code source. Vous avez vu avec le pattern strategy que la composition 11 est souvent prfrable l'hritage 12 : vous aviez dni de nouveaux comportements pour vos objets en crant un supertype d'objet par comportement. Ce pattern aussi utilise la composition comme principe de base : vous allez voir que nos objets seront composs d'autres objets. La dirence rside dans le fait que nos nouvelles fonctionnalits ne seront pas obtenues uniquement en crant de nouveaux objets, mais en associant ceux-ci des objets existants. Ce sera cette association qui crera de nouvelles fonctionnalits ! Nous allons procder de la faon suivante :  nous allons crer un objet Gateau ;  nous allons lui ajouter une CoucheChocolat ;  nous allons aussi lui ajouter une CoucheCaramel ;  nous appellerons la mthode qui confectionnera notre gteau. Tout cela dmarre avec un concept fondamental : l'objet de base et les objets qui le dcorent doivent tre du mme type, et ce, toujours pour la mme raison, le polymorphisme, le polymorphisme, et le polymorphisme ! Vous allez comprendre. En fait, les objets qui vont dcorer notre gteau possderont la mme mthode preparer() que notre objet principal, et nous allons faire fondre cet objet dans les autres. Cela signie que nos objets qui vont servir de dcorateurs comporteront une instance de type Patisserie ; ils vont englober les instances les unes aprs les autres et du coup, nous pourrons appeler la mthode preparer() de manire rcursive ! Vous pouvez voir les dcorateurs comme des poupes russes : il est possible de mettre une poupe dans une autre. Cela signie que si nous dcorons notre gateau avec un objet CoucheChocolat et un objet CoucheCaramel, la situation pourrait tre symbolise par la gure 15.10.

Figure

15.10  Encapsulation des objets

L'objet CoucheCaramel contient l'instance de la classe CoucheChocolat qui, elle, contient l'instance de Gateau : en fait, on va passer notre instance d'objet en objet ! Nous allons ajouter les fonctionnalits des objets dcorants en appelant la mthode preparer() de l'instance se trouvant dans l'objet avant d'eectuer les traitements de la mme mthode de l'objet courant (gure 15.11).
11.  A un . 12.  Est un .

191

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE

Figure

15.11  Invocation des mthodes

Nous verrons, lorsque nous parlerons de la classe Thread, que ce systme ressemble fortement la pile d'invocations de mthodes. Voyons maintenant quoi ressemble le diagramme de classes de notre exemple (gure 15.12).

Figure

15.12  Diagramme de classes

Vous remarquez sur ce diagramme que notre classe mre Patisserie est en fait la strategy 13 de notre structure, c'est pour cela que nous pourrons appeler la mthode preparer() de faon rcursive an d'ajouter des fonctionnalits nos objets. Voici les direntes classes que j'ai utilises 14 .

Patisserie.java
puli strt lss tisserie { puli strt tring preprer@AY

13. Une classe encapsulant un comportement fait rfrence au pattern strategy : on peut dire qu'elle est la strategy de notre hirarchie. 14. Je n'ai utilis que des String an de ne pas surcharger les sources, et pour que vous vous focalisiez plus sur la logique que sur le code.

192

LE PATTERN DECORATOR
}

Gateau.java
puli lss qteu extends tisserie{ puli tring preprer@A { return 4te suis un gteu et je suis onstitu des lments sui vntsF n4Y } }

Couche.java
puli strt lss gouhe extends tisserie{ proteted tisserie ptY proteted tring nomY puli gouhe@tisserie pA{ pt a pY } puli tring preprer@A { tring str a ptFpreprer@AY return str C nomY }

CoucheChocolat.java
puli lss gouheghoolt extends gouhe{ puli gouheghoolt@tisserie pA { super@pAY thisFnom a 4tE ne ouhe de hooltFn4Y } }

CoucheCaramel.java
puli lss gouhegrmel extends gouhe{ puli gouhegrmel@tisserie pA { super@pAY thisFnom a 4tE ne ouhe de rmelFn4Y } }

193

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE

CoucheBiscuit.java
puli lss gouhefisuit extends gouhe { puli gouhefisuit@tisserie pA { super@pAY thisFnom a 4tE ne ouhe de isuitFn4Y } }

Et voici un code de test ainsi que son rsultat (gure 15.13).


puli lss win{ puli stti void min@tring rgsA{ tisserie pt a new gouheghoolt@ new gouhegrmel@ new gouhefisuit@ new gouheghoolt@ new qteu@AAAAAY ystemFoutFprintln@ptFpreprer@AAY } }

Figure

15.13  Rsultat du test

J'ai agrment l'exemple d'une couche de biscuit, mais je pense que tout cela est assez reprsentatif de la faon dont fonctionnent des ux d'entre/sortie en Java. Vous devriez russir saisir tout cela sans souci. Le fait est que vous commencez maintenant avoir en main des outils intressants pour programmer, et c'est sans compter les outils du langage : vous venez de mettre votre deuxime pattern de conception dans votre mallette du programmeur. Vous avez pu voir que l'invocation des mthodes se faisait en allant jusqu'au dernier lment pour remonter ensuite la pile d'invocations. Pour inverser ce fonctionnement, il vous sut d'inverser les appels dans la mthode preparer() : aecter d'abord le nom de la couche et ensuite le nom du dcorateur.

En rsum
 Les classes traitant des entres/sorties se trouvent dans le package java.io. 194

LE PATTERN DECORATOR  Les classes que nous avons tudies dans ce chapitre sont hrites des classes suivantes :  InputStream, pour les classes grant les ux d' entre ;  OutputStream, pour les classes grant les ux de sortie.  La faon dont on travaille avec des ux doit respecter la logique suivante :  ouverture de ux ;  lecture/criture de ux ;  fermeture de ux.  La gestion des ux peut engendrer la leve d'exceptions : FileNotFoundException , IOException. . .  L'action de sauvegarder des objets s'appelle la srialisation.  Pour qu'un objet soit srialisable, il doit implmenter l'interface Serializable.  Si un objet srialisable comporte un objet d'instance non srialisable, une exception sera leve lorsque vous voudrez sauvegarder votre objet.  L'une des solutions consiste rendre l'objet d'instance srialisable, l'autre le dclarer transient an qu'il soit ignor la srialisation.  L'utilisation de buers permet une nette amlioration des performances en lecture et en criture de chiers.  An de pouvoir ajouter des fonctionnalits aux objets grant les ux, Java utilise le pattern decorator.  Ce pattern permet d'encapsuler une fonctionnalit et de l'invoquer de faon rcursive sur les objets tant composs de dcorateurs.

195

CHAPITRE 15. LES FLUX D'ENTRE/SORTIE

196

Chapitre

16
Dicult :

Les numrations

es numrations constituent une notion nouvelle depuis Java 5. Ce sont des structures qui dnissent une liste de valeurs possibles. Cela vous permet de crer des types de donnes personnaliss. Nous allons par exemple construire le type Langage qui ne peut prendre qu'un certain nombre de valeurs : JAVA, PHP, C, etc. Le principe est trs simple, vous allez voir !

197

CHAPITRE 16. LES NUMRATIONS

Avant les numrations


Vous aurez sans doute besoin, un jour ou l'autre, de donnes permettant de savoir ce que vous devez faire. Beaucoup de variables statiques dans Java servent cela, vous le verrez bientt dans une prochaine partie. Voici le cas qui nous intresse :
puli lss evntinumertion { puli stti finl int eewI a IY puli stti finl int eewP a PY puli void fit@int prmA{ if@prm aa eewIA ystemFoutFprintln@4pit l fon xI4AY if@prm aa eewPA ystemFoutFprintln@4pit l fon xP4AY } puli stti void min@tring rgsA{ evntinumertion e a new evntinumertion@AY eFfit@evntinumertionFeewIAY eFfit@evntinumertionFeewPAY eFfit@RAY }

Voyons le rendu de ce test en gure 16.1.

Figure

16.1  Avant les numrations, des erreurs taient possibles

Je viens de vous montrer non seulement le principe dont je vous parlais, mais aussi sa faiblesse. . . Vous voyez que rien ne vous empche de passer un paramtre inattendu une mthode : c'est ce qui s'est pass la dernire ligne de notre test. Ici, rien de mchant, mais vous conviendrez tout de mme que le comportement de notre mthode est fauss ! Bien sr, vous pourriez crer un objet qui vous sert de paramtre de la mthode. Eh bien c'est cela que servent les enum : fabriquer ce genre d'objet de faon plus simple et plus rapide. 198

UNE SOLUTION : LES ENUM

Une solution : les enum


Une numration se dclare comme une classe, mais en remplaant le mot-cl class par enum. Autre dirence : les numrations hritent de la classe java.lang.Enum. Voici quoi ressemble une numration :
puli enum vngge { teeD gD glusD rY }

Rien de dicile ! Avec cela, vous obtenez une structure de donnes qui encapsule quatre  objets . En fait, c'est comme si vous aviez un objet JAVA, un objet C, un objet CPlus et un objet PHP partageant tous les mmes mthodes issues de la classe java.lang.Object comme n'importe quel autre objet : equals(), toString() , etc. Vous constatez aussi qu'il n'y a pas de dclaration de porte, ni de type : les numrations s'utilisent comme des variables statiques dclares public : on crira par exemple Langage.JAVA. De plus, vous pouvez recourir la mthode values() retournant la liste des dclarations de l'numration (voyez un exemple sur la gure 16.2 et son code ci-dessous).
puli lss win { puli stti void min@tring rgsA{ for@vngge lng X vnggeFvlues@AA{ if@vnggeFteeFequls@lngAA ystemFoutFprintln@4t9ime le X 4 C lngAY else ystemFoutFprintln@lngAY } } }

Figure

16.2  Utilisation d'une enum

Vous disposez ainsi d'un petit aperu de l'utilisation des numrations. Vous aurez pu constater que la mthode toString() retourne le nom de l'objet dni dans l'numration. prsent, toons tout cela en rednissant justement cette mthode. Pour ce faire, nous allons ajouter un paramtre dans notre numration, un constructeur et ladite mthode rednie. Voici notre nouvelle numration (rsultat en gure 16.3) : 199

CHAPITRE 16. LES NUMRATIONS


puli enum vngge { GGyjets diretement onstruits tee @4vngge tee4AD g @4vngge g4AD glus @4vngge gCC4AD r @4vngge r4AY privte tring nme a 44Y GGgonstruteur vngge@tring nmeA{ thisFnme a nmeY } puli tring totring@A{ return nmeY }

Figure

16.3  Utilisation d'un constructeur avec une enum

Mme remarque pour le constructeur : pas de dclaration de porte, pour une raison simple ; il est toujours considr comme private an de prserver les valeurs dnies dans l'enum. Vous noterez par ailleurs que les donnes formant notre numration sont directement construites dans la classe. Voici le code du dbut de chapitre, revu pour prfrer les numrations aux variables statiques :
puli lss evntinumertion { puli void fit@vngge prmA{ if@prmFequls@vnggeFteeAA ystemFoutFprintln@4pit l fon xI4AY if@prmFequls@vnggeFrAA ystemFoutFprintln@4pit l fon xP4AY } puli stti void min@tring rgsA{ evntinumertion e a new evntinumertion@AY eFfit@vnggeFteeAY eFfit@vnggeFrAY eFfit@RAY }

200

UNE SOLUTION : LES ENUM La gure 16.4 nous montre ce que cela donne. . .

Figure

16.4  Code du dbut de chapitre avec une enum

. . . une belle exception ! Normal, puisque la mthode attend un certain type d'argument, et que vous lui en passez un autre : supprimez la dernire ligne, le code fonctionnera trs bien. Maintenant, nous avons un mcanisme protg : seuls des arguments valides peuvent tre passs en paramtres de la mthode. Voici un petit exemple plus complet :
puli enum vngge { GGyjets diretement onstruits tee@4vngge tee4D 4ilipse4AD g @4vnge g4D 4gode flok4AD glus @4vngge gCC4D 4isul studio4AD r @4vngge r4D 4 d4AY privte tring nme a 44Y privte tring editor a 44Y GGgonstruteur vngge@tring nmeD tring editorA{ thisFnme a nmeY thisFeditor a editorY } puli void getiditor@A{ ystemFoutFprintln@4iditeur X 4 C editorAY } puli tring totring@A{ return nmeY } puli stti void min@tring rgsA{ vngge lI a vnggeFteeY vngge lP a vnggeFrY lIFgetiditor@AY lPFgetiditor@AY

Voyons le rsultat de cet exemple en gure 16.5. . . 201

CHAPITRE 16. LES NUMRATIONS

Figure

16.5  Exemple plus complet

Vous voyez ce que je vous disais : les numrations ne sont pas trs diciles utiliser et nos programmes y gagnent en rigueur et en clart.

En rsum
     Une numration est une classe contenant une liste de sous-objets. Une numration se construit grce au mot cl enum. Les enum hritent de la classe java.lang.Enum. Chaque lment d'une numration est un objet part entire. Vous pouvez complter les comportements des objets d'une numration en ajoutant des mthodes.

202

Chapitre

17
Dicult :

Les collections d'objets

oici une partie qui va particulirement vous plaire. . . Nous allons voir que nous ne sommes pas obligs de stocker nos donnes dans des tableaux ! Ces fameuses collections d'objets sont d'ailleurs dynamiques : en gros, elles n'ont pas de taille prdnie. Il est donc impossible de dpasser leur capacit ! Je ne passerai pas en revue tous les types et tous les objets Collection car ils sont nombreux, mais nous verrons les principaux d'entre eux. Les objets que nous allons aborder ici sont tous dans le package java.util, facile retenir, non ? Ce chapitre vous sera d'une grande utilit, car les collections sont primordiales dans les programmes Java.

203

CHAPITRE 17. LES COLLECTIONS D'OBJETS

Les dirents types de collections


Avant de vous prsenter certains objets, je me propose de vous prsenter la hirarchie d'interfaces composant ce qu'on appelle les collections. Oui, vous avez bien lu, il s'agit bien d'interfaces : celles-ci encapsulent la majeure partie des mthodes utilisables avec toutes les implmentations concrtes. Voici un petit diagramme de classes sur la gure 17.1 schmatisant cette hirarchie.

Figure

17.1  Hirarchie d'interfaces

Vous pouvez voir qu'il existe plusieurs types de collections, que les interfaces List et Set implmentent directement l'interface Collection et que l'interface Map gravite autour de cette hirarchie, tout en faisant partie des collections Java. En lisant la suite de ce chapitre, vous constaterez que ces interfaces ont des particularits correspondant des besoins spciques. Les objets de type List servent stocker des objets sans condition particulire sur la faon de les stocker. Ils acceptent toutes les valeurs, mme les valeurs null. Les types Set sont un peu plus restrictifs, car ils n'autorisent pas deux fois la mme valeur (le mme objet), ce qui est pratique pour une liste d'lments uniques, par exemple. Les Map sont particulires, car elles fonctionnent avec un systme cl - valeur pour ranger et retrouver les objets qu'elles contiennent. Maintenant que je vous ai brivement expliqu les dirences entre ces types, voyons comment utiliser ces objets. 204

LES OBJETS LIST

Les objets List


Les objets appartenant la catgorie List sont, pour simplier, des tableaux extensibles volont. On y trouve les objets Vector, LinkedList et ArrayList. Vous pouvez y insrer autant d'lments que vous le souhaitez sans craindre de dpasser la taille de votre tableau. Ils fonctionnent tous de la mme manire : vous pouvez rcuprer les lments de la liste via leurs indices. De plus, les List contiennent des objets. Je vous propose de voir deux objets de ce type qui, je pense, vous seront trs utiles.

L'objet LinkedList
Une liste chane 1 est une liste dont chaque lment est li aux lments adjacents par une rfrence ces derniers. Chaque lment contient une rfrence l'lment prcdent et l'lment suivant, excepts le premier, dont l'lment prcdent vaut null, et le dernier, dont l'lment suivant vaut galement null. Voici un petit schma (gure 17.2) qui vous permettra de mieux vous reprsenter le fonctionnement de cet objet :

Figure

17.2  Fonctionnement de la LinkedList

Voici un petit code pour appuyer mes dires :


import jvFutilFvinkedvistY import jvFutilFvistY import jvFutilFviststertorY puli lss est { puli stti void min@tring rgsA {

1. LinkedList en anglais.

205

CHAPITRE 17. LES COLLECTIONS D'OBJETS

vist l a new vinkedvist@AY lFdd@IPAY lFdd@4toto 3 34AY lFdd@IPFPHfAY for@int i a HY i ` lFsize@AY iCCA ystemFoutFprintln@4lment l9index 4 C i C 4 a 4 C lFget@iAAY } }

Si vous essayez ce code, vous constaterez que tous les lments s'achent ! Il y a autre chose que vous devez savoir sur ce genre d'objet : ceux-ci implmentent l'interface Iterator. Ainsi, nous pouvons utiliser cette interface pour lister notre LinkedList. Un itrateur est un objet qui a pour rle de parcourir une collection. C'est d'ailleurs son unique raison d'tre. Pour tre tout fait prcis, l'utilisation des itrateurs dans Java fonctionne de la mme manire que le pattern du mme nom. Tout comme nous avons pu le voir avec la pattern strategy, les design patterns sont en fait des modles de conception d'objets permettant une meilleure stabilit et une rutilisabilit accrue. Les itrateurs en font partie. Dans le code suivant, j'ai ajout le parcours avec un itrateur :
import jvFutilFvinkedvistY import jvFutilFvistY import jvFutilFviststertorY puli lss est { puli stti void min@tring rgsA { vist l a new vinkedvist@AY lFdd@IPAY lFdd@4toto 3 34AY lFdd@IPFPHfAY for@int i a HY i ` lFsize@AY iCCA ystemFoutFprintln@4lment l9index 4 C i C 4 a 4 C lFget@iAAY ystemFoutFprintln@4n trours ve un itrteur 4AY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY viststertor li a lFliststertor@AY while@liFhsxext@AA ystemFoutFprintln@liFnext@AAY

206

LES OBJETS LIST Les deux manires de procder sont analogues ! Attention, je dois vous dire quelque chose sur les listes chanes : vu que tous les lments contiennent une rfrence l'lment suivant, de telles listes risquent de devenir particulirement lourdes en grandissant ! Cependant, elles sont adaptes lorsqu'il faut beaucoup manipuler une collection en supprimant ou en ajoutant des objets en milieu de liste. Elles sont donc utiliser avec prcaution.

L'objet ArrayList
Voici un objet bien pratique. ArrayList est un de ces objets qui n'ont pas de taille limite et qui, en plus, acceptent n'importe quel type de donnes, y compris null ! Nous pouvons mettre tout ce que nous voulons dans un ArrayList, voici un morceau de code qui le prouve :
import jvFutilFerryvistY puli lss est { puli stti void min@tring rgsA { erryvist l a new erryvist@AY lFdd@IPAY lFdd@4ne hne de rtres 34AY lFdd@IPFPHfAY lFdd@9d9AY for@int i a HY i ` lFsize@AY iCCA { ystemFoutFprintln@4donne l9indie 4 C i C 4 a 4 C lFget@iAAY }

Si vous excutez ce code, vous obtiendrez la gure 17.3.

Figure

17.3  Parcours d'un ArrayList

Je pense que vous voyez dj les avantages des ArrayList. Sachez aussi qu'il existe tout un panel de mthodes fournies avec cet objet : 207

CHAPITRE 17. LES COLLECTIONS D'OBJETS      


add() permet d'ajouter un lment ; get(int index) retourne l'lment l'indice demand ; remove(int index) eace l'entre l'indice demand ; isEmpty() renvoie  vrai  si l'objet est vide ; removeAll() eace tout le contenu de l'objet ; contains(Object element) retourne  vrai  si l'lment pass en paramtre est dans l'ArrayList.

Contrairement aux LinkedList, les ArrayList sont rapides en lecture, mme avec un gros volume d'objets. Elles sont cependant plus lentes si vous devez ajouter ou supprimer des donnes en milieu de liste. Pour rsumer l'extrme, si vous eectuez beaucoup de lectures sans vous soucier de l'ordre des lments, optez pour une ArrayList ; en revanche, si vous insrez beaucoup de donnes au milieu de la liste, optez pour une Linkedlist.

Les objets Map


Une collection de type Map est une collection qui fonctionne avec un couple cl - valeur. On y trouve les objets Hashtable, HashMap, TreeMap, WeakHashMap. . . La cl, qui sert identier une entre dans notre collection, est unique. La valeur, au contraire, peut tre associe plusieurs cls. Ces objets ont comme point faible majeur leur rapport conictuel avec la taille des donnes stocker. En eet, plus vous aurez de valeurs mettre dans un objet Map, plus celles-ci seront lentes et lourdes : logique, puisque par rapport aux autres collections, il stocke une donne supplmentaire par enregistrement. Une donne c'est de la mmoire en plus et, mme si les ordinateurs actuels en ont normment, gardez en tte que  la mmoire, c'est sacr  2 .

L'objet Hashtable
Vous pouvez galement dire table de hachage, si vous traduisez mot mot. . . On parcourt cet objet grce aux cls qu'il contient en recourant la classe Enumeration. L'objet Enumeration contient notre Hashtable et permet de le parcourir trs simplement. Regardez, le code suivant insre les quatre saisons avec des cls qui ne se suivent pas, et notre numration rcupre seulement les valeurs :
import jvFutilFinumertionY import jvFutilFrshtleY puli lss est { puli stti void min@tring rgsA { rshtle ht a new rshtle@AY

2. Je vous rappelle que les applications Java ne sont pas forcment destines aux appareils bnciant de beaucoup de mmoire.

208

LES OBJETS SET


htFput@ID 4printemps4AY htFput@IHD 4t4AY htFput@IPD 4utomne4AY htFput@RSD 4hiver4AY inumertion e a htFelements@AY while@eFhsworeilements@AA ystemFoutFprintln@eFnextilement@AAY } }

Cet objet nous ore lui aussi tout un panel de mthodes utiles :  isEmpty() retourne  vrai  si l'objet est vide ;  contains(Object value) retourne  vrai  si la valeur est prsente. Identique containsValue(Object value) ;  containsKey(Object key) retourne  vrai  si la cl passe en paramtre est prsente dans la Hashtable ;  put(Object key, Object value) ajoute le couple key - value dans l'objet ;  elements() retourne une numration des lments de l'objet ;  keys() retourne la liste des cls sous forme d'numration. De plus, il faut savoir qu'un objet Hashtable n'accepte pas la valeur null et qu'il est Thread Safe, c'est--dire qu'il est utilisable dans plusieurs threads 3 simultanment sans qu'il y ait un risque de conit de donnes.

L'objet HashMap
Cet objet ne dire que trs peu de la Hashtable :  il accepte la valeur null ;  il n'est pas Thread Safe. En fait, les deux objets de type Map sont, peu de choses prs, quivalents.

Les objets Set


Un Set est une collection qui n'accepte pas les doublons. Par exemple, elle n'accepte qu'une seule fois null, car deux valeurs null sont considres comme un doublon. On trouve parmi les Set les objets HashSet, TreeSet, LinkedHashSet. . . Certains Set sont plus restrictifs que d'autres : il en existe qui n'acceptent pas null, certains types d'objets, etc.
3. Cela signie que plusieurs lments de votre programme peuvent l'utiliser simultanment. Nous y reviendrons.

209

CHAPITRE 17. LES COLLECTIONS D'OBJETS Les Set sont particulirement adapts pour manipuler une grande quantit de donnes. Cependant, les performances de ceux-ci peuvent tre amoindries en insertion. Gnralement, on opte pour un HashSet, car il est plus performant en temps d'accs, mais si vous avez besoin que votre collection soit constamment trie, optez pour un TreeSet.

L'objet HashSet
C'est sans nul doute la plus utilise des implmentations de l'interface Set. On peut parcourir ce type de collection avec un objet Iterator ou extraire de cet objet un tableau d'Object :
import jvFutilFrshetY import jvFutilFstertorY puli lss est { puli stti void min@tring rgsA { rshet hs a new rshet@AY hsFdd@4toto4AY hsFdd@IPAY hsFdd@9d9AY stertor it a hsFitertor@AY while@itFhsxext@AA ystemFoutFprintln@itFnext@AAY ystemFoutFprintln@4nrours ve un tleu d9ojet4AY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY yjet oj a hsFtoerry@AY for@yjet o X ojA ystemFoutFprintln@oAY

Voici une liste des mthodes que l'on trouve dans cet objet :  add() ajoute un lment ;  contains(Object value) retourne  vrai  si l'objet contient value ;  isEmpty() retourne  vrai  si l'objet est vide ;  iterator() renvoie un objet de type Iterator ;  remove(Object o) retire l'objet o de la collection ;  toArray() retourne un tableau d'Object. Voil ! Nous avons vu quelque chose d'assez intressant que nous pourrons utiliser dans peu de temps, mais avant, nous avons encore du pain sur la planche. Dans le chapitre suivant nous verrons d'autres aspects de nos collections. 210

LES OBJETS SET

En rsum
      Une collection permet de stocker un nombre variable d'objets. Il y a principalement trois types de collection : les List, les Set et les Map. Chaque type a ses avantages et ses inconvnients. Les Collection stockent des objets alors que les Map stockent un couple cl - valeur. Si vous insrez frquemment des donnes en milieu de liste, utilisez une LinkedList. Si vous voulez rechercher ou accder une valeur via une cl de recherche, optez pour une collection de type Map.  Si vous avez une grande quantit de donnes traiter, tournez-vous vers une liste de type Set.

211

CHAPITRE 17. LES COLLECTIONS D'OBJETS

212

Chapitre

18
Dicult :

La gnricit en Java

our assimiler ce concept, ajout au JDK depuis la version 1.5, nous allons essentiellement travailler avec des exemples tout au long de ce chapitre. Le principe de la gnricit est de faire des classes qui n'acceptent qu'un certain type d'objets ou de donnes de faon dynamique ! Avec ce que nous avons appris au chapitre prcdent, vous avez srement pouss un soupir de soulagement lorsque vous avez vu que ces objets acceptent tous les types de donnes. Par contre, un problme de taille se pose : lorsque vous voudrez travailler avec ces donnes, vous allez devoir faire un cast ! Et peut-tre mme un cast de cast, voire un cast de cast de cast. . . C'est l que se situe le problme. . . Mais comme je vous le disais, depuis la version 1.5 du JDK, la gnricit est l pour vous aider !

213

CHAPITRE 18. LA GNRICIT EN JAVA

Principe de base
Bon, pour vous montrer la puissance de la gnricit, nous allons tout de suite voir un cas de classe qui ne l'utilise pas. Il existe un exemple trs simple que vous pourrez retrouver aisment sur Internet, car il s'agit d'un des cas les plus faciles permettant d'illustrer les bases de la gnricit. Nous allons coder une classe Solo. Celle-ci va travailler avec des rfrences de type String. Voici le diagramme de classe de cette dernire en gure 18.1.

Figure

18.1  Classe Solo

Vous pouvez voir que le code de cette classe est trs rudimentaire. On aecte une valeur, on peut la mettre jour et la rcuprer. . . Maintenant, si je vous demande de me faire une classe qui permet de travailler avec n'importe quel type de donnes, j'ai une vague ide de ce que vous allez faire. . . Ne serait-ce pas quelque chose s'approchant de la gure 18.2 ?

Figure

18.2  Classe Solo travaillant avec des Object

J'en tais sr. . . Crez la classe Solo, ainsi qu'une classe avec une mthode main. Si vous voulez utiliser les donnes de l'objet Solo, vous allez devoir faire un cast. Testez ce code dans votre main :
puli lss est { puli stti void min@tring rgsA { olo vl a new olo@IPAY int nre a vlFgetleur@AY } }

214

PRINCIPE DE BASE Vous constatez que vous essayez vainement de mettre un objet de type Object dans un objet de type Integer : c'est interdit ! La classe Object est plus globale que la classe Integer, vous ne pouvez donc pas eectuer cette opration, sauf si vous castez votre objet en Integer comme ceci :
olo vl a new olo@IPAY int nre a @sntegerAvlFgetleur@AY

Pour le moment, on peut dire que votre classe peut travailler avec tous les types de donnes, mais les choses se corsent un peu l'utilisation. . . Vous serez donc sans doute tents d'crire une classe par type de donne ( SoloInt, SoloString, etc.). Et c'est l que la gnricit s'avre utile, car avec cette dernire, vous pourrez savoir ce que contient votre objet Solo et n'aurez qu'une seule classe dvelopper ! Voil le diagramme de classe de cet objet en gure 18.3.

Figure

18.3  Objet gnrique

Et voici son code :


puli lss olo`b { GGrile d9instne privte vleurY GGgonstruteur pr dfut puli olo@A{ thisFvleur a nullY } GGgonstruteur ve prmtre inonnu pour l9instnt puli olo@ vlA{ thisFvleur a vlY } GGhfinit l vleur ve le prmtre puli void setleur@ vlA{ thisFvleur a vlY }

215

CHAPITRE 18. LA GNRICIT EN JAVA


GGetourne l vleur dj  ste puli getleur@A{ return thisFvleurY } pr l signture de l mthode 3

Impressionnant, n'est-ce pas ? Dans cette classe, le T n'est pas encore dni. Vous vous en occuperez l'instanciation de la classe. Par contre, une fois instanci avec un type, l'objet ne pourra travailler qu'avec le type de donnes que vous lui avez spci ! Exemple de code :
puli stti void min@tring rgsA { olo`sntegerb vl a new olo`sntegerb@IPAY int nre a vlFgetleur@AY }

Ce code fonctionne trs bien, mais si vous essayez de faire ceci :


puli stti void min@tring rgsA { olo`sntegerb vl a new olo`sntegerb@4toto4AY GGsiD on essie de mettre une hne de rtres l ple d9un entier int nre a vlFgetleur@AY }

. . . ou encore ceci :
puli stti void min@tring rgsA { olo`sntegerb vl a new olo`sntegerb@IPAY vlFsetleur@IPFPfAY GGsiD on essie de mettre un nomre virgule flottnte GG l ple d9un entier }

. . . vous obtiendrez une erreur dans la zone de saisie. Ceci vous indique que votre objet ne reoit pas le bon type d'argument, il y a donc un conit entre le type de donnes que vous avez pass votre instance lors de sa cration et le type de donnes que vous essayez d'utiliser dans celle-ci ! Par contre, vous devez savoir que cette classe ne fonctionne pas seulement avec des Integer. Vous pouvez utiliser tous les types que vous souhaitez ! Voici une dmonstration de ce que j'avance :
puli stti void min@tring rgsA { olo`sntegerb vl a new olo`sntegerb@AY olo`tringb vl a new olo`tringb@4yyyy4AY olo`plotb vlp a new olo`plotb@IPFPfAY olo`houleb vlh a new olo`houleb@IPFPHPSTVAY }

216

PRINCIPE DE BASE Vous avez certainement remarqu que je n'ai pas utilis ici les types de donnes que vous employez pour dclarer des variables de type primitif ! Ce sont les classes de ces types primitifs. En eet, lorsque vous dclarez une variable de type primitif, vous pouvez utiliser ses classes enveloppes (on parle aussi de classe wrapper) ; elles ajoutent les mthodes de la classe Object vos types primitifs ainsi que des mthodes permettant de caster leurs valeurs, etc. ceci, je dois ajouter que depuis Java 5, est gr ce qu'on appelle l'autoboxing, une fonctionnalit du langage permettant de transformer automatiquement un type primitif en classe wrapper 1 et inversement, c'est--dire une classe wrapper en type primitif 2 . Ces deux fonctionnalits forment l' autoboxing. Par exemple :
puli stti void min@tring rgsA{ int i a new snteger@IPAY GGist quivlent int i a IP doule d a new houle@IPFPSVTAY GGist quivlent doule d a IPFPSVT houle d a IPFHY ghrter a 9g9Y l a new erryvist@AY GGevnt tv S il fllit fire lFdd@new snteger@IPAA GGhepuis tv S il suffit de fire lFdd@IPAY GGFFF }

Plus loin dans la gnricit !


Vous devez savoir que la gnricit peut tre multiple ! Nous avons cr une classe Solo, mais rien ne vous empche de crer une classe Duo, qui elle prend deux paramtres gnriques ! Voil le code source de cette classe :
puli lss huo`D b { GGrile d9instne de type privte vleurIY GGrile d9instne de type privte vleurPY GGgonstruteur pr dfut puli huo@A{ thisFvleurI a nullY thisFvleurP a nullY } GGgonstruteur ve prmtres puli huo@ vlID vlPA{ thisFvleurI a vlIY thisFvleurP a vlPY

1. On appelle a le boxing. 2. Ceci s'appelle l'unboxing.

217

CHAPITRE 18. LA GNRICIT EN JAVA


} GGwthodes d9initilistion des deux vleurs puli void setleur@ vlID vlPA{ thisFvleurI a vlIY thisFvleurP a vlPY } GGetourne l vleur puli getleurI@A { return vleurIY } GGhfinit l vleur puli void setleurI@ vleurIA { thisFvleurI a vleurIY } GGetourne l vleur puli getleurP@A { return vleurPY } GGhfinit l vleur puli void setleurP@ vleurPA { thisFvleurP a vleurPY }

Voyez que cette classe prend deux types de rfrences qui ne sont pas encore dnis. An de mieux comprendre son fonctionnement, voici un code que vous pouvez tester :
puli stti void min@tring rgsA { huo`tringD foolenb dul a new huo`tringD foolenb@4toto4D trueAY ystemFoutFprintln@4leur de l9ojet dul X vlI a 4 C dulFgetleurI@A C 4D vlP a 4 C dulFgetleurP@AAY huo`houleD ghrterb dulP a new huo`houleD ghrterb@IPFPSVSD 9g9AY ystemFoutFprintln@4leur de l9ojet dulP X vlI a 4 C dulPFgetleurI@A C 4D vlP a 4 C dulPFgetleurP@AAY

Le rsultat est visible sur la gure 18.4. Vous voyez qu'il n'y a rien de bien mchant ici. Ce principe fonctionne exactement comme dans l'exemple prcdent. La seule dirence rside dans le fait qu'il n'y a pas un, mais deux paramtres gnriques ! 218

GNRICIT ET COLLECTIONS

Figure

18.4  Test de la classe Duo

Attends une minute. . . Lorsque je dclare une rfrence de type Duo<String, Boolean>, je ne peux plus la changer en un autre type !
En fait, non. Si vous faites :
puli stti void min@tring rgsA { huo`tringD foolenb dul a new huo`tringD foolenb@4toto4D trueAY ystemFoutFprintln@4leur de l9ojet dulX vlI a 4 C dulFgetleurI@A C 4D vlP a 4 C dulFgetleurP@AAY dul a new huo`houleD ghrterb@AY }

. . . vous violez la contrainte que vous avez mise lors de la dclaration du type de rfrence ! Vous ne pourrez donc pas modier la dclaration gnrique d'un objet. . . Donc si vous suivez bien, on va pouvoir encore corser la chose !

Gnricit et collections
Vous pouvez aussi utiliser la gnricit sur les objets servant grer des collections. C'est mme l'un des points les plus utiles de la gnricit ! En eet, lorsque vous listiez le contenu d'un ArrayList par exemple, vous n'tiez jamais srs 100 % du type de rfrence sur lequel vous alliez tomber 3 . . . Eh bien ce calvaire est termin et le polymorphisme va pouvoir rapparatre, plus puissant que jamais ! Voyez comment utiliser la gnricit avec les collections :
puli stti void min@tring rgsA { ystemFoutFprintln@4viste de tring4AY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY vist`tringb listetringa new erryvist`tringb@AY listetringFdd@4ne hne4AY listetringFdd@4ne utre4AY listetringFdd@4inore une utre4AY

3. Normal, puisqu'un ArrayList accepte tous les types d'objets.

219

CHAPITRE 18. LA GNRICIT EN JAVA


listetringFdd@4ellezD une dernire4AY for@tring str X listetringA ystemFoutFprintln@strAY ystemFoutFprintln@4nviste de flot4AY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY vist`plotb listeplot a new erryvist`plotb@AY listeplotFdd@IPFPSfAY listeplotFdd@ISFPSfAY listeplotFdd@PFPSfAY listeplotFdd@IPVUTRFPSfAY for@flot f X listeplotA ystemFoutFprintln@fAY }

Voyez le rsultat de ce code sur la gure 18.5.

Figure

18.5  ArrayList et gnricit

La gnricit sur les listes est rgie par les lois vues prcdemment : pas de type float dans un ArrayList<String>.
Vu qu'on y va crescendo, on pimente nouveau le tout !

Hritage et gnricit
L o les choses sont pernicieuses, c'est quand vous employez des classes usant de la gnricit avec des objets comprenant la notion d'hritage ! L'hritage dans la gnricit 220

GNRICIT ET COLLECTIONS est l'un des concepts les plus complexes en Java. Pourquoi ? Tout simplement parce qu'il va l'encontre de ce que vous avez appris jusqu' prsent. . .

Acceptons le postulat suivant. . .


Nous avons une classe Voiture dont hrite une autre classe VoitureSansPermis, ce qui nous donnerait le diagramme reprsent la gure 18.6.

Figure

18.6  Hirarchie de classes

Jusque-l, c'est simplissime. Maintenant, a se complique :


puli stti void min@tring rgsA { vist`oitureb listoiture a new erryvist`oitureb@AY vist`oiturensermisb listoiture a new erryvist`oiturensermisb@AY } listoiture a listoitureY GGsnterdit 3

Si vous avez l'habitude de la covariance des variables, sachez que cela n'existe pas avec la gnricit ! En tout cas, pas sous la mme forme. Imaginez deux secondes que l'instruction interdite soit permise ! Dans listVoiture, vous avez le contenu de la liste des voitures sans permis, et rien ne vous empche d'y ajouter une voiture. L o le problme prend toute son envergure, c'est lorsque vous voudrez sortir toutes les voitures sans permis de votre variable listVoiture. Eh oui ! Vous y avez ajout une voiture ! Lors du balayage de la liste, vous aurez, un moment, une rfrence de type VoitureSansPermis laquelle vous tentez d'aecter une rfrence de type Voiture. Voil pourquoi ceci est interdit. Une des solutions consiste utiliser le wildcard : ?. Le fait de dclarer une collection avec le wildcard, comme ceci :
ArrayList<?> list;

revient indiquer que notre collection accepte n'importe quel type d'objet. Cependant, nous allons voir un peu plus loin qu'il y a une restriction. Je vais maintenant vous indiquer quelque chose d'important. Avec la gnricit, vous pouvez aller encore plus loin. . . Nous avons vu comment restreindre le contenu d'une de nos listes, mais nous pouvons aussi l'largir ! Si je veux par exemple qu'un ArrayList puisse avoir toutes les instances de Voiture et de ses classes lles. . . comment faire ?

Ce qui suit s'applique aussi aux interfaces susceptibles d'tre implmentes par une classe !
221

CHAPITRE 18. LA GNRICIT EN JAVA Attention les yeux, a pique :


puli stti void min@tring rgsA { GGvist n9eptnt que des instnes de oiture GGou de ses sousElsses vist`c extends oitureb listoiture a new erryvist`oiturensermisb@AY }

Une application de ceci consiste crire des mthodes gnriques, par exemple une mthode qui permet de lister toutes les valeurs de notre ArrayList cit prcdemment :
puli stti void min@tring rgsA { vist`c extends oitureb listoiture a new erryvist`oiturensermisb@AY ffiher@listoitureAY

GGwthode gnrique 3 stti void ffiher@erryvist`c extends oitureb listA{ for@oiture v X listA ystemFoutFprintln@vFtotring@AAY }

Eh, attends ! On a voulu ajouter des objets dans notre collection et le programme ne compile plus !
Oui. . . Ce que je ne vous avais pas dit, c'est que ds que vous utilisez le wildcard, vos listes sont verrouilles en insertion : elles se transforment en collections en

lecture seule. . .

En fait, il faut savoir que c'est la compilation du programme que Java ne vous laisse pas faire : le wildcard signie  tout objet , et ds l'utilisation de celui-ci, la JVM verrouillera la compilation du programme an de prvenir les risques d'erreurs. Dans notre exemple, il est combin avec extends (signiant hritant), mais cela n'a pas d'incidence directe : c'est le wildcard la cause du verrou 4 . Par contre, ce type d'utilisation fonctionne merveille pour la lecture :
puli stti void min@tring rgsA{ GGviste de voiture vist`oitureb listoiture a new erryvist`oitureb@AY listoitureFdd@new oiture@AAY listoitureFdd@new oiture@AAY

4. Un objet gnrique comme notre objet Solo dclar Solo<?> solo; sera galement bloqu en criture.

222

GNRICIT ET COLLECTIONS
vist`oiturensermisb listoiture a new erryvist`oiturensermisb@AY listoitureFdd@new oiturensermis@AAY listoitureFdd@new oiturensermis@AAY ffihe@listoitureAY ffihe@listoitureAY

GGeve ette mthodeD on epte ussi ien les olletions de oiture GGque les olletion de oiturensermis stti void ffihe@vist`c extends oitureb listA{ for@oiture v X listA ystemFoutFprint@vFtotring@AAY

Avant que vous ne posiez la question, non, dclarer la mthode affiche(List<Voiture> list) {...} ne vous permet pas de parcourir des listes de VoitureSansPermis, mme si celle-ci hrite de la classe Voiture.

Les mthodes dclares avec un type gnrique sont verrouilles an de n'tre utilises qu'avec ce type bien prcis, toujours pour les mmes raisons !
Attendez : ce n'est pas encore tout. Nous avons vu comment largir le contenu de nos collections (pour la lecture), nous allons voir comment restreindre les collections acceptes par nos mthodes. La mthode :
stti void ffihe@vist`c extends oitureb listA{ for@oiture v X listA ystemFoutFprint@vFtotring@AAY }

. . . autorise n'importe quel objet de type List dont Voiture est la superclasse. La signication de l'instruction suivante est donc que la mthode autorise un objet de type List de n'importe quelle superclasse de la classe Voiture (y compris Voiture elle-mme).
stti void ffihe@vist`c super oitureb listA{ for@yjet v X listA ystemFoutFprint@vFtotring@AAY }

Ce code fonctionne donc parfaitement :


puli stti void min@tring rgsA{ GGviste de voiture vist`oitureb listoiture a new erryvist`oitureb@AY listoitureFdd@new oiture@AAY listoitureFdd@new oiture@AAY

223

CHAPITRE 18. LA GNRICIT EN JAVA

vist`yjetb listoiture a new erryvist`yjetb@AY listoitureFdd@new yjet@AAY listoitureFdd@new yjet@AAY ffihe@listoitureAY } GGeve ette mthodeD on epte ussi ien les olletions de oiture GGque les olletions d9yjet X superlsse de toutes les lsses stti void ffihe@vist`c super oitureb listA{ for@yjet v X listA ystemFoutFprint@vFtotring@AAY }

L'utilit du wildcard est surtout de permettre de retrouver le polymorphisme avec les collections. An de mieux cerner l'intrt de tout cela, voici un petit exemple de code :
import jvFutilFerryvistY import jvFutilFvistY puli lss qrge { vist`oitureb list a new erryvist`oitureb@AY puli void dd@vist`c extends oitureb listoitureA{ for@oiture v X listoitureA listFdd@vAY ystemFoutFprintln@4gontenu de notre grge X4AY for@oiture v X listA ystemFoutFprint@vFtotring@AAY

Un petit test rapide :


puli stti void min@tring rgsA{ vist`oitureb listoiture a new erryvist`oitureb@AY listoitureFdd@new oiture@AAY vist`oiturensermisb listoiture a new erryvist`oiturensermisb@AY listoitureFdd@new oiturensermis@AAY qrge grge a new qrge@AY grgeFdd@listoitureAY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEE4AY grgeFdd@listoitureAY

Essayez donc : ce code fonctionne parfaitement et vous permettra de constater que le polymorphisme est possible avec les collections. Je conois bien que ceci est un peu 224

GNRICIT ET COLLECTIONS dicile comprendre, mais vous en aurez srement besoin dans une de vos prochaines applications !

En rsum
 La gnricit est un concept trs utile pour dvelopper des objets travaillant avec plusieurs types de donnes.  Vous passerez donc moins de temps dvelopper des classes traitant de faon identique des donnes direntes.  La gnricit permet de rutiliser sans risque le polymorphisme avec les collections.  Cela confre plus de robustesse votre code.  Vous pouvez coupler les collections avec la gnricit !  Le wildcard (?) permet d'indiquer que n'importe quel type peut tre trait et donc accept !  Ds que le wildcard (?) est utilis, cela revient rendre ladite collection en lecture seule !  Vous pouvez largir le champ d'acceptation d'une collection gnrique grce au motcl extends.  L'instruction ? extends MaClasse autorise toutes les collections de classes ayant pour supertype MaClasse.  L'instruction ? super MaClasse autorise toutes les collections de classes ayant pour type MaClasse et tous ses supertypes !  Pour ce genre de cas, les mthodes gnriques sont particulirement adaptes et permettent d'utiliser le polymorphisme dans toute sa splendeur !

225

CHAPITRE 18. LA GNRICIT EN JAVA

226

Chapitre

19
Dicult :

Java et la rexivit

a rexivit, aussi appele introspection, consiste dcouvrir de faon dynamique des informations relatives une classe ou un objet. C'est notamment utilis au niveau de la machine virtuelle Java lors de l'excution du programme. En gros, la machine virtuelle stocke les informations relatives une classe dans un objet. La rexivit n'est que le moyen de connatre toutes les informations concernant une classe donne. Vous pourrez mme crer des instances de classe de faon dynamique grce cette notion. Ce chapitre va srement vous intresser ! Alors, allons-y. . .

227

CHAPITRE 19. JAVA ET LA RFLEXIVIT

L'objet Class
Concrtement, que se passe-t-il ? Au chargement d'une classe Java, votre JVM cre automatiquement un objet. Celui-ci rcupre toutes les caractristiques de votre classe ! Il s'agit d'un objet Class. Exemple : vous avez cr trois nouvelles classes Java. l'excution de votre programme, la JVM va crer un objet Class pour chacune d'elles. Comme vous devez vous en douter, cet objet possde une multitude de mthodes permettant d'obtenir tous les renseignements possibles et imaginables sur une classe. Dans ce chapitre, nous allons visiter la classe String. Crez un nouveau projet ainsi qu'une classe contenant la mthode main. Voici deux faons de rcuprer un objet Class :
puli stti void min@tring rgsA { glss a tringFlssY glss P a new tring@AFgetglss@AY GBv fmeuse mthode finle dont je vous prlis dns le hpitre sur l9hritgeF gette mthode vient de l lsse yjetF BG }

Maintenant que vous savez rcuprer un objet Class, nous allons voir ce dont il est capable. Nous n'allons examiner qu'une partie des fonctionnalits de l'objet Class : je ne vais pas tout vous montrer, je pense que vous tes dornavant mme de chercher et de trouver tout seuls. Vous avez l'habitude de manipuler des objets, prsent. . .

Connatre la superclasse d'une classe


Voici un petit code qui va rpondre la question de la superclasse :
ystemFoutFprintln@4v superlsse de l lsse 4 C tringFlssFgetxme@A C 4 est X 4 C tringFlssFgetuperlss@AAY

Ce qui nous donne :


La superclasse de la classe java.lang.String est : class java.lang.Object

Notez que la classe Object n'a pas de superclasse. . . Normal, puisqu'elle se trouve au sommet de la hirarchie. Donc si vous remplacez la classe String de l'exemple ci-dessus par la classe Object, vous devriez obtenir :
La superclasse de la classe java.lang.Object est : null

En plus de a, l'objet Class permet de connatre la faon dont votre objet est constitu : interfaces, classe mre, variables. . . 228

L'OBJET CLASS

Connatre la liste des interfaces d'une classe


Vous pouvez tester ce code :
puli stti void min@tring rgsA { GGyn rupre un ojet glss glss a new tring@AFgetglss@AY GGglss a tringFlssY est quivlent GGv mthode getsnterfes retourne un tleu de glss glss fes a Fgetsnterfes@AY GGour voir le nomre d9interfes ystemFoutFprintln@4sl y 4 C fesFlength C 4 interfes implmentes4AY GGyn prourt le tleu d9interfes for@int i a HY i ` fesFlengthY iCCA ystemFoutFprintln@fesiAY

Ce qui nous donne la gure 19.1.

Figure

19.1  Rcupration des interfaces d'une classe

Connatre la liste des mthodes de la classe


La mthode getMethods() de l'objet Class nous retourne un tableau d'objets Method prsents dans le package java.lang.reflect. Vous pouvez soit faire l'import la main, soit dclarer un tableau d'objets Method et utiliser le raccourci Ctrl + Shift + O. Voici un code qui retourne la liste des mthodes de la classe String :
puli stti void min@tring rgsA { glss a new tring@AFgetglss@AY wethod m a Fgetwethods@AY ystemFoutFprintln@4sl y 4 C mFlength C 4 mthodes dns ette lsse4AY GGyn prourt le tleu de mthodes for@int i a HY i ` mFlengthY iCCA ystemFoutFprintln@miAY

229

CHAPITRE 19. JAVA ET LA RFLEXIVIT Et voici un morceau du rsultat (gure 19.2). Comme vous pouvez le constater, il y a beaucoup de mthodes dans la classe String.

Figure

19.2  Mthodes de la classe String

Vous pouvez constater que l'objet Method regorge lui aussi de mthodes intressantes. Voici un code qui ache la liste des mthodes, ainsi que celle de leurs arguments respectifs :
puli stti void min@tring rgsA { glss a new tring@AFgetglss@AY wethod m a Fgetwethods@AY ystemFoutFprintln@4sl y 4 C mFlength C 4 mthodes dns ette lsse4AY GGyn prourt le tleu de mthodes for@int i a HY i ` mFlengthY iCCA { ystemFoutFprintln@miAY glss p a miFgetrmeterypes@AY for@int j a HY j ` pFlengthY jCCA ystemFoutFprintln@pjFgetxme@AAY } ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEn4AY

Le rsultat est visible sur la gure 19.3. Il est intressant de voir que vous obtenez toutes sortes d'informations sur les mthodes, leurs paramtres, les exceptions leves, leur type de retour, etc. 230

L'OBJET CLASS

Figure

19.3  Utilisation de l'objet Method

Connatre la liste des champs (variable de classe ou d'instance)


Ici, nous allons procder de la mme faon qu'avec la liste des mthodes sauf que cette fois, la mthode invoque retournera un tableau d'objets Field. Voici un code qui ache la liste des champs de la classe String.

puli stti void min@tring rgsA { glss a new tring@AFgetglss@AY pield m a Fgethelredpields@AY ystemFoutFprintln@4sl y 4 C mFlength C 4 hmps dns ette lsse4AY GGyn prourt le tleu de mthodes for@int i a HY i ` mFlengthY iCCA ystemFoutFprintln@miFgetxme@AAY

Ce qui nous donne : 231

CHAPITRE 19. JAVA ET LA RFLEXIVIT


Il y a 7 champs dans cette classe value offset count hash serialVersionUID serialPersistentFields CASE_INSENSITIVE_ORDER

Connatre la liste des constructeurs de la classe


Ici, nous utiliserons un objet Constructor pour lister les constructeurs de la classe :
puli stti void min@tring rgsA { glss a new tring@AFgetglss@AY gonstrutor onstru a Fgetgonstrutors@AY ystemFoutFprintln@4sl y 4 C onstruFlength C 4 onstruteurs dns ette lsse4AY GGyn prourt le tleu des onstruteurs for@int i a HY i ` onstruFlengthY iCCA{ ystemFoutFprintln@onstruiFgetxme@AAY glss prm a onstruiFgetrmeterypes@AY for@int j a HY j ` prmFlengthY jCCA ystemFoutFprintln@prmjAY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEn4AY }

Vous constatez que l'objet Class regorge de mthodes en tout genre ! Et si nous essayions d'exploiter un peu plus celles-ci ?

Instanciation dynamique
Nous allons voir une petite partie de la puissance de cette classe (pour l'instant). Dans un premier temps, crez un nouveau projet avec une mthode main ainsi qu'une classe correspondant au diagramme en gure 19.4. Voici son code Java :
puli lss ire { privte tring vleurID vleurPY puli ire@A{ thisFvleurI a nullY

232

INSTANCIATION DYNAMIQUE

Figure

19.4  Classe Paire

thisFvleurP a nullY ystemFoutFprintln@4snstnition 34AY

puli ire@tring vlID tring vlPA{ thisFvleurI a vlIY thisFvleurP a vlPY ystemFoutFprintln@4snstnition ve des prmtres 34AY } puli tring totring@A{ return 4te suis un ojet qui pour vleur X 4 C thisFvleurI C 4 E 4 C thisFvleurPY } puli tring getleurI@A { return vleurIY } puli void setleurI@tring vleurIA { thisFvleurI a vleurIY } puli tring getleurP@A { return vleurPY } puli void setleurP@tring vleurPA { thisFvleurP a vleurPY }

Le but du jeu consiste crer un objet Paire sans utiliser l'oprateur new. Pour instancier un nouvel objet Paire, commenons par rcuprer ses constructeurs. Ensuite, nous prparons un tableau contenant les donnes insrer, puis invoquons la mthode toString(). Regardez comment procder ; attention, il y a moult exceptions : 233

CHAPITRE 19. JAVA ET LA RFLEXIVIT


puli stti void min@tring rgsA { tring nom a ireFlssFgetxme@AY try { GGyn re un ojet glss glss l a glssFforxme@nomAY GGxouvelle instne de l lsse ire yjet o a lFnewsnstne@AY GGyn re les prmtres du onstruteur glss types a new glss{tringFlssD tringFlss}Y GGyn rupre le onstruteur ve les deux prmtres gonstrutor t a lFgetgonstrutor@typesAY GGyn instnie l9ojet ve le onstruteur surhrg 3 yjet oP a tFnewsnstne@new tring{4vleur I 4D 4vleur P4} AY } th @eurityixeption eA { eFprinttkre@AY } th @slleglergumentixeption eA { eFprinttkre@AY } th @glssxotpoundixeption eA { eFprinttkre@AY } th @snstntitionixeption eA { eFprinttkre@AY } th @sllegleessixeption eA { eFprinttkre@AY } th @xouhwethodixeption eA { eFprinttkre@AY } th @snvotionrgetixeption eA { eFprinttkre@AY }

Et le rsultat donne la gure 19.5.

Figure

19.5  Instanciation dynamique

Nous pouvons maintenant appeler la mthode toString() du deuxime objet. . . Oh et puis soyons fous, appelons-la sur les deux :
puli stti void min@tring rgsA { tring nom a ireFlssFgetxme@AY try {

234

INSTANCIATION DYNAMIQUE
GGyn re un ojet glss glss l a glssFforxme@nomAY GGxouvelle instne de l lsse ire yjet o a lFnewsnstne@AY GGyn re les prmtres du onstruteur glss types a new glss{tringFlssD tringFlss}Y GGyn rupre le onstruteur ve les deux prmtres gonstrutor t a lFgetgonstrutor@typesAY GGyn instnie l9ojet ve le onstruteur surhrg 3 yjet oP a tFnewsnstne@new tring{4vleur I 4D 4vleur P4} AY GGyn v herher l mthode totringD elle n9 uun prmtre wethod m a lFgetwethod@4totring4D nullAY GGv mthode invoke exute l mthode sur l9ojet pss en prmtreD GG ps de prmtreD don null en deuxime prmtre de l mthode invoke 3 ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY ystemFoutFprintln@4wthode 4 C mFgetxme@A C 4 sur oPX 4 CmFinvoke@oPD nullAAY ystemFoutFprintln@4wthode 4 C mFgetxme@A C 4 sur oX 4 CmFinvoke@oD null AAY } th @eurityixeption eA { eFprinttkre@AY } th @slleglergumentixeption eA { eFprinttkre@AY } th @glssxotpoundixeption eA { eFprinttkre@AY } th @snstntitionixeption eA { eFprinttkre@AY } th @sllegleessixeption eA { eFprinttkre@AY } th @xouhwethodixeption eA { eFprinttkre@AY } th @snvotionrgetixeption eA { eFprinttkre@AY }

Et le rsultat en gure 19.6. Voil : nous venons de crer deux instances d'une classe sans passer par l'oprateur new. Mieux encore, nous avons pu appeler une mthode de nos instances ! Je ne vais pas m'attarder sur ce sujet, mais gardez en tte que cette faon de faire, quoique trs lourde, pourrait vous tre utile. Sachez que certains frameworks 1 utilisent la rexivit an d'instancier leurs objets 2 .
1. Ensemble d'objets orant des fonctionnalits pour dvelopper 2. Je pense notamment des frameworks bass sur des chiers de conguration XML tels que

235

CHAPITRE 19. JAVA ET LA RFLEXIVIT

Figure

19.6  Invocation dynamique de mthodes

L'utilit de ceci vous semble-t-elle vidente ? Mme si vous ne savez pas les utiliser, peut-tre avez-vous dj entendu parler de ces frameworks Java. Maintenant, vous n'allez pas utiliser ce genre de technique tous les jours. Cependant, il est possible que vous ayez besoin, pour une raison quelconque, de stocker le nom d'une classe Java dans une base de donnes an, justement, de pouvoir l'utiliser plus tard. Dans ce cas, lorsque votre base de donnes vous fournira le nom de la classe en question, vous pourrez la manipuler dynamiquement.

En rsum
 Lorsque votre JVM interprte votre programme, elle cre automatiquement un objet Class pour chaque classe charge.  Avec un tel objet, vous pouvez connatre absolument tout sur votre classe.  L'objet Class utilise des sous-objets tels que Method, Field et Constructor qui permettent de travailler avec vos dirents objets ainsi qu'avec ceux prsents dans Java.  Grce cet objet, vous pouvez crer des instances de vos classes Java sans utiliser new.

Hibernate, Struts, Spring. . .

236

Troisime partie
Les interfaces graphiques

237

Chapitre

20
Dicult :

Notre premire fentre

ans cette partie, nous aborderons les interfaces graphiques (on parle aussi d' IHM pour Interfaces Homme Machine ou de GUI pour Graphical User Interfaces) et, par extension, la programmation vnementielle. Par l, vous devez comprendre que votre programme ne ragira plus des saisies au clavier mais des vnements provenant d'un composant graphique : un bouton, une liste, un menu. . . Le langage Java propose direntes bibliothques pour programmer des IHM, mais dans cet ouvrage, nous utiliserons essentiellement les packages javax.swing et java.awt prsents d'oce dans Java. Ce chapitre vous permettra d'apprendre utiliser l'objet JFrame, prsent dans le package java.swing. Vous serez alors mme de crer une fentre, de dnir sa taille, etc. Le fonctionnement de base des IHM vous sera galement prsent et vous apprendrez qu'en ralit, une fentre n'est qu'une multitude de composants poss les uns sur les autres et que chacun possde un rle qui lui est propre. Mais trve de bavardages inutiles, commenons tout de suite !

239

CHAPITRE 20. NOTRE PREMIRE FENTRE

L'objet JFrame
Nous y voil. . . Avant de nous lancer corps perdu dans cette partie, vous devez savoir de quoi nous allons nous servir. Dans ce livre, nous traiterons de javax.swing et de java.awt. Nous n'utiliserons pas de composants awt, nous travaillerons uniquement avec des composants swing ; en revanche, des objets issus du package awt seront utiliss an d'interagir et de communiquer avec les composants swing. Par exemple, un composant peut tre reprsent par un bouton, une zone de texte, une case cocher. . . An de mieux comprendre comment tout cela fonctionne, vous devez savoir que lorsque le langage Java a vu le jour, dans sa version 1.0, seul awt tait utilisable ; swing n'existait pas, il est apparu dans la version 1.2 de Java 1 . Les composants awt sont considrs comme lourds 2 car ils sont fortement lis au systme d'exploitation, c'est ce dernier qui les gre. Les composants swing, eux, sont comme dessins dans un conteneur, ils sont dit lgers 3 ; ils n'ont pas le mme rendu l'achage, car ce n'est plus le systme d'exploitation qui les gre. Il existe galement d'autres dirences, comme le nombre de composants utilisables, la gestion des bordures. . . Pour toutes ces raisons, il est trs fortement recommand de ne pas mlanger les composants swing et awt dans une mme fentre ; cela pourrait occasionner des conits ! Si vous associez les deux, vous aurez de trs grandes dicults dvelopper une IHM stable et valide. En eet, swing et awt ont les mmes fondements mais dirent dans leur utilisation. Cette parenthse ferme, nous pouvons entrer dans le vif du sujet. Je ne vous demande pas de crer un projet contenant une classe main, celui-ci doit tre prt depuis des lustres ! Pour utiliser une fentre de type JFrame, vous devez l'instancier, comme ceci :
import jvxFswingFtprmeY puli lss est { puli stti void min@tring rgsA{ tprme fenetre a new tprme@AY } }

Lorsque vous excutez ce code, vous n'obtenez rien, car par dfaut, votre JFrame n'est pas visible. Vous devez donc lui dire  sois visible  de cette manire :
import jvxFswingFtprmeY puli lss est { puli stti void min@tring rgsA{ tprme fenetre a new tprme@AY fenetreFsetisile@trueAY

1. Appele aussi Java 2. 2. On dit aussi HeavyWeight. 3. On dit aussi LightWeight.

240

L'OBJET JFRAME
}

Ainsi, lorsque vous excutez ce code, vous obtenez la gure 20.1.

Figure

20.1  Premire fentre

toutes celles et ceux qui se disent  Elle est toute petite, cette fentre ! , je rponds :  Bienvenue dans le monde de la programmation vnementielle !  Il faut que vous vous y fassiez, vos composants ne sont pas intelligents : il va falloir leur dire tout ce qu'ils doivent faire. Pour obtenir une fentre plus consquente, il faudrait donc :  qu'elle soit plus grande ;  qu'elle comporte un titre (ce ne serait pas du luxe !) ;  qu'elle gure au centre de l'cran, ce serait parfait ;  que notre programme s'arrte rellement lorsqu'on clique sur la croix rouge, car, pour ceux qui ne l'auraient pas remarqu, le processus Eclipse tourne encore mme aprs la fermeture de la fentre. Pour chacun des lments que je viens d'numrer, il y a aura une mthode appeler an que notre JFrame sache quoi s'en tenir. Voici un code rpondant toutes nos exigences :
import jvxFswingFtprmeY puli lss est { puli stti void min@tring rgsA{ tprme fenetre a new tprme@AY GGhfinit un titre pour notre fentre fenetreFsetitle@4w premire fentre tv4AY GGhfinit s tille X RHH pixels de lrge et IHH pixels de hut fenetreFsetize@RHHD IHHAY GGxous demndons mintennt notre ojet de se positionner u entre fenetreFsetvotioneltiveo@nullAY GGermine le proessus lorsqu9on lique sur l roix rouge fenetreFsethefultgloseypertion@tprmeFisyxgvyiAY GGit enfinD l rendre visile fenetreFsetisile@trueAY

241

CHAPITRE 20. NOTRE PREMIRE FENTRE

Figure

20.2  Une fentre plus adapte

Voyez le rendu de ce code en gure 20.2. An de ne pas avoir rednir les attributs chaque fois, je pense qu'il serait utile que nous possdions notre propre objet. Comme a, nous aurons notre propre classe ! Pour commencer, eaons tout le code que nous avons crit dans notre mthode main. Crons ensuite une classe que nous allons appeler Fenetre et faisons-la hriter de JFrame. Nous allons maintenant crer notre constructeur, dans lequel nous placerons nos instructions. Cela nous donne :
import jvxFswingFtprmeY puli lss penetre extends tprme { puli penetre@A{ thisFsetitle@4w premire fentre tv4AY thisFsetize@RHHD SHHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetisile@trueAY } }

Ensuite, vous avez le choix : soit vous conservez votre classe contenant la mthode main et vous crez une instance de Fenetre, soit vous eacez cette classe et vous placez votre mthode main dans votre classe Fenetre. Mais dans tous les cas, vous devez crer une instance de votre Fenetre. Personnellement, je prfre placer ma mthode main dans une classe part. . . Mais je ne vous oblige pas faire comme moi ! Quel que soit l'emplacement de votre main, la ligne de code suivante doit y gurer :
penetre fen a new penetre@AY

Excutez votre nouveau code, et. . . vous obtenez exactement la mme chose que prcdemment. Vous conviendrez que c'est tout de mme plus pratique de ne plus crire les mmes instructions chaque fois. Ainsi, vous possdez une classe qui va se charger de l'achage de votre futur programme. Et voici une petite liste de mthodes que vous serez susceptibles d'utiliser. 242

L'OBJET JFRAME

Positionner la fentre l'cran


Nous avons dj centr notre fentre, mais vous voudriez peut-tre la positionner ailleurs. Pour cela, vous pouvez utiliser la mthode setLocation(int x, int y) . Grce cette mthode, vous pouvez spcier o doit se situer votre fentre sur l'cran. Les coordonnes, exprimes en pixels, sont bases sur un repre dont l'origine est reprsente par le coin suprieur gauche (gure 20.3).

Figure

20.3  Coordonnes sur votre cran

La premire valeur de la mthode vous positionne sur l'axe x, 0 correspondant l'origine ; les valeurs positives dplacent la fentre vers la droite tandis que les ngatives la font sortir de l'cran par la gauche. La mme rgle s'applique aux valeurs de l'axe y, si ce n'est que les valeurs positives font descendre la fentre depuis l'origine tandis que les ngatives la font sortir par le haut de l'cran.

Empcher le redimensionnement de la fentre


Pour cela, il sut d'invoquer la mthode setResizable(boolean b) : true empche le redimensionnement tandis que false l'autorise.

Garder la fentre au premier plan


Il s'agit l encore d'une mthode qui prend un boolen en paramtre. Passer true laissera la fentre au premier plan quoi qu'il advienne, false annulera cela. Cette mthode est setAlwaysOnTop(boolean b) .

Retirer les contours et les boutons de contrle


Pour ce faire, il faut utiliser la mthode setUndecorated(boolean b) . Je ne vais pas faire le tour de toutes les mthodes maintenant, car de toute faon, nous allons nous servir de bon nombre d'entre elles trs prochainement. Je suppose que vous aimeriez bien remplir un peu votre fentre. Je m'en doutais, mais avant, il vous faut encore apprendre une bricole. En eet, votre fentre, telle qu'elle 243

CHAPITRE 20. NOTRE PREMIRE FENTRE apparat, vous cache quelques petites choses. . . Vous pensez, et c'est lgitime, que votre fentre est toute simple, dpourvue de tout composant (hormis les contours). Eh bien, vous vous trompez ! Une JFrame est dcoupe en plusieurs parties superposes (gure 20.4) que voici, dans l'ordre :  la fentre ;  ensuite, le RootPane, le conteneur principal qui contient les autres composants ;  puis le LayeredPane, qui forme juste un panneau compos du conteneur global et de la barre de menu (MenuBar) ;  la MenuBar (barre de menu), quand il y en a une ;  vient ensuite le content pane : c'est dans celui-ci que nous placerons nos composants ;  enn, le GlassPane, couche utilise pour intercepter les actions de l'utilisateur avant qu'elles ne parviennent aux composants.

Figure

20.4  Structure d'une JFrame

Pas de panique, nous allons nous servir uniquement du content pane. Pour le rcuprer, il nous sut d'utiliser la mthode getContentPane() de la classe JFrame. Cependant, nous allons utiliser un composant autre que le content pane : un JPanel dans lequel nous insrerons nos composants.

Il existe d'autres types de fentre : la JWindow, une JFrame sans bordure et non draggable 4 , et la JDialog, une fentre non redimensionnable. Nous n'en parlerons toutefois pas ici.
4. Dplaable.

244

L'OBJET JPANEL

L'objet JPanel
Comme je vous l'ai dit, nous allons utiliser un JPanel, composant de type conteneur dont la vocation est d'accueillir d'autres objets de mme type ou des objets de type composant (boutons, cases cocher. . .).

Marche suivre
1. Importer la classe javax.swing.JPanel dans notre classe hrite de JFrame. 2. Instancier un JPanel puis lui spcier une couleur de fond pour mieux le distinguer. 3. Avertir notre JFrame que ce sera notre JPanel qui constituera son content pane. Rien de bien sorcier, en somme. Qu'attendons-nous ?
import jvFwtFgolorY import jvxFswingFtprmeY import jvxFswingFtnelY puli lss penetre extends tprme { puli penetre@A{ thisFsetitle@4w premire fentre tv4AY thisFsetize@RHHD IHHAY thisFsetvotioneltiveo@nullAY GGsnstnition d9un ojet tnel tnel pn a new tnel@AY GGhfinition de s ouleur de fond pnFsetfkground@golorFyexqiAY GGyn prvient notre tprme que notre tnel ser son ontent pne thisFsetgontentne@pnAY thisFsetisile@trueAY

Vous pouvez voir le rsultat en gure 20.5.

Figure

20.5  Premier JPanel

C'est un bon dbut, mais je vois que vous tes frustrs car il n'y a pas beaucoup de changement par rapport la dernire fois. . . Eh bien, c'est maintenant que les choses deviennent intressantes ! Avant de vous faire utiliser des composants (des boutons, par 245

CHAPITRE 20. NOTRE PREMIRE FENTRE exemple), nous allons nous amuser avec notre JPanel. Plus particulirement avec un objet dont le rle est de dessiner et de peindre notre composant. . . a vous tente ? Alors, go !

Les objets Graphics et Graphics2D


L'objet Graphics
Nous allons commencer par l'objet Graphics.Cet objet a une particularit de taille : vous ne pouvez l'utiliser que si et seulement si le systme vous l'a donn via la mthode getGraphics() d'un composant swing ! Pour bien comprendre le fonctionnement de nos futurs conteneurs (ou composants), nous allons crer une classe hrite de JPanel : appelons-la Panneau. Nous allons faire un petit tour d'horizon du fonctionnement de cette classe, dont voici le code :
import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ GGous verrez ette phrse hque fois que l mthode ser invoque ystemFoutFprintln@4te suis exute 34AY gFfillyvl@PHD PHD USD USAY } }

Qu'est-ce que c'est que cette mthode ?


Cette mthode est celle que l'objet appelle pour se dessiner sur votre fentre ; si vous rduisez cette dernire et que vous l'achez de nouveau, c'est encore cette mthode qui est appele pour acher votre composant. Idem si vous redimensionnez votre fentre. . . De plus, nous n'avons mme pas besoin de rednir un constructeur car cette mthode est appele automatiquement ! C'est trs pratique pour personnaliser des composants, car vous n'aurez jamais l'appeler vous-mmes : c'est automatique ! Tout ce que vous pouvez faire, c'est forcer l'objet se repeindre ; ce n'est toutefois pas cette mthode que vous invoquerez, mais nous y reviendrons. Vous aurez constat que cette mthode possde un argument et qu'il s'agit du fameux objet Graphics tant convoit. Nous reviendrons sur l'instruction g.fillOval(20, 20, 75, 75), mais vous verrez quoi elle sert lorsque vous excuterez votre programme. Voici maintenant notre classe Fenetre : 246

LES OBJETS GRAPHICS ET GRAPHICS2D


import jvxFswingFtprmeY puli lss penetre extends tprme { puli penetre@A{ thisFsetitle@4w premire fentre tv4AY thisFsetize@IHHD ISHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetgontentne@new nneu@AAY } thisFsetisile@trueAY

Excutez votre main, vous devriez obtenir la mme chose que sur la gure 20.6.

Figure

20.6  Test de l'objet Graphics

Une fois votre fentre ache, tirez-la, rduisez-la. . . prsent, vous pouvez voir ce qu'il se passe lorsque vous interagissez avec votre fentre : celle-ci met jour ses composants chaque changement d'tat ou de statut. L'intrt de disposer d'une classe hrite d'un conteneur ou d'un composant, c'est que nous pouvons rednir la faon dont est peint ce composant sur la fentre. Aprs cette mise en bouche, explorons un peu plus les capacits de notre objet Graphics. Comme vous avez pu le voir, ce dernier permet, entre autres, de tracer des ronds ; mais il possde tout un tas de mthodes plus pratiques et amusantes les unes que les autres. . . Nous ne les tudierons pas toutes, mais vous aurez dj de quoi faire. Pour commencer, reprenons la mthode utilise prcdemment : g.fillOval(20, 20, 75, 75). Si nous devions traduire cette instruction en franais, cela donnerait :  Trace un rond plein en commenant dessiner sur l'axe x 20 pixels et sur l'axe y 20 pixels, et fais en sorte qu'il occupe 75 pixels de large et 75 pixels de haut. 

Oui, mais si je veux que mon rond soit centr et qu'il le reste ?
C'est dans ce genre de cas qu'il est intressant d'utiliser une classe hrite. Puisque nous sommes dans notre objet JPanel, nous avons accs ses donnes lorsque nous le dessinons. 247

CHAPITRE 20. NOTRE PREMIRE FENTRE En eet, il existe des mthodes dans les objets composants qui retournent leur largeur (getWidth()) et leur hauteur (getHeight()). En revanche, russir centrer un rond dans un JPanel en toutes circonstances demande un peu de calcul mathmatique de base, une pince de connaissances et un soupon de logique ! Reprenons notre fentre telle qu'elle se trouve en ce moment. Vous pouvez constater que les coordonnes de dpart correspondent au coin suprieur gauche du carr qui entoure ce cercle (gure 20.7).

Figure

20.7  Point de dpart du cercle dessin

Cela signie que si nous voulons que notre cercle soit tout le temps centr, il faut que notre carr soit centr, donc que le centre de celui-ci corresponde au centre de notre fentre ! Voici un schma reprsentant ce que nous devons obtenir (gure 20.8).

Figure

20.8  Coordonnes recherches

Ainsi, le principe est d'utiliser la largeur et la hauteur de notre composant ainsi que la largeur et la hauteur du carr qui englobe notre rond ; c'est facile, jusqu' prsent. . . Maintenant, pour trouver o se situe le point depuis lequel doit commencer le dessin, il faut soustraire la moiti de la largeur du composant la moiti de celle du rond an d'obtenir la valeur sur l'axe x, et faire de mme (en soustrayant les hauteurs, cette fois) pour l'axe y. An que notre rond soit le plus optimis possible, nous allons donner comme taille notre carr la moiti de la taille de notre fentre ; ce qui revient, au nal, diviser la largeur et la hauteur de cette dernire par quatre. Voici le code correspondant :
import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{

248

LES OBJETS GRAPHICS ET GRAPHICS2D


int xI a thisFgetidth@AGRY int yI a thisFgetreight@AGRY gFfillyvl@xID yID thisFgetidth@AGPD thisFgetreight@AGPAY

Si vous testez nouveau notre code, vous vous apercevez que notre rond est maintenant centr. Cependant, l'objet Graphics permet d'eectuer plein d'autres choses, comme peindre des ronds vides, par exemple. Sans rire ! Maintenant que vous avez vu comment fonctionne cet objet, nous allons pouvoir utiliser ses mthodes.

La mthode drawOval(int x1, int y1, int width, int height)


Il s'agit de la mthode qui permet de dessiner un rond vide. Elle fonctionne exactement de la mme manire que la mthode fillOval(). Voici un code mettant en uvre cette mthode :
import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ int xI a thisFgetidth@AGRY int yI a thisFgetreight@AGRY gFdrwyvl@xID yID thisFgetidth@AGPD thisFgetreight@AGPAY } }

Le rsultat se trouve en gure 20.9 5 .

Figure

20.9  Rendu de la mthode drawOval()

La mthode drawRect(int x1, int y1, int width, int height)


Cette mthode permet de dessiner des rectangles vides. Bien sr, son homologue fillRect() existe. Ces deux mthodes fonctionnent de la mme manire que les prcdentes, voyez plutt ce code :
5. Si vous spciez une largeur dirente de la hauteur, ces mthodes dessineront une forme ovale.

249

CHAPITRE 20. NOTRE PREMIRE FENTRE


import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ gFdrwet@IHD IHD SHD THAY gFfillet@TSD TSD QHD RHAY } }

Et le rsultat en gure 20.10.

Figure

20.10  Rendu des mthodes drawRect() et fillRect()

La mthode drawRoundRect(int x1, int y1, int width, int height, int
arcWidth, int arcHeight)

Il s'agit du mme lment que prcdemment, hormis le fait que le rectangle sera arrondi. L'arrondi est dni par la valeur des deux derniers paramtres.
import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ gFdrwoundet@IHD IHD QHD SHD IHD IHAY gFfilloundet@SSD TSD SSD QHD SD SAY } }

Voyez le rsultat en gure 20.11.

La mthode drawLine(int x1, int y1, int x2, int y2)


Cette mthode permet de tracer des lignes droites. Il sut de lui spcier les coordonnes de dpart et d'arrive de la ligne. Dans ce code, je trace les diagonales du conteneur : 250

LES OBJETS GRAPHICS ET GRAPHICS2D

Figure

20.11  Rendu de la mthode drawRoundRect()

import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ gFdrwvine@HD HD thisFgetidth@AD thisFgetreight@AAY gFdrwvine@HD thisFgetreight@AD thisFgetidth@AD HAY } }

Le rsultat se trouve en gure 20.12.

Figure

20.12  Rendu de la mthode drawLine()

La mthode drawPolygon(int[] x, int[] y, int nbrePoints)


Grce cette mthode, vous pouvez dessiner des polygones de votre composition. Eh oui, c'est vous de dnir les coordonnes de tous les points qui les forment ! Le dernier paramtre de cette mthode est le nombre de points formant le polygone. Ainsi, vous n'aurez pas besoin d'indiquer deux fois le point d'origine pour boucler votre gure : Java la fermera automatiquement en reliant le dernier point de votre tableau au premier. Cette mthode possde galement son homologue pour dessiner des polygones remplis : fillPolygon().
import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{

251

CHAPITRE 20. NOTRE PREMIRE FENTRE


int x a {PHD QHD SHD THD THD SHD QHD PH}Y int y a {QHD PHD PHD QHD SHD THD THD SH}Y gFdrwolygon@xD yD VAY int xP a {SHD THD VHD WHD WHD VHD THD SH}Y int yP a {THD SHD SHD THD VHD WHD WHD VH}Y gFfillolygon@xPD yPD VAY

Voyez le rsultat en gure 20.13.

Figure

20.13  Rendu des mthodes drawPolygon() et fillPolygon()

Il existe aussi une mthode qui prend exactement les mmes arguments mais qui, elle, trace plusieurs lignes : drawPolyline(int[] x, int[] y, int nbrePoints) . Cette mthode va dessiner les lignes correspondant aux coordonnes dnies dans les tableaux, sachant que lorsque son indice s'incrmente, la mthode prend automatiquement les valeurs de l'indice prcdent comme point d'origine. Cette mthode ne fait pas le lien entre la premire et la dernire valeur de vos tableaux. Vous pouvez essayer le code prcdent en remplaant drawPolygon() par cette mthode.

La mthode drawString(String str, int x, int y)


Voici la mthode permettant d'crire du texte. Elle est trs simple utiliser : il sut de lui passer en paramtre la phrase crire et de lui spcier quelles coordonnes commencer.
import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ gFdrwtring@4iens 3 ve ite du ro 34D IHD PHAY } }

Le rsultat se trouve en gure 20.14. 252

LES OBJETS GRAPHICS ET GRAPHICS2D

Figure

20.14  Rendu de la mthode drawString()

Vous pouvez aussi modier la couleur 6 et la police d'criture. Pour rednir la police d'criture, vous devez crer un objet Font. Le code suivant illustre la faon de procder.
import jvFwtFgolorY import jvFwtFpontY import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ pont font a new pont@4gourier4D pontFfyvhD PHAY gFsetpont@fontAY gFsetgolor@golorFredAY gFdrwtring@4iens 3 ve ite du ro 34D IHD PHAY } }

Le rsultat correspond la gure 20.15.

Figure

20.15  Changement de couleur et de police d'criture

La mthode drawImage(Image img, int x, int y, Observer obs)


Vous devez charger votre image grce trois objets :  un objet Image ;  un objet ImageIO ;  un objet File.
6. La modication s'appliquera galement pour les autres mthodes.

253

CHAPITRE 20. NOTRE PREMIRE FENTRE Vous allez voir que l'utilisation de ces objets est trs simple. Il sut de dclarer un objet de type Image et de l'initialiser en utilisant une mthode statique de l'objet ImageIO qui, elle, prend un objet File en paramtre. a peut sembler compliqu, mais vous allez voir que ce n'est pas le cas. . . Notre image sera stocke la racine de notre projet, mais ce n'est pas une obligation. Dans ce cas, faites attention au chemin d'accs de votre image. En ce qui concerne le dernier paramtre de la mthode drawImage, il s'agit de l'objet qui est cens observer l'image. Ici, nous allons utiliser notre objet Panneau, donc this.

Cette mthode dessinera l'image avec ses propres dimensions. Si vous voulez qu'elle occupe l'intgralit de votre conteneur, utilisez le constructeur suivant : drawImage(Image img, int x, int y, int width, int height, Observer obs) .
import import import import import import jvFwtFqrphisY jvFwtFsmgeY jvFioFpileY jvFioFsyixeptionY jvxFimgeioFsmgesyY jvxFswingFtnelY

puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ try { smge img a smgesyFred@new pile@4imgesFjpg4AAY gFdrwsmge@imgD HD HD thisAY GGour une imge de fond GGgFdrwsmge@imgD HD HD thisFgetidth@AD thisFgetreight@AD thisAY } th @syixeption eA { eFprinttkre@AY } } }

Les rsultats se trouvent aux gures 20.16 7 et 20.17.

Figure

20.16  Conservation de la taille d'origine de l'image

7. Pour bien vous montrer la dirence, j'ai cr une fentre plus grande que l'image.

254

LES OBJETS GRAPHICS ET GRAPHICS2D

Figure

20.17  Adaptation de la taille de l'image

L'objet Graphics2D
Ceci est une amlioration de l'objet Graphics, et vous allez vite comprendre pourquoi. . . Pour utiliser cet objet, il nous sut en eet de caster l'objet Graphics en Graphics2D (Graphics2D g2d = (Graphics2D) g ), et de ne surtout pas oublier d'importer notre classe qui se trouve dans le package java.awt. L'une des possibilits qu'ore cet objet n'est autre que celle de peindre des objets avec des dgrads de couleurs. . . Cette opration n'est pas du tout dicile raliser : il sut d'utiliser un objet GradientPaint et une mthode de l'objet Graphics2D. Nous n'allons pas reprendre tous les cas que nous avons vus jusqu' prsent, mais juste deux ou trois an que vous voyiez bien la dirence. Commenons par notre objet GradientPaint ; voici comment l'initialiser 8 :
qrdientint gp a new qrdientint@HD HD golorFihD QHD QHD golorFynD trueAY

Alors, que signie tout cela ? Voici le dtail du constructeur utilis dans ce code :  premier paramtre : la coordonne x o doit commencer la premire couleur ;  deuxime paramtre : la coordonne y o doit commencer la premire couleur ;  troisime paramtre : la premire couleur ;  quatrime paramtre : la coordonne x o doit commencer la seconde couleur ;  cinquime paramtre : la coordonne y o doit commencer la seconde couleur ;  sixime paramtre : la seconde couleur ;  septime paramtre : le boolen indiquant si le dgrad doit se rpter. Ensuite, pour utiliser ce dgrad dans une forme, il faut mettre jour notre objet Graphics2D, comme ceci :
import import import import import import jvFwtFgolorY jvFwtFpontY jvFwtFqrdientintY jvFwtFqrphisY jvFwtFqrphisPhY jvFwtFsmgeY

8. Vous devez mettre jour vos imports en ajoutant import java.awt.GradientPaint .

255

CHAPITRE 20. NOTRE PREMIRE FENTRE


import jvFioFpileY import jvFioFsyixeptionY import jvxFimgeioFsmgesyY import jvxFswingFtnelY puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ qrphisPh gPd a @qrphisPhAgY qrdientint gp a new qrdientint@HD HD golorFihD QHD QHD golorFynD trueAY gPdFsetint@gpAY gPdFfillet@HD HD thisFgetidth@AD thisFgetreight@AAY } }

Voici les rsultats obtenus, l'un avec le boolen true (gure 20.18), et l'autre false (gure 20.19).

Figure

20.18  Dgrad rpt

Figure

20.19  Dgrad stopp

Votre dgrad est oblique (rien ne m'chappe, moi :p). Ce sont les coordonnes choisies qui inuent sur la direction du dgrad. Dans notre exemple, nous partons du point de coordonnes (0, 0) vers le point de coordonnes (30, 30). Pour obtenir un dgrad vertical, il sut d'indiquer la valeur de la seconde coordonne x 0, ce qui correspond la gure 20.20. Voici un petit cadeau. . . Arc-en-ciel Code web : 649521  256


LES OBJETS GRAPHICS ET GRAPHICS2D

Figure

20.20  Dgrad horizontal

import import import import import import

jvFwtFgolorY jvFwtFqrdientintY jvFwtFqrphisY jvFwtFqrphisPhY jvxFimgeioFsmgesyY jvxFswingFtnelY

puli lss nneu extends tnel { puli void pintgomponent@qrphis gA{ qrphisPh gPd a @qrphisPhAgY qrdientint gpD gpPD gpQD gpRD gpSD gpTY gp a new qrdientint@HD HD golorFihD PHD HD golorFmgentD trueAY gpP a new qrdientint@PHD HD golorFmgentD RHD HD golorFlueD trueAY gpQ a new qrdientint@RHD HD golorFlueD THD HD golorFgreenD trueAY gpR a new qrdientint@THD HD golorFgreenD VHD HD golorFyellowD trueAY gpS a new qrdientint@VHD HD golorFyellowD IHHD HD golorForngeD trueAY gpT a new qrdientint@IHHD HD golorForngeD IPHD HD golorFredD trueAY gPdFsetint@gpAY gPdFfillet@HD HD PHD thisFgetreight@AAY gPdFsetint@gpPAY gPdFfillet@PHD HD PHD thisFgetreight@AAY gPdFsetint@gpQAY gPdFfillet@RHD HD PHD thisFgetreight@AAY gPdFsetint@gpRAY gPdFfillet@THD HD PHD thisFgetreight@AAY gPdFsetint@gpSAY gPdFfillet@VHD HD PHD thisFgetreight@AAY gPdFsetint@gpTAY gPdFfillet@IHHD HD RHD thisFgetreight@AAY

Maintenant que vous savez utiliser les dgrads avec des rectangles, vous savez les utiliser avec toutes les formes. Je vous laisse essayer cela tranquillement chez vous. 257

CHAPITRE 20. NOTRE PREMIRE FENTRE

En rsum
 Pour crer des fentres, Java fournit les composants swing (dans javax.swing) et awt (dans java.awt).  Il ne faut pas mlanger les composants swing et awt.  Une JFrame est constitue de plusieurs composants.  Par dfaut, une fentre a une taille minimale et n'est pas visible.  Un composant doit tre bien paramtr pour qu'il fonctionne votre convenance.  L'objet JPanel se trouve dans le package javax.swing.  Un JPanel peut contenir des composants ou d'autres conteneurs.  Lorsque vous ajoutez un JPanel principal votre fentre, n'oubliez pas d'indiquer votre fentre qu'il constituera son content pane.  Pour rednir la faon dont l'objet est dessin sur votre fentre, vous devez utiliser la mthode paintComponent() en crant une classe hrite.  Cette mthode prend en paramtre un objet Graphics.  Cet objet doit vous tre fourni par le systme.  C'est lui que vous allez utiliser pour dessiner dans votre conteneur.  Pour des dessins plus volus, vous devez utiliser l'objet Graphics2D qui s'obtient en eectuant un cast sur l'objet Graphics.

258

Chapitre

21
Dicult :

Le l rouge : une animation

ans ce chapitre, nous allons voir comment crer une animation simple. Il ne vous sera pas possible de raliser un jeu au terme de ce chapitre, mais je pense que vous y trouverez de quoi vous amuser un peu. . . Nous rutiliserons cette animation dans plusieurs chapitres de cette troisime partie an d'illustrer le fonctionnement de divers composants graphiques. L'exemple est rudimentaire, mais il a l'avantage d'tre ecace et de favoriser votre apprentissage de la programmation vnementielle. Je sens que vous tes impatients de commencer. . . Alors, let's go !

259

CHAPITRE 21. LE FIL ROUGE : UNE ANIMATION

Cration de l'animation
Voici un rsum de ce que nous avons dj cod :  une classe hrite de JFrame ;  une classe hrite de JPanel avec laquelle nous faisons de jolis dessins. Un rond, en l'occurrence. En utilisant ces deux classes, nous allons pouvoir crer un eet de dplacement. Vous avez bien lu : j'ai parl d'un eet de dplacement ! Le principe rside dans le fait que vous allez modier les coordonnes de votre rond et forcer votre objet Panneau se redessiner. Tout cela  vous l'avez dj devin  dans une boucle. Jusqu' prsent, nous avons utilis des valeurs xes pour les coordonnes du rond, mais il va falloir dynamiser tout a. . . Nous allons donc crer deux variables prives de type int dans la classe Panneau : appelons-les posX et posY. Dans l'animation sur laquelle nous allons travailler, notre rond viendra de l'extrieur de la fentre. Partons du principe que celui-ci a un diamtre de cinquante pixels : il faut donc que notre panneau peigne ce rond en dehors de sa zone d'achage. Nous initialiserons donc nos deux variables d'instance -50. Voici le code de notre classe Panneau :
import jvFwtFgolorY import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { privte int pos a ESHY privte int pos a ESHY puli void pintgomponent@qrphis gA{ gFsetgolor@golorFredAY gFfillyvl@posD posD SHD SHAY } puli int getos@A { return posY } puli void setos@int posA { thisFpos a posY } puli int getos@A { return posY } puli void setos@int posA { thisFpos a posY }

260

CRATION DE L'ANIMATION Il ne nous reste plus qu' faire en sorte que notre rond se dplace. Nous allons devoir trouver un moyen de changer ses coordonnes grce une boucle. An de grer tout cela, ajoutons une mthode prive dans notre classe Fenetre que nous appellerons en dernier lieu dans notre constructeur. Voici donc ce quoi ressemble notre classe Fenetre :
import jvFwtFhimensionY import jvxFswingFtprmeY puli lss penetre extends tprme{ privte nneu pn a new nneu@AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY thisFsetgontentne@pnAY thisFsetisile@trueAY go@AY } privte void go@A{ for@int i a ESHY i ` pnFgetidth@AY iCCA{ int x a pnFgetos@AD y a pnFgetos@AY xCCY yCCY pnFsetos@xAY pnFsetos@yAY pnFrepint@AY try { hredFsleep@IHAY } th @snterruptedixeption eA { eFprinttkre@AY } } }

Vous vous demandez srement l'utilit des deux instructions la n de la mthode go(). . . La premire de ces deux nouvelles instructions est pan.repaint(). Elle demande votre composant, ici un JPanel, de se redessiner. La toute premire fois, dans le constructeur de notre classe Fenetre, votre composant avait invoqu la mthode paintComponent() et avait dessin un rond aux coordonnes que vous lui aviez spcies. La mthode repaint() ne fait rien d'autre qu'appeler nouveau la mthode paintComponent() ; mais puisque nous avons chang les coordonnes du rond par le biais des accesseurs, la position de celui-ci sera modie chaque tour de boucle. 261

CHAPITRE 21. LE FIL ROUGE : UNE ANIMATION La deuxime instruction, Thread.sleep(), est un moyen de suspendre votre code. . . Elle met en attente votre programme pendant un laps de temps dni dans la mthode sleep() exprim en millimes de seconde 1 . Thread est en fait un objet qui permet de crer un nouveau processus dans un programme ou de grer le processus principal. Dans tous les programmes, il y a au moins un processus : celui qui est en cours d'excution. Vous verrez plus tard qu'il est possible de diviser certaines tches en plusieurs processus an de ne pas perdre du temps et des performances. Pour le moment, sachez que vous pouvez eectuer des pauses dans vos programmes grce cette instruction :
try{ hredFsleep@IHHHAY GGsiD une puse d9une seonde }th@snterruptedixeption eA { eFprinttkre@AY }

Cette instruction est dite  risque , vous devez donc l'entourer d'un bloc try{...} catch{...} an de capturer les exceptions potentielles. Sinon : erreur de compilation !
Maintenant que la lumire est faite sur cette aaire, excutez ce code, vous obtenez la gure 21.1.

Figure

21.1  Rendu nal de l'animation

Bien sr, cette image est le rsultat nal : vous devez avoir vu votre rond bouger. Sauf qu'il a laiss une trane derrire lui. . . L'explication de ce phnomne est simple : vous avez demand votre objet Panneau de se redessiner, mais il a galement ach les prcdents passages de votre rond ! Pour rsoudre ce problme, il faut eacer ces derniers avant de redessiner le rond. Comment ? Dessinez un rectangle de n'importe quelle couleur occupant toute la surface disponible avant de peindre votre rond. Voici le nouveau code de la classe Panneau :
1. Plus le temps d'attente est court, plus l'animation est rapide.

262

AMLIORATIONS
import jvFwtFgolorY import jvFwtFqrphisY import jvxFswingFtnelY puli lss nneu extends tnel { privte int pos a ESHY privte int pos a ESHY puli void pintgomponent@qrphis gA{ GGyn hoisit une ouleur de fond pour le retngle gFsetgolor@golorFwhiteAY GGyn le dessine de sorte qu9il oupe toute l surfe gFfillet@HD HD thisFgetidth@AD thisFgetreight@AAY GGyn redfinit une ouleur pour le rond gFsetgolor@golorFredAY GGyn le dessine ux oordonnes souhites gFfillyvl@posD posD SHD SHAY } puli int getos@A { return posY } puli void setos@int posA { thisFpos a posY } puli int getos@A { return posY } puli void setos@int posA { thisFpos a posY }

Voici trois captures d'cran (gure 21.2) prises dirents instants de l'animation. Cela vous plairait-il que votre animation se poursuive tant que vous ne fermez pas la fentre ? Oui ? Alors, continuons.

Amliorations
Voici l'un des moments dlicats que j'attendais. . . Si vous vous rappelez bien ce que je vous ai expliqu sur le fonctionnement des boucles, vous vous souvenez de mon avertissement propos des boucles innies. Eh bien, ce que nous allons faire ici, c'est justement utiliser une boucle innie. Il existe plusieurs manires de raliser une boucle innie : vous avez le choix entre une 263

CHAPITRE 21. LE FIL ROUGE : UNE ANIMATION

Figure

21.2  Capture de l'animation trois moments dirents

boucle for, while ou do... while. Regardez ces dclarations :


GGixemple ve une oule while while@trueA{ GGge ode se rpter l9infiniD r l ondition est toujours vrie 3 } GGixemple ve une oule for for@YYA { GGsdem que prdemment X il n9y ps d9inrmentD GGdon l oule ne se terminer jmisF } GGixemple ve doFFF while do{ GGinore une oule que ne se terminer psF }while@trueAY

Nous allons donc remplacer notre boucle nie par une boucle innie dans la mthode go() de l'objet Fenetre. Cela donne :
privte void go@A{ for@YYA{ int x a pnFgetos@AD y a pnFgetos@AY xCCY yCCY pnFsetos@xAY pnFsetos@yAY pnFrepint@AY try { hredFsleep@IHAY } th @snterruptedixeption eA { eFprinttkre@AY }

264

AMLIORATIONS
}

Si vous avez excut cette nouvelle version, vous vous tes rendu compte qu'il reste un problme rgler. . . En eet, notre rond ne se replace pas son point de dpart une fois qu'il a atteint l'autre ct de la fentre !

Si vous ajoutez une instruction System.out.println() dans la mthode inscrivant les coordonnes du rond, vous verrez que celles-ci ne cessent de crotre.
paintComponent()

Le premier objectif est bien atteint, mais il nous reste rsoudre ce dernier problme. Pour cela, il faut rinitialiser les coordonnes du rond lorsqu'elles atteignent le bout de notre composant. Voici donc notre mthode go() revue et corrige :
privte void go@A{ for@YYA{ int x a pnFgetos@AD y a pnFgetos@AY xCCY yCCY pnFsetos@xAY pnFsetos@yAY pnFrepint@AY try { hredFsleep@IHAY } th @snterruptedixeption eA { eFprinttkre@AY } GGi nos oordonnes rrivent u ord de notre omposnt GGyn rinitilise if@x aa pnFgetidth@A || y aa pnFgetreight@AA{ pnFsetos@ESHAY pnFsetos@ESHAY } } }

Ce code fonctionne parfaitement (en tout cas, comme nous l'avons prvu), mais avant de passer au chapitre suivant, nous pouvons encore l'amliorer. . . Nous allons maintenant rendre notre rond capable de dtecter les bords de notre Panneau et de ricocher sur ces derniers ! Jusqu' prsent, nous n'attachions aucune importance au bord que notre rond dpassait. Cela est termin ! Dornavant, nous sparerons le dpassement des coordonnes posX et posY de notre Panneau.

Pour les instructions qui vont suivre, gardez en mmoire que les coordonnes du rond correspondent en ralit aux coordonnes du coin suprieur gauche du carr entourant le rond.
265

CHAPITRE 21. LE FIL ROUGE : UNE ANIMATION Voici la marche suivre :  si la valeur de la coordonne x du rond est infrieure la largeur du composant et que le rond avance, on continue d'avancer ;  sinon, on recule. Nous allons faire de mme pour la coordonne y. Comment savoir si l'on doit avancer ou reculer ? Grce un boolen, par exemple. Au tout dbut de notre application, deux boolens seront initialiss false, et si la coordonne x est suprieure la largeur du Panneau, on recule ; sinon, on avance. Idem pour la coordonne y.

Dans ce code, j'utilise deux variables de type int pour viter de rappeler les mthodes getPosX() et getPosY().
Voici donc le nouveau code de la mthode go() :
privte void go@A{ GGves oordonnes de dprt de notre rond int x a pnFgetos@AD y a pnFgetos@AY GGve oolen pour svoir si l9on reule ou non sur l9xe x oolen k a flseY GGve oolen pour svoir si l9on reule ou non sur l9xe y oolen k a flseY GGhns et exempleD j9utilise une oule while GGous verrez qu9elle fontionne trs ien while@trueA{ GGi l oordonne x est infrieure ID on vne if@x ` IAk a flseY GGi l oordonne x est suprieure l tille du nneu GGmoins l tille du rondD on reule if@x b pnFgetidth@AESHAk a trueY GGsdem pour l9xe y if@y ` IAk a flseY if@y b pnFgetreight@AESHAk a trueY GGi on vneD on inrmente l oordonne GGk est un oolenD don 3k revient rire GGif @k aa flseA if@3kA pnFsetos@CCxAY GGinonD on drmente else pnFsetos@EExAY GGsdem pour l9xe if@3kA pnFsetos@CCyAY else

266

AMLIORATIONS
pnFsetos@EEyAY GGyn redessine notre nneu pnFrepint@AY GGgomme on dit X l puse s9impose 3 siD trois millimes de seonde try { hredFsleep@QAY } th @snterruptedixeption eA { eFprinttkre@AY }

Excutez l'application : le rond ricoche contre les bords du Panneau. Vous pouvez mme tirer la fentre ou la rduire, a marchera toujours ! On commence faire des choses sympa, non ? Vous pouvez tlcharger le projet avec le code complet si vous le souhaitez : Copier le projet Code web : 638812 


En rsum
 l'instanciation d'un composant, la mthode paintComponent() est automatiquement appele.  Vous pouvez forcer un composant se redessiner en invoquant la mthode repaint().  Pensez bien ce que va produire votre composant une fois redessin.  Pour viter que votre animation ne bave, rinitialisez le fond du composant.  Tous les composants fonctionnent de la mme manire.  L'instruction Thread.sleep() permet d'eectuer une pause dans le programme.  Cette mthode prend en paramtre un entier qui correspond une valeur temporelle exprime en millimes de seconde.  Vous pouvez utiliser des boucles innies pour crer des animations.

267

CHAPITRE 21. LE FIL ROUGE : UNE ANIMATION

268

Chapitre

22
Dicult :

Positionner des boutons

oici l'un des moments que vous attendiez avec impatience ! Vous allez enn pouvoir utiliser un bouton dans votre application. Cependant, ne vous rjouissez pas trop vite : vous allez eectivement insrer un bouton, mais vous vous rendrez rapidement compte que les choses se compliquent ds que vous employez ce genre de composant. . . Et c'est encore pire lorsqu'il y en a plusieurs ! Avant de commencer, nous devrons apprendre positionner des composants dans une fentre. Il nous faut en eet grer la faon dont le contenu est ach dans une fentre.

269

CHAPITRE 22. POSITIONNER DES BOUTONS

Utiliser la classe JButton


Comme indiqu dans le titre, nous allons utiliser la classe JButton issue du package javax.swing. Au cours de ce chapitre, notre projet prcdent sera mis l'cart : oublions momentanment notre objet Panneau. Crons un nouveau projet comprenant :  une classe contenant une mthode main que nous appellerons Test ;  une classe hrite de JFrame 1 , nous la nommerons Fenetre. Dans la classe Fenetre, nous allons crer une variable d'instance de type JPanel et une autre de type JButton. Faisons de JPanel le content pane de notre Fenetre, puis dnissons le libell 2 de notre bouton et mettons-le sur ce qui nous sert de content pane (en l'occurrence, JPanel). Pour attribuer un libell un bouton, il y a deux possibilits :
GGossiilit I X instnition ve le liell tfutton outon a new tfutton@4won premier outon4AY GGossiilit P X instnition puis dfinition du liell tfutton outonP a new tfutton@AY outonPFsetext@4won deuxime outon4AY

Il ne nous reste plus qu' ajouter ce bouton sur notre content pane grce la mthode add() de l'objet JPanel. Voici donc notre code :
import jvxFswingFtfuttonY import jvxFswingFtprmeY import jvxFswingFtnelY puli lss penetre extends tprme{ privte tnel pn a new tnel@AY privte tfutton outon a new tfutton@4won outon4AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY GGejout du outon notre ontent pne pnFdd@outonAY thisFsetgontentne@pnAY thisFsetisile@trueAY }

Voyez le rsultat en gure 22.1.


1. Contenant la totalit du code que l'on a dj crit, hormis la mthode go(). 2. On parle aussi d'tiquette.

270

UTILISER LA CLASSE JBUTTON

Figure

22.1  Achage d'un JButton

Je ne sais pas si vous avez remarqu, mais votre bouton est centr sur votre conteneur ! Cela vous semble normal ? a l'est, car par dfaut, JPanel gre la mise en page. En fait, il existe en Java des objets qui servent agencer vos composants, et JPanel en instancie un par dfaut. Pour vous le prouver, je vais vous faire travailler sur le content pane de votre JFrame. Vous constaterez que pour obtenir la mme chose que prcdemment, nous allons tre obligs d'utiliser un de ces fameux objets d'agencement. Tout d'abord, pour utiliser le content pane d'une JFrame, il faut appeler la mthode getContentPane() : nous ajouterons nos composants au content pane qu'elle retourne. Voici donc le nouveau code :
import jvxFswingFtfuttonY import jvxFswingFtprmeY puli lss penetre extends tprme{ privte tfutton outon a new tfutton@4won outon4AY puli penetre@A{ thisFsetitle@4fouton4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY GGyn joute le outon u ontent pne de l tprme thisFgetgontentne@AFdd@outonAY thisFsetisile@trueAY }

La gure 22.2 montre que le rsultat n'est pas du tout concluant. Votre bouton est norme ! En fait, il occupe toute la place disponible, parce que le content pane de votre JFrame ne possde pas d'objet d'agencement. Faisons donc un petit tour d'horizon de ces objets et voyons comment ils fonctionnent. 271

CHAPITRE 22. POSITIONNER DES BOUTONS

Figure

22.2  Bouton positionn sur le content pane

Positionner son composant : les layout managers


Vous allez voir qu'il existe plusieurs sortes de layout managers, plus ou moins simples utiliser, dont le rle est de grer la position des lments sur la fentre. Tous ces layout managers se trouvent dans le package java.awt.

L'objet BorderLayout
Le premier objet que nous aborderons est le BorderLayout. Il est trs pratique si vous voulez placer vos composants de faon simple par rapport une position cardinale de votre conteneur. Si je parle de positionnement cardinal, c'est parce que vous devez utiliser les valeurs NORTH, SOUTH, EAST, WEST ou encore CENTER. Mais puisqu'un aperu vaut mieux qu'un expos sur le sujet, voici un exemple (gure 22.3) mettant en uvre un BorderLayout.

Figure

22.3  Exemple de BorderLayout

Cette fentre est compose de cinq JButton positionns aux cinq endroits dirents que propose un BorderLayout. Voici le code de cette fentre : 272

POSITIONNER SON COMPOSANT : LES LAYOUT MANAGERS


import jvFwtFfordervyoutY import jvxFswingFtfuttonY import jvxFswingFtprmeY puli lss penetre extends tprme{ puli penetre@A{ thisFsetitle@4fouton4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY GGyn dfinit le lyout utiliser sur le ontent pne thisFsetvyout@new fordervyout@AAY GGyn joute le outon u ontent pne de l tprme GGeu entre thisFgetgontentne@AFdd@new tfutton@4gixi4AD fordervyoutFgixiAY GGeu nord thisFgetgontentne@AFdd@new tfutton@4xyr4AD fordervyoutFxyrAY GGeu sud thisFgetgontentne@AFdd@new tfutton@4yr4AD fordervyoutFyrAY GG l9ouest thisFgetgontentne@AFdd@new tfutton@4i4AD fordervyoutFiAY GG l9est thisFgetgontentne@AFdd@new tfutton@4ie4AD fordervyoutFieAY thisFsetisile@trueAY } }

Ce n'est pas trs dicile comprendre. Vous dnissez le layout utiliser avec la mthode setLayout() de l'objet JFrame ; ensuite, pour chaque composant que vous souhaitez positionner avec add(), vous utilisez en deuxime paramtre un attribut static de la classe BorderLayout 3 . Utiliser l'objet BorderLayout soumet vos composants certaines contraintes. Pour une position NORTH ou SOUTH, la hauteur de votre composant sera proportionnelle la fentre, mais il occupera toute la largeur ; tandis qu'avec WEST et EAST, ce sera la largeur qui sera proportionnelle alors que toute la hauteur sera occupe ! Et bien entendu, avec CENTER, tout l'espace est utilis.

Vous devez savoir que CENTER est aussi le layout par dfaut du content pane de la fentre, d'o la taille du bouton lorsque vous l'avez ajout pour la premire fois.
L'objet GridLayout
Celui-ci permet d'ajouter des composants suivant une grille dnie par un nombre de lignes et de colonnes. Les lments sont disposs partir de la case situe en haut
3. Dont la liste est cite plus haut.

273

CHAPITRE 22. POSITIONNER DES BOUTONS gauche. Ds qu'une ligne est remplie, on passe la suivante. Si nous dnissons une grille de trois lignes et de deux colonnes, nous obtenons le rsultat visible sur la gure 22.4.

Figure

22.4  Exemple de rendu avec un GridLayout

Voici le code de cet exemple :


import jvFwtFqridvyoutY import jvxFswingFtfuttonY import jvxFswingFtprmeY puli lss penetre extends tprme{ puli penetre@A{ thisFsetitle@4fouton4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY GGyn dfinit le lyout utiliser sur le ontent pne GGrois lignes sur deux olonnes thisFsetvyout@new qridvyout@QD PAAY GGyn joute le outon u ontent pne de l tprme thisFgetgontentne@AFdd@new tfutton@4I4AAY thisFgetgontentne@AFdd@new tfutton@4P4AAY thisFgetgontentne@AFdd@new tfutton@4Q4AAY thisFgetgontentne@AFdd@new tfutton@4R4AAY thisFgetgontentne@AFdd@new tfutton@4S4AAY thisFsetisile@trueAY } }

Ce code n'est pas bien dirent du prcdent : nous utilisons simplement un autre layout manager et n'avons pas besoin de dnir le positionnement lors de l'ajout du composant avec la mthode add(). Sachez galement que vous pouvez dnir le nombre de lignes et de colonnes en utilisant ces mthodes : 274

POSITIONNER SON COMPOSANT : LES LAYOUT MANAGERS


qridvyout gl a new qridvyout@AY glFsetgolumns@PAY glFsetows@QAY thisFsetvyout@glAY

Vous pouvez aussi ajouter de l'espace entre les colonnes et les lignes.
qridvyout gl a new qridvyout@QD PAY glFsetrgp@SAY GGginq pixels d9espe entre les olonnes @r omme rorizontlA glFsetgp@SAY GGginq pixels d9espe entre les lignes @ omme ertilA GGyu en rg X qridvyout gl a new qridvyout@QD PD SD SAY

On obtient ainsi la gure 22.5.

Figure

22.5  Ajout d'espaces entre les lignes et les colonnes

L'objet BoxLayout
Grce lui, vous pourrez ranger vos composants la suite soit sur une ligne, soit sur une colonne. . . Le mieux, c'est encore un exemple de rendu (gure 22.6) avec un petit code.

Figure

22.6  Exemple de BoxLayout

Voici le code correspondant :


import jvxFswingFfoxvyoutY import jvxFswingFtfuttonY

275

CHAPITRE 22. POSITIONNER DES BOUTONS


import jvxFswingFtprmeY import jvxFswingFtnelY puli lss penetre extends tprme{ puli penetre@A{ thisFsetitle@4fox vyout4AY thisFsetize@QHHD IPHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY tnel I a new tnel@AY GGyn dfinit le lyout en lui indiqunt qu9il trviller en ligne IFsetvyout@new foxvyout@ID foxvyoutFvsxiesAAY IFdd@new tfutton@4fouton I4AAY tnel P a new tnel@AY GGsdem pour ette ligne PFsetvyout@new foxvyout@PD foxvyoutFvsxiesAAY PFdd@new tfutton@4fouton P4AAY PFdd@new tfutton@4fouton Q4AAY tnel Q a new tnel@AY GGsdem pour ette ligne QFsetvyout@new foxvyout@QD foxvyoutFvsxiesAAY QFdd@new tfutton@4fouton R4AAY QFdd@new tfutton@4fouton S4AAY QFdd@new tfutton@4fouton T4AAY tnel R a new tnel@AY GGyn positionne mintennt es trois lignes en olonne RFsetvyout@new foxvyout@RD foxvyoutFeqiesAAY RFdd@IAY RFdd@PAY RFdd@QAY thisFgetgontentne@AFdd@RAY thisFsetisile@trueAY

les rangeons dans un quatrime o, cette fois, nous les agenons dans une colonne grce l'attribut PAGE_AXIS. Rien de compliqu, vous en conviendrez, mais vous devez savoir qu'il existe un moyen encore plus simple d'utiliser ce layout : via l'objet Box. Ce dernier n'est rien d'autre qu'un conteneur paramtr avec un BoxLayout. Voici un code achant la mme chose que le prcdent : 276

Ce code est simple : on cre trois JPanel contenant chacun un certain nombre de JButton rangs en ligne grce l'attribut LINE_AXIS. Ces trois conteneurs crs, nous

POSITIONNER SON COMPOSANT : LES LAYOUT MANAGERS


import jvxFswingFfoxY import jvxFswingFtfuttonY import jvxFswingFtprmeY puli lss penetre extends tprme{ puli penetre@A{ thisFsetitle@4fox vyout4AY thisFsetize@QHHD IPHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY GGyn re un onteneur ve gestion horizontle fox I a foxFreterorizontlfox@AY IFdd@new tfutton@4fouton I4AAY GGsdem fox P a foxFreterorizontlfox@AY PFdd@new tfutton@4fouton P4AAY PFdd@new tfutton@4fouton Q4AAY GGsdem fox Q a foxFreterorizontlfox@AY QFdd@new tfutton@4fouton R4AAY QFdd@new tfutton@4fouton S4AAY QFdd@new tfutton@4fouton T4AAY GGyn re un onteneur ve gestion vertile fox R a foxFreteertilfox@AY RFdd@IAY RFdd@PAY RFdd@QAY thisFgetgontentne@AFdd@RAY thisFsetisile@trueAY

L'objet CardLayout
Vous allez prsent pouvoir grer vos conteneurs comme un tas de cartes (les uns sur les autres), et basculer d'un contenu l'autre en deux temps, trois clics. Le principe est d'assigner des conteneurs au layout en leur donnant un nom an de les retrouver plus facilement, permettant de passer de l'un l'autre sans eort. La gure 22.7 est un schma reprsentant ce mode de fonctionnement. Je vous propose un code utilisant ce layout. Vous remarquerez que j'ai utilis des boutons an de passer d'un conteneur un autre et n'y comprendrez peut-tre pas tout, mais ne vous inquitez pas, nous allons apprendre raliser tout cela avant la n de ce chapitre. Pour le moment, ne vous attardez donc pas trop sur les actions : concentrez-vous sur le layout en lui-mme. 277

CHAPITRE 22. POSITIONNER DES BOUTONS

Figure

22.7  Schma du CardLayout

import import import import import import import import

jvFwtFfordervyoutY jvFwtFgrdvyoutY jvFwtFgolorY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtnelY

puli lss penetre extends tprme{ grdvyout l a new grdvyout@AY tnel ontent a new tnel@AY GGviste des noms de nos onteneurs pour l pile de rtes tring listgontent a {4gehI4D 4gehP4D 4gehQ4}Y int indie a HY puli penetre@A{ thisFsetitle@4grdvyout4AY thisFsetize@QHHD IPHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY GGyn re trois onteneurs de ouleur diffrente tnel rdI a new tnel@AY rdIFsetfkground@golorFlueAY tnel rdP a new tnel@AY rdPFsetfkground@golorFredAY tnel rdQ a new tnel@AY rdQFsetfkground@golorFgreenAY tnel outonne a new tnel@AY tfutton outon a new tfutton@4gontenu suivnt4AY GGhfinition de l9tion du outon outonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eventA{ GGi ette instrutionD on psse u prohin onteneur de l pile lFnext@ontentAY } }AY

278

POSITIONNER SON COMPOSANT : LES LAYOUT MANAGERS

tfutton outonP a new tfutton@4gontenu pr indie4AY GGhfinition de l9tion du outonP outonPFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eventA{ if@CCindie b PA indie a HY GGi ette instrutionD on psse u onteneur GGorrespondnt u nom fourni en prmtre lFshow@ontentD listgontentindieAY } }AY outonneFdd@outonAY outonneFdd@outonPAY GGyn dfinit le lyout ontentFsetvyout@lAY GGyn joute les rtes l pile ve un nom pour les retrouver ontentFdd@rdID listgontentHAY ontentFdd@rdPD listgontentIAY ontentFdd@rdQD listgontentPAY thisFgetgontentne@AFdd@outonneD fordervyoutFxyrAY thisFgetgontentne@AFdd@ontentD fordervyoutFgixiAY thisFsetisile@trueAY

Copier ce code Code web : 933702  La gure 22.8 correspond aux rsultats de ce code chaque clic sur les boutons.

L'objet GridBagLayout
Cet objet est certainement le plus dicile utiliser et comprendre (ce qui l'a beaucoup desservi auprs des dveloppeurs Java). Pour faire simple, ce layout se prsente sous la forme d'une grille la faon d'un tableau Excel : vous devez positionner vos composants en vous servant des coordonnes des cellules (qui sont dnies lorsque vous spciez leur nombre). Vous devez aussi dnir les marges et la faon dont vos composants se rpliquent dans les cellules. . . Vous voyez que c'est plutt dense comme gestion du positionnement. Je tiens aussi vous prvenir que je n'entrerai pas trop dans les dtails de ce layout an de ne pas trop compliquer les choses. La gure 22.9 reprsente la faon dont nous allons positionner nos composants. Imaginez que le nombre de colonnes et de lignes ne soit pas limit comme il l'est sur le schma (c'est un exemple et j'ai d limiter sa taille, mais le principe est l). Vous paramtreriez le composant avec des coordonnes de cellules, en prcisant si celui-ci doit occuper une ou plusieurs d'entre elles. An d'obtenir un rendu correct, vous devriez 279

CHAPITRE 22. POSITIONNER DES BOUTONS

Figure

22.8  Schma du CardLayout

Figure

22.9  Positionnement avec le GridBagLayout

280

POSITIONNER SON COMPOSANT : LES LAYOUT MANAGERS indiquer au layout manager lorsqu'une ligne se termine, ce qui se fait en spciant qu'un composant est le dernier lment d'une ligne, et vous devriez en plus spcier au composant dbutant la ligne qu'il doit suivre le dernier composant de la prcdente. Je me doute que c'est assez ou et confus, je vous propose donc un exemple en vous montrant ce que nous allons obtenir (gure 22.10).

Figure

22.10  Exemple de GridBagLayout

Tous les lments que vous voyez sont des conteneurs positionns suivant une matrice, comme expliqu ci-dessus. An que vous vous en rendiez compte, regardez comment le tout est rang sur la gure 22.11.

Figure

22.11  Composition du GridBagLayout

Vous pouvez voir que nous avons fait en sorte d'obtenir un tableau de quatre colonnes sur trois lignes. Nous avons positionn quatre lments sur la premire ligne, spci que le quatrime lment terminait celle-ci, puis nous avons plac un autre composant au dbut de la deuxime ligne d'une hauteur de deux cases, en informant le gestionnaire que celui-ci suivait directement la n de la premire ligne. Nous ajoutons un composant de trois cases de long terminant la deuxime ligne, pour passer ensuite un composant de deux cases de long puis un dernier achevant la dernire ligne. Lorsque des composants se trouvent sur plusieurs cases, vous devez spcier la faon dont ils s'talent : horizontalement ou verticalement. Le moment est venu de vous fournir le code de cet exemple, mais je vous prviens, a pique un peu les yeux :
import jvFwtFfordervyoutY import jvFwtFgolorY

281

CHAPITRE 22. POSITIONNER DES BOUTONS


import import import import import jvFwtFhimensionY jvFwtFqridfggonstrintsY jvFwtFqridfgvyoutY jvxFswingFtprmeY jvxFswingFtnelY

puli lss penetre extends tprme{ puli penetre@A{ thisFsetitle@4qridfgvyout4AY thisFsetize@QHHD ITHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY GGyn re nos diffrents onteneurs de ouleur diffrente tnel ellI a new tnel@AY ellIFsetfkground@golorFivvyAY ellIFsetreferredize@new himension@THD RHAAY tnel ellP a new tnel@AY ellPFsetfkground@golorFredAY ellPFsetreferredize@new himension@THD RHAAY tnel ellQ a new tnel@AY ellQFsetfkground@golorFgreenAY ellQFsetreferredize@new himension@THD RHAAY tnel ellR a new tnel@AY ellRFsetfkground@golorFlkAY ellRFsetreferredize@new himension@THD RHAAY tnel ellS a new tnel@AY ellSFsetfkground@golorFynAY ellSFsetreferredize@new himension@THD RHAAY tnel ellT a new tnel@AY ellTFsetfkground@golorFfviAY ellTFsetreferredize@new himension@THD RHAAY tnel ellU a new tnel@AY ellUFsetfkground@golorForngeAY ellUFsetreferredize@new himension@THD RHAAY tnel ellV a new tnel@AY ellVFsetfkground@golorFheuqeAY ellVFsetreferredize@new himension@THD RHAAY GGve onteneur prinipl tnel ontent a new tnel@AY ontentFsetreferredize@new himension@QHHD IPHAAY ontentFsetfkground@golorFrsiAY GGyn dfinit le lyout mnger ontentFsetvyout@new qridfgvyout@AAY GGv9ojet servnt positionner les omposnts qridfggonstrints g a new qridfggonstrints@AY

282

POSITIONNER SON COMPOSANT : LES LAYOUT MANAGERS


GGyn positionne l se de dprt du omposnt gFgridx a HY gFgridy a HY GGv tille en huteur et en lrgeur gFgridheight a IY gFgridwidth a IY ontentFdd@ellID gAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE gFgridx a IY ontentFdd@ellPD gAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE gFgridx a PY ontentFdd@ellQD gAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGgette instrution informe le lyout que 9est une fin de ligne gFgridwidth a qridfggonstrintsFiwesxhiY gFgridx a QY ontentFdd@ellRD gAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE gFgridx a HY gFgridy a IY gFgridwidth a IY gFgridheight a PY GGgelleEi indique que l ellule se rplique de fon vertile gFfill a qridfggonstrintsFisgevY ontentFdd@ellSD gAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE gFgridx a IY gFgridheight a IY GGgelleEi indique que l ellule se rplique de fon horizontle gFfill a qridfggonstrintsFrysyxevY gFgridwidth a qridfggonstrintsFiwesxhiY ontentFdd@ellTD gAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE gFgridx a IY gFgridy a PY gFgridwidth a PY ontentFdd@ellUD gAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE gFgridx a QY gFgridwidth a qridfggonstrintsFiwesxhiY ontentFdd@ellVD gAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGyn joute le onteneur thisFsetgontentne@ontentAY thisFsetisile@trueAY

283

CHAPITRE 22. POSITIONNER DES BOUTONS Copier ce code Code web : 513658  Vous pouvez vous rendre compte que c'est via l'objet GridBagConstraints que tout se joue. Vous pouvez utiliser ses dirents arguments an de positionner vos composants, en voici une liste.  gridx : position en x dans la grille.  gridy : position en y dans la grille.  gridwidth : nombre de colonnes occupes.  gridheight : nombre de lignes occupes.  weightx : si la grille est plus large que l'espace demand, l'espace est redistribu proportionnellement aux valeurs de weightx des direntes colonnes.  weighty : si la grille est plus haute que l'espace demand, l'espace est redistribu proportionnellement aux valeurs de weighty des direntes lignes.  anchor : ancrage du composant dans la cellule, c'est--dire son alignement dans la cellule 4 . Voici les direntes valeurs utilisables :  FIRST_LINE_START : en haut gauche ;  PAGE_START : en haut au centre ;  FIRST_LINE_END : en haut droite ;  LINE_START : au milieu gauche ;  CENTER : au milieu et centr ;  LINE_END : au milieu droite ;  LAST_LINE_START : en bas gauche ;  PAGE_END : en bas au centre ;  LAST_LINE_END : en bas droite.  fill : remplissage si la cellule est plus grande que le composant. Valeurs possibles : NONE, HORIZONTAL, VERTICAL et BOTH.  insets : espace autour du composant. S'ajoute aux espacements dnis par les proprits ipadx et ipady ci-dessous.  ipadx : espacement gauche et droite du composant.  ipady : espacement au-dessus et au-dessous du composant. Dans mon exemple, je ne vous ai pas parl de tous les attributs existants, mais si vous avez besoin d'un complment d'information, n'hsitez pas consulter le site d'Oracle.


L'objet FlowLayout
Celui-ci est certainement le plus facile utiliser ! Il se contente de centrer les composants dans le conteneur. Regardez plutt la gure 22.12. On dirait bien que nous venons de trouver le layout manager dni par dfaut dans les objets JPanel. Lorsque vous insrez plusieurs composants dans ce gestionnaire, il passe la ligne suivante ds que la place est trop troite. Voyez l'exemple de la gure 22.13. Il faut que vous sachiez que les IHM ne sont en fait qu'une imbrication de composants
4. En bas droite, en haut gauche. . .

284

POSITIONNER SON COMPOSANT : LES LAYOUT MANAGERS

Figure

22.12  Exemple de FlowLayout

Figure

22.13  FlowLayout contenant plusieurs composants

285

CHAPITRE 22. POSITIONNER DES BOUTONS positionns grce des layout managers. Vous allez tout de suite voir de quoi je veux parler : nous allons maintenant utiliser notre conteneur personnalis avec un bouton. Vous pouvez donc revenir dans le projet contenant notre animation cre au cours des chapitres prcdents. Le but est d'insrer notre animation au centre de notre fentre et un bouton en bas de celle-ci, comme le montre la gure 22.14.

Figure

22.14  Bouton et animation dans la mme fentre

Voici le nouveau code de notre classe Fenetre :


import jvFwtFfordervyoutY import jvFwtFgolorY import jvxFswingFtfuttonY import jvxFswingFtprmeY import jvxFswingFtnelY puli lss penetre extends tprme{ privte nneu pn a new nneu@AY privte tfutton outon a new tfutton@4mon outon4AY privte tnel ontiner a new tnel@AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY ontinerFdd@outonD fordervyoutFyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY go@AY }

286

POSITIONNER SON COMPOSANT : LES LAYOUT MANAGERS


privte void go@A{ GGves oordonnes de dprt de notre rond int x a pnFgetos@AD y a pnFgetos@AY GGve oolen pour svoir si l9on reule ou non sur l9xe x oolen k a flseY GGve oolen pour svoir si l9on reule ou non sur l9xe y oolen k a flseY GGhns et exempleD j9utilise une oule while GGous verrez qu9elle fontionne trs ien while@trueA{ GGi l oordonne x est infrieure ID on vne if@x ` IAk a flseY GGi l oordonne x est suprieure l tille du nneu GGmoins l tille du rondD on reule if@x b pnFgetidth@AESHAk a trueY GGsdem pour l9xe y if@y ` IAk a flseY if@y b pnFgetreight@AESHAk a trueY GGi on vneD on inrmente l oordonne if@3kA pnFsetos@CCxAY GGinonD on drmente else pnFsetos@EExAY GGsdem pour l9xe if@3kA pnFsetos@CCyAY else pnFsetos@EEyAY GGyn redessine notre nneu pnFrepint@AY GGgomme on dit X l puse s9impose 3 siD trois millimes de seonde try { hredFsleep@QAY } th @snterruptedixeption eA { eFprinttkre@AY }

Copier ce code Code web : 735876 

287

CHAPITRE 22. POSITIONNER DES BOUTONS

En rsum
 Un bouton s'utilise avec la classe JButton prsente dans le package javax.swing.  Pour ajouter un bouton dans une fentre, vous devez utiliser la mthode add() de son content pane.  Il existe des objets permettant de positionner les composants sur un content pane ou un conteneur : les layout managers.  Les layout managers se trouvent dans le package java.awt.  Le layout manager par dfaut du content pane d'un objet JFrame est le BorderLayout.  Le layout manager par dfaut d'un objet JPanel est le FlowLayout.  Outre le FlowLayout et le BorderLayout, il existe le GridLayout, le CardLayout, le BoxLayout et le GridBagLayout. La liste n'est pas exhaustive.  On dnit un layout sur un conteneur grce la mthode setLayout().

288

Chapitre

23
Dicult :

Interagir avec des boutons

ous avons vu dans le chapitre prcdent les direntes faons de positionner des boutons et, par extension, des composants (car oui, ce que nous venons d'apprendre pourra tre rutilis avec tous les autres composants que nous verrons par la suite). Maintenant que vous savez positionner des composants, il est grand temps de leur indiquer ce qu'ils doivent faire. C'est ce que je vous propose d'aborder dans ce chapitre. Mais avant cela, nous allons voir comment personnaliser un bouton. Toujours prts ?

289

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS

Une classe Bouton personnalise


Crons une classe hritant de javax.swing.JButton que nous appellerons Bouton et rednissons sa mthode paintComponent(). Vous devriez y arriver tout seuls. Cet exemple est reprsent la gure 23.1 :

Figure

23.1  Bouton personnalis

Voici la classe Bouton de cette application :


import import import import import import jvFwtFgolorY jvFwtFpontY jvFwtFpontwetrisY jvFwtFqrdientintY jvFwtFqrphisY jvFwtFqrphisPhY

import jvxFswingFtfuttonY puli lss fouton extends tfutton { privte tring nmeY puli fouton@tring strA{ super@strAY thisFnme a strY } puli void pintgomponent@qrphis gA{ qrphisPh gPd a @qrphisPhAgY qrdientint gp a new qrdientint@HD HD golorFlueD HD PHD golorFynD trueAY gPdFsetint@gpAY gPdFfillet@HD HD thisFgetidth@AD thisFgetreight@AAY gPdFsetgolor@golorFwhiteAY gPdFdrwtring@thisFnmeD

290

UNE CLASSE BOUTON PERSONNALISE


thisFgetidth@A G P E @thisFgetidth@AG P GRAD @thisFgetreight@A G PA C SAY

J'ai aussi cr un bouton personnalis avec une image de fond (gure 23.2).

Figure

23.2  Image de fond du bouton

Voyez le rsultat en gure 23.3.

Figure

23.3  Bouton avec une image de fond

J'ai appliqu l'image 1 sur l'intgralit du fond, comme je l'ai montr lorsque nous nous amusions avec notre Panneau. Voici le code de cette classe Bouton :
import import import import import import import import import import import jvFwtFgolorY jvFwtFqrdientintY jvFwtFqrphisY jvFwtFqrphisPhY jvFwtFsmgeY jvFwtFeventFwouseiventY jvFwtFeventFwousevistenerY jvFioFpileY jvFioFsyixeptionY jvxFimgeioFsmgesyY jvxFswingFtfuttonY

puli lss fouton extends tfutton{ privte tring nmeY privte smge imgY

1. Bien sr, ladite image se trouve la racine de mon projet !

291

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS

puli fouton@tring strA{ super@strAY thisFnme a strY try { img a smgesyFred@new pile@4fondfoutonFpng4AAY } th @syixeption eA { eFprinttkre@AY } } puli void pintgomponent@qrphis gA{ qrphisPh gPd a @qrphisPhAgY qrdientint gp a new qrdientint@HD HD golorFlueD HD PHD golorFynD trueAY gPdFsetint@gpAY gPdFdrwsmge@imgD HD HD thisFgetidth@AD thisFgetreight@AD thisAY gPdFsetgolor@golorFlkAY gPdFdrwtring@thisFnmeD thisFgetidth@A G P E @thisFgetidth@A G P GRAD @thisFgetreight@A G PA C SAY }

Rien de compliqu jusque-l. . . C'est partir de maintenant que les choses deviennent intressantes ! Et si je vous proposais de changer l'aspect de votre objet lorsque vous cliquez dessus avec votre souris et lorsque vous relchez le clic ? Il existe des interfaces implmenter qui permettent de grer toutes sortes d'vnements dans votre IHM. Le principe est un peu droutant au premier abord, mais il est assez simple lorsqu'on a un peu pratiqu. N'attendons plus et voyons cela de plus prs !

Interactions avec la souris : l'interface

MouseListener

Avant de nous lancer dans l'implmentation, vous pouvez voir le rsultat que nous allons obtenir sur les gures 23.4 et 23.5. Il va tout de mme falloir passer par un peu de thorie avant d'arriver ce rsultat. Pour dtecter les vnements qui surviennent sur votre composant, Java utilise ce qu'on appelle le design pattern observer. Je ne vous l'expliquerai pas dans le dtail tout de suite, nous le verrons la n de ce chapitre. Vous vous en doutez, nous devrons implmenter l'interface MouseListener dans notre classe Bouton. Nous devrons aussi prciser notre classe qu'elle devra tenir quelqu'un au courant de ses changements d'tat par rapport la souris. Ce quelqu'un n'est autre. . . qu'elle-mme ! Eh oui : notre classe va s'couter, ce qui signie que ds que notre objet observable (notre bouton) obtiendra des informations concernant les actions eectues par la souris, il indiquera l'objet qui l'observe (c'est--dire lui-mme) ce 292

UNE CLASSE BOUTON PERSONNALISE

Figure

23.4  Apparence du bouton au survol de la souris

Figure

23.5  Apparence du bouton lors d'un clic de souris

293

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS qu'il doit eectuer. Cela est ralisable grce la mthode addMouseListener(MouseListener obj) qui prend un objet MouseListener en paramtre (ici, elle prendra this). Rappelez-vous que vous pouvez utiliser le type d'une interface comme supertype : ici, notre classe implmente l'interface MouseListener, nous pouvons donc utiliser cet objet comme rfrence de cette interface. Voici prsent notre classe Bouton :
import import import import import import import import import import import jvFwtFgolorY jvFwtFqrdientintY jvFwtFqrphisY jvFwtFqrphisPhY jvFwtFsmgeY jvFwtFeventFwouseiventY jvFwtFeventFwousevistenerY jvFioFpileY jvFioFsyixeptionY jvxFimgeioFsmgesyY jvxFswingFtfuttonY

puli lss fouton extends tfutton implements wousevistener{ privte tring nmeY privte smge imgY puli fouton@tring strA{ super@strAY thisFnme a strY try { img a smgesyFred@new pile@4fondfoutonFpng4AAY } th @syixeption eA { eFprinttkre@AY } GGqre ette instrutionD notre ojet v s9outer GGhs qu9un vnement de l souris ser intereptD GGil en ser verti thisFddwousevistener@thisAY } puli void pintgomponent@qrphis gA{ qrphisPh gPd a @qrphisPhAgY qrdientint gp a new qrdientint@HD HD golorFlueD HD PHD golorFynD trueAY gPdFsetint@gpAY gPdFdrwsmge@imgD HD HD thisFgetidth@AD thisFgetreight@AD thisAY gPdFsetgolor@golorFlkAY gPdFdrwtring@thisFnmeD thisFgetidth@A G P E @thisFgetidth@A G P GRAD @thisFgetreight@A G PA C SAY }

294

UNE CLASSE BOUTON PERSONNALISE


GGwthode ppele lors du li de souris puli void mousegliked@wouseivent eventA { } GGwthode ppele lors du survol de l souris puli void mouseintered@wouseivent eventA { } GGwthode ppele lorsque l souris sort de l zone du outon puli void mouseixited@wouseivent eventA { } GGwthode ppele lorsque l9on presse le outon guhe de l souris puli void mouseressed@wouseivent eventA { } GGwthode ppele lorsque l9on relhe le li de souris puli void mouseelesed@wouseivent eventA { }

C'est en rednissant ces direntes mthodes prsentes dans l'interface MouseListener que nous allons grer les direntes images dessiner dans notre objet. Rappelez-vous en outre que mme si vous n'utilisez pas toutes les mthodes d'une interface, vous devez malgr tout insrer le squelette des mthodes non utilises (avec les accolades), cela tant galement valable pour les classes abstraites.

Dans notre cas, la mthode repaint() est appele de faon implicite : lorsqu'un vnement est dclench, notre objet se redessine automatiquement ! Comme lorsque vous redimensionniez votre fentre dans les premiers chapitres.
Nous n'avons alors plus qu' modier notre image en fonction de la mthode invoque. Notre objet comportera les caractristiques suivantes :  il aura une teinte jaune au survol de la souris ;  il aura une teinte orange lorsque l'on pressera le bouton gauche ;  il reviendra la normale si on relche le clic. Pour ce faire, voici les chiers PNG dont je me suis servi 2 . Tlcharger les images Code web : 920059 


Je vous rappelle que dans le code qui suit, les images sont places la racine du projet.
Voici maintenant le code de notre classe Bouton personnalise :
import jvFwtFgolorY import jvFwtFqrdientintY

2. Rien ne vous empche de les crer vous-mmes.

295

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


import import import import import import import import import jvFwtFqrphisY jvFwtFqrphisPhY jvFwtFsmgeY jvFwtFeventFwouseiventY jvFwtFeventFwousevistenerY jvFioFpileY jvFioFsyixeptionY jvxFimgeioFsmgesyY jvxFswingFtfuttonY

puli lss fouton extends tfutton implements wousevistener{ privte tring nmeY privte smge imgY puli fouton@tring strA{ super@strAY thisFnme a strY try { img a smgesyFred@new pile@4fondfoutonFpng4AAY } th @syixeption eA { eFprinttkre@AY } thisFddwousevistener@thisAY } puli void pintgomponent@qrphis gA{ qrphisPh gPd a @qrphisPhAgY qrdientint gp a new qrdientint@HD HD golorFlueD HD PHD golorFynD trueAY gPdFsetint@gpAY gPdFdrwsmge@imgD HD HD thisFgetidth@AD thisFgetreight@AD thisAY gPdFsetgolor@golorFlkAY gPdFdrwtring@thisFnmeD thisFgetidth@A G P E @thisFgetidth@A G P GRAD @thisFgetreight@A G PA C SAY } puli void mousegliked@wouseivent eventA { GGsnutile d9utiliser ette mthode ii } puli void mouseintered@wouseivent eventA { GGxous hngeons le fond de notre imge pour le june GGlors du survolD ve le fihier fondfoutonroverFpng try { img a smgesyFred@new pile@4fondfoutonroverFpng4AAY } th @syixeption eA { eFprinttkre@AY }

296

UNE CLASSE BOUTON PERSONNALISE

puli void mouseixited@wouseivent eventA { GGxous hngeons le fond de notre imge pour le vert GGlorsque nous quittons le outonD ve le fihier fondfoutonFpng try { img a smgesyFred@new pile@4fondfoutonFpng4AAY } th @syixeption eA { eFprinttkre@AY }

puli void mouseressed@wouseivent eventA { GGxous hngeons le fond de notre imge pour le june GGlors du li guheD ve le fihier fondfoutongliFpng try { img a smgesyFred@new pile@4fondfoutongliFpng4AAY } th @syixeption eA { eFprinttkre@AY } } puli void mouseelesed@wouseivent eventA { GGxous hngeons le fond de notre imge pour le ornge GGlorsque nous relhons le liD ve le fihier fondfoutonroverFpng try { img a smgesyFred@new pile@4fondfoutonroverFpng4AAY } th @syixeption eA { eFprinttkre@AY } }

Copier ce code Code web : 111582  Et voil le travail ! Si vous avez enregistr mes images, elles ne possdent probablement pas le mme nom que dans mon code : vous devez alors modier le code en fonction de celui que vous leur avez attribu ! D'accord, a va de soi. . . mais on ne sait jamais. Vous possdez dornavant un bouton personnalis qui ragit au passage de votre souris. Je sais qu'il y aura des  p'tits malins  qui cliqueront sur le bouton et relcheront le clic en dehors du bouton : dans ce cas, le fond du bouton deviendra orange, puisque c'est ce qui doit tre eectu vu la mthode mouseReleased(). An de pallier ce problme, nous allons vrier que lorsque le clic est relch, la souris se trouve toujours sur le bouton. Nous avons implment l'interface MouseListener ; il reste cependant un objet que nous n'avons pas encore utilis. . . Vous ne le voyez pas ? C'est le paramtre prsent dans toutes les mthodes de cette interface : oui, c'est MouseEvent ! Cet objet nous permet d'obtenir beaucoup d'informations sur les vnements. Nous ne 297

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS dtaillerons pas tout ici, mais nous verrons certains cts pratiques de ce type d'objet tout au long de cette partie. Dans notre cas, nous pouvons rcuprer les coordonnes x et y du curseur de la souris par rapport au Bouton grce aux mthodes getX() et getY(). Cela signie que si nous relchons le clic en dehors de la zone o se trouve notre objet, la valeur retourne par la mthode getY() sera ngative. Voici le correctif de la mthode mouseReleased() de notre classe Bouton :
puli void mouseelesed@wouseivent eventA { GGxous hngeons le fond de notre imge pour le ornge GGlorsque nous relhons le li GGve le fihier fondfoutonroverFpng GGsi l souris est toujours sur le outon if@@eventFget@A b H 88 eventFget@A ` outonFgetreight@AA 88 @eventFget@A b H 88 eventFget@A ` outonFgetidth@AAA{ try { img a smgesyFred@new pile@4fondfoutonroverFpng4AAY } th @syixeption eA { eFprinttkre@AY } } GGi on se trouve l9extrieurD on dessine le fond pr dfut else{ try { img a smgesyFred@new pile@4fondfoutonFpng4AAY } th @syixeption eA { eFprinttkre@AY } } }

Vous verrez dans les chapitres qui suivent qu'il existe plusieurs interfaces pour les direntes actions possibles sur une IHM. Sachez qu'il existe aussi une convention pour ces interfaces : leur nom commence par le type de l'action, suivi du mot Listener. Nous avons tudi ici les actions de la souris, voyez le nom de l'interface : MouseListener.
Nous possdons prsent un bouton ractif, mais qui n'eectue rien pour le moment. Je vous propose de combler cette lacune.

Interagir avec son bouton


Dclencher une action : l'interface
ActionListener
An de grer les direntes actions eectuer selon le bouton sur lequel on clique, nous allons utiliser l'interface ActionListener. 298

INTERAGIR AVEC SON BOUTON Nous n'allons pas implmenter cette interface dans notre classe Bouton mais dans notre classe Fenetre, le but tant de faire en sorte que lorsque l'on clique sur le bouton, il se passe quelque chose dans notre application : changer un tat, une variable, eectuer une incrmentation. . . Enn, n'importe quelle action ! Comme je vous l'ai expliqu, lorsque nous appliquons un addMouseListener(), nous informons l'objet observ qu'un autre objet doit tre tenu au courant de l'vnement. Ici, nous voulons que ce soit notre application (notre Fenetre) qui coute notre Bouton, le but tant de pouvoir lancer ou arrter l'animation dans le Panneau. Avant d'en arriver l, nous allons faire plus simple : nous nous pencherons dans un premier temps sur l'implmentation de l'interface ActionListener. An de vous montrer toute la puissance de cette interface, nous utiliserons un nouvel objet issu du package javax.swing : le JLabel. Cet objet se comporte comme un libell : il est spcialis dans l'achage de texte ou d'image. Il est donc idal pour notre premier exemple ! On l'instancie et l'initialise plus ou moins de la mme manire que le JButton :
tvel lelI a new tvel@AY lelIFsetext@4won premier tvel4AY GGyu enore tvel lelP a new tvel@4won deuxime tvel4AY

Crez une variable d'instance de type JLabel  appelez-la label  et initialisezla avec le texte qui vous plat ; ajoutez-la ensuite votre content pane en position BorderLayout.NORTH. Le rsultat se trouve en gure 23.6.

Figure

23.6  Utilisation d'un JLabel

Voici le code correspondant :


puli lss penetre extends tprme { privte nneu pn a new nneu@AY privte fouton outon a new fouton@4mon outon4AY

299

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


privte tnel ontiner a new tnel@AY privte tvel lel a new tvel@4ve tvel4AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY ontinerFdd@outonD fordervyoutFyrAY ontinerFdd@lelD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY go@AY GGve reste ne hnge ps

} }

Vous pouvez voir que le texte de cet objet est align par dfaut en haut gauche. Il est possible de modier quelques paramtres tels que :  l'alignement du texte ;  la police utiliser ;  la couleur du texte ;  d'autres paramtres. Voici un code mettant tout cela en pratique :
puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY ontinerFdd@outonD fordervyoutFyrAY GGhfinition d9une polie d9riture pont polie a new pont@4hom4D pontFfyvhD ITAY GGyn l9pplique u tvel lelFsetpont@polieAY GGghngement de l ouleur du texte lelFsetporeground@golorFlueAY GGyn modifie l9lignement du texte gre ux ttriuts sttiques GGde l lsse tvel

300

INTERAGIR AVEC SON BOUTON


lelFsetrorizontlelignment@tvelFgixiAY ontinerFdd@lelD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY go@AY

La gure 23.7 donne un aperu de ce code.

Figure

23.7  Utilisation plus ne d'un JLabel

Maintenant que notre libell se prsente exactement sous la forme que nous voulons, nous pouvons implmenter l'interface ActionListener. Vous remarquerez que cette interface ne contient qu'une seule mthode !
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme implements etionvistener{ privte nneu pn a new nneu@AY privte fouton outon a new fouton@4mon outon4AY privte tnel ontiner a new tnel@AY privte tvel lel a new tvel@4ve tvel4AY puli penetre@A{ GGge moreu de ode ne hnge ps } GGwthode qui ser ppele lors d9un li sur le outon puli void tionerformed@etionivent rgHA { } }

Nous allons maintenant informer notre objet Bouton que notre objet Fenetre l'coute. Vous l'avez devin : ajoutons notre Fenetre la liste des objets qui coutent notre 301

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


Bouton grce la mthode addActionListener(ActionListener obj) prsente dans la classe JButton, donc utilisable avec la variable bouton. Ajoutons cette instruction dans le constructeur en passant this en paramtre (puisque c'est notre Fenetre qui coute le Bouton).

Une fois l'opration eectue, nous pouvons modier le texte du JLabel avec la mthode actionPerformed(). Nous allons compter le nombre de fois que l'on a cliqu sur le bouton : ajoutons une variable d'instance de type int dans notre class et appelonsla compteur, puis dans la mthode actionPerformed(), incrmentons ce compteur et achons son contenu dans notre libell. Voici le code de notre objet mis jour :
import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFpontY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme implements etionvistener{ privte nneu pn a new nneu@AY privte fouton outon a new fouton@4mon outon4AY privte tnel ontiner a new tnel@AY privte tvel lel a new tvel@4ve tvel4AY GGgompteur de lis privte int ompteur a HY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY GGxous joutons notre fentre l liste des uditeurs de notre outon outonFddetionvistener@thisAY ontinerFdd@outonD fordervyoutFyrAY pont polie a new pont@4hom4D pontFfyvhD ITAY lelFsetpont@polieAY lelFsetporeground@golorFlueAY lelFsetrorizontlelignment@tvelFgixiAY ontinerFdd@lelD fordervyoutFxyrAY thisFsetgontentne@ontinerAY

302

INTERAGIR AVEC SON BOUTON


thisFsetisile@trueAY go@AY

privte void go@A{ GGgette mthode ne hnge ps } puli void tionerformed@etionivent rgHA { GGvorsque l9on lique sur le outonD on met jour le tvel thisFompteurCCY lelFsetext@4ous vez liqu 4 C thisFompteur C 4 fois4AY

Voyez le rsultat la gure 23.8.

Figure

23.8  Interaction avec le bouton

Et nous ne faisons que commencer. . . Eh oui, nous allons maintenant ajouter un deuxime bouton notre Fenetre, ct du premier 3 . Pour ma part, j'utiliserai des boutons normaux ; en eet, dans notre classe personnalise, la faon dont le libell est crit dans notre bouton n'est pas assez souple et l'achage peut donc tre dcevant 4 . . . Bref, nous possdons prsent deux boutons couts par notre objet Fenetre.

Vous devez crer un deuxime JPanel qui contiendra nos deux boutons, puis l'insrer dans le content pane en position BorderLayout.SOUTH. Si vous tentez de positionner deux composants au mme endroit grce un BorderLayout, seul le dernier composant ajout apparatra : en eet, le composant occupe toute la place disponible dans un BorderLayout !
Voici notre nouveau code :
3. Vous tes libres d'utiliser la classe personnalise ou un simple JButton. 4. Dans certains cas, le libell peut ne pas tre centr.

303

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


import import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFpontY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme implements etionvistener{ privte nneu pn a new nneu@AY privte tfutton outon a new tfutton@4outon I4AY privte tfutton outonP a new tfutton@4outon P4AY privte tnel ontiner a new tnel@AY privte tvel lel a new tvel@4ve tvel4AY privte int ompteur a HY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY outonFddetionvistener@thisAY outonPFddetionvistener@thisAY tnel south a new tnel@AY southFdd@outonAY southFdd@outonPAY ontinerFdd@southD fordervyoutFyrAY pont polie a new pont@4hom4D pontFfyvhD ITAY lelFsetpont@polieAY lelFsetporeground@golorFlueAY lelFsetrorizontlelignment@tvelFgixiAY ontinerFdd@lelD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY go@AY

} }

GGFFF

La gure 23.9 illustre le rsultat que nous obtenons. 304

INTERAGIR AVEC SON BOUTON

Figure

23.9  Un deuxime bouton dans la fentre

prsent, le problme est le suivant : comment eectuer deux actions direntes dans la mthode actionPerformed() ? En eet, si nous laissons la mthode actionPerformed() telle quelle, les deux boutons excutent la mme action lorsqu'on les clique. Essayez, vous verrez le rsultat. Il existe un moyen de connatre l'lment ayant dclench l'vnement : il faut se servir de l'objet pass en paramtre dans la mthode actionPerformed(). Nous pouvons exploiter la mthode getSource() de cet objet pour connatre le nom de l'instance qui a gnr l'vnement. Testez la mthode actionPerformed() suivante et voyez si le rsultat correspond la gure 23.10.
puli void tionerformed@etionivent rgHA { if@rgHFgetoure@A aa outonA lelFsetext@4ous vez liqu sur le outon I4AY if@rgHFgetoure@A aa outonPA lelFsetext@4ous vez liqu sur le outon P4AY

Notre code fonctionne merveille ! Cependant, cette approche n'est pas trs oriente objet : si notre IHM contient une multitude de boutons, la mthode actionPerformed() sera trs charge. Nous pourrions crer deux objets part, chacun coutant un bouton, dont le rle serait de ragir de faon approprie pour chaque bouton ; mais si nous avions besoin de modier des donnes spciques la classe contenant nos boutons, il faudrait ruser an de parvenir faire communiquer nos objets. . . Pas terrible non plus.

Parler avec sa classe intrieure


En Java, on peut crer ce que l'on appelle des classes internes. Cela consiste dclarer une classe l'intrieur d'une autre classe. Je sais, a peut paratre tordu, mais vous allez bientt constater que c'est trs pratique. 305

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS

Figure

23.10  Dtection de la source de l'vnement

En eet, les classes internes possdent tous les avantages des classes normales, de l'hritage d'une superclasse l'implmentation d'une interface. Elles bncient donc du polymorphisme et de la covariance des variables. En outre, elles ont l'avantage d'avoir accs aux attributs de la classe dans laquelle elles sont dclares ! Dans le cas qui nous intresse, cela permet de crer une implmentation de l'interface ActionListener dtache de notre classe Fenetre, mais pouvant utiliser ses attributs. La dclaration d'une telle classe se fait exactement de la mme manire que pour une classe normale, si ce n'est qu'elle se trouve dj dans une autre classe. Nous procdons donc comme ceci :
puli lss wglsseixterne{ puli wglsseixterne@A{ GGFFF } lss wglsssnterne{ puli wglsssnterne@A{ GGFFF } }

Grce cela, nous pourrons concevoir une classe spcialise dans l'coute des composants et qui eectuera un travail bien dtermin. Dans notre exemple, nous crerons deux classes internes implmentant chacune l'interface ActionListener et rednissant la mthode actionPerformed() :  BoutonListener coutera le premier bouton ;  Bouton2Listener coutera le second. Une fois ces oprations eectues, il ne nous reste plus qu' indiquer chaque bouton  qui l'coute  grce la mthode addActionListener(). 306

INTERAGIR AVEC SON BOUTON Voyez ci-dessous la classe Fenetre mise jour.
import import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFpontY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme{ privte privte privte privte privte privte nneu pn a new nneu@AY tfutton outon a new tfutton@4outon I4AY tfutton outonP a new tfutton@4outon P4AY tnel ontiner a new tnel@AY tvel lel a new tvel@4ve tvel4AY int ompteur a HY

puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY GGge sont mintennt nos lsses internes qui outent nos outons outonFddetionvistener@new foutonvistener@AAY outonPFddetionvistener@new foutonPvistener@AAY tnel south a new tnel@AY southFdd@outonAY southFdd@outonPAY ontinerFdd@southD fordervyoutFyrAY pont polie a new pont@4hom4D pontFfyvhD ITAY lelFsetpont@polieAY lelFsetporeground@golorFlueAY lelFsetrorizontlelignment@tvelFgixiAY ontinerFdd@lelD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY go@AY

privte void go@A{

307

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


GGgette mthode ne hnge ps

GGglsse outnt notre premier outon lss foutonvistener implements etionvistener{ GGedfinition de l mthode tionerformed@A puli void tionerformed@etionivent rgHA { lelFsetext@4ous vez liqu sur le outon I4AY } } GGglsse outnt notre seond outon lss foutonPvistener implements etionvistener{ GGedfinition de l mthode tionerformed@A puli void tionerformed@etionivent eA { lelFsetext@4ous vez liqu sur le outon P4AY } }

Le rsultat, consultable la gure 23.11, est parfait.

Figure

23.11  Utilisation de deux actions sur deux boutons

Vous pouvez constater que nos classes internes ont mme accs aux attributs dclars private dans notre classe Fenetre.
Dornavant, nous n'avons plus nous soucier du bouton qui a dclench l'vnement, car nous disposons de deux classes coutant chacune un bouton. Nous pouvons souer un peu : une grosse pine vient de nous tre retire du pied.

Vous pouvez aussi faire couter votre bouton par plusieurs classes. Il vous sut d'ajouter ces classes supplmentaires l'aide d' addActionListener().
308

INTERAGIR AVEC SON BOUTON

Eh oui, faites le test : crez une troisime classe interne et attribuez-lui le nom que vous voulez (personnellement, je l'ai appele Bouton3Listener). Implmentez-y l'interface ActionListener et contentez-vous d'eectuer un simple System.out.println() dans la mthode actionPerformed(). N'oubliez pas de l'ajouter la liste des classes qui coutent votre bouton (n'importe lequel des deux ; j'ai pour ma part choisi le premier). Je vous cris uniquement le code ajout :
GGves importsFFF puli lss penetre extends tprme{ GGves vriles d9instneFFF puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY GGremire lsse outnt mon premier outon outonFddetionvistener@new foutonvistener@AAY GGheuxime lsse outnt mon premier outon outonFddetionvistener@new foutonQvistener@AAY outonPFddetionvistener@new foutonPvistener@AAY tnel south a new tnel@AY southFdd@outonAY southFdd@outonPAY ontinerFdd@southD fordervyoutFyrAY pont polie a new pont@4hom4D pontFfyvhD ITAY lelFsetpont@polieAY lelFsetporeground@golorFlueAY lelFsetrorizontlelignment@tvelFgixiAY ontinerFdd@lelD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY go@AY

GGFFF lss foutonQvistener implements etionvistener{

309

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


GGedfinition de l mthode tionerformed@A puli void tionerformed@etionivent eA { ystemFoutFprintln@4w lsse interne numro Q oute ien 34AY }

Le rsultat se trouve sur la gure 23.12.

Figure

23.12  Deux couteurs sur un bouton

Les classes internes sont vraiment des classes part entire. Elles peuvent galement hriter d'une superclasse. De ce fait, c'est presque comme si nous nous trouvions dans le cas d'un hritage multiple (ce n'en est pas un, mme si cela y ressemble). Ce code est donc valide :
puli lss wglsseixterne extends tprme{ puli wglsseixterne@A{ GGFFF } lss wglsssnterne extends tnel{ puli wglsssnterne@A{ GGFFF } } lss wglsssnterneP extends tfutton{ puli wglsssnterne@A{ GGFFF } }

310

INTERAGIR AVEC SON BOUTON Vous voyez bien que ce genre de classes peut s'avrer trs utile. Bon, nous avons rgl le problme d'implmentation : nous possdons deux boutons qui sont couts. Il ne nous reste plus qu' lancer et arrter notre animation l'aide de ces boutons. Mais auparavant, nous allons tudier une autre manire d'implmenter des couteurs et, par extension, des classes devant rednir les mthodes d'une classe abstraite ou d'une interface.

Les classes anonymes


Il n'y a rien de compliqu dans cette faon de procder, mais je me rappelle avoir t dconcert lorsque je l'ai rencontre pour la premire fois. . . Les classes anonymes sont le plus souvent utilises pour la gestion d'vnements ponctuels, lorsque crer une classe pour un seul traitement est trop lourd. Rappelez-vous ce que j'ai utilis pour dnir le comportement de mes boutons lorsque je vous ai prsent l'objet CardLayout : c'taient des classes anonymes. Pour rappel, voici ce que je vous avais amens coder :
tfutton outon a new tfutton@4gontenu suivnt4AY GGhfinition de l9tion sur le outon outonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eventA{ GGetion 3 } }AY

L'une des particularits de cette mthode, c'est que l'couteur n'coutera que ce composant. Vous pouvez vrier qu'il n'y se trouve aucune dclaration de classe et que nous instancions une interface par l'instruction new ActionListener(). Nous devons seulement rednir la mthode, que vous connaissez bien maintenant, dans un bloc d'instructions ; d'o les accolades aprs l'instanciation, comme le montre la gure 23.13.

Figure

23.13  Dcoupage d'une classe anonyme

Pourquoi appelle-t-on cela une classe anonyme ?


311

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS C'est simple : procder de cette manire revient crer une classe lle sans tre oblig de crer cette classe de faon explicite. L'hritage se produit automatiquement. En fait, le code ci-dessus revient eectuer ceci :
lss penetre extends tprme{ GGFFF outonFddetionvistener@new etionvistenerfis@AAY GGFFF puli lss etionvistenerfis implements etionvistener{ puli void tionerformed@etionivent eventA{ GGetion 3 } }

Seulement, la classe cre n'a pas de nom, l'hritage s'eectue de faon implicite ! Nous bncions donc de tous les avantages de la classe mre en ne rednissant que la mthode qui nous intresse. Sachez aussi que les classes anonymes peuvent tre utilises pour implmenter des classes abstraites. Je vous conseille d'eectuer de nouveaux tests en utilisant notre exemple du pattern strategy ; mais cette fois, plutt que de crer des classes, crez des classes anonymes. Les classes anonymes sont soumises aux mmes rgles que les classes  normales  :  utilisation des mthodes non rednies de la classe mre ;  obligation de rednir toutes les mthodes d'une interface ;  obligation de rednir les mthodes abstraites d'une classe abstraite. Cependant, ces classes possdent des restrictions cause de leur rle et de leur raison d'tre :  elles ne peuvent pas tre dclares abstract ;  elles ne peuvent pas non plus tre dclares static ;  elles ne peuvent pas dnir de constructeur ;  elles sont automatiquement dclares final : on ne peut driver de cette classe, l'hritage est donc impossible !

Contrler son animation : lancement et arrt


Pour parvenir grer le lancement et l'arrt de notre animation, nous allons devoir modier un peu le code de notre classe Fenetre. Il va falloir changer le libell des boutons de notre IHM : le premier achera Go et le deuxime Stop. Pour viter d'interrompre l'animation alors qu'elle n'est pas lance et de l'animer quand elle l'est dj, nous allons tantt activer et dsactiver les boutons. Je m'explique :  au lancement, le bouton Go ne sera pas cliquable alors que le bouton Stop oui ;  si l'animation est interrompue, le bouton Stop ne sera plus cliquable, mais le bouton Go le sera. 312

INTERAGIR AVEC SON BOUTON Ne vous inquitez pas, c'est trs simple raliser. Il existe une mthode grant ces changements d'tat :
tfutton outon a new tfutton@4outon4AY outonFsetinled@flseAY GGve outon n9est plus liqule outonFsetinled@trueAY GGve outon est de nouveu liqule

Ces objets permettent de raliser pas mal de choses ; soyez curieux et testez-en les mthodes. Allez donc faire un tour sur le site d'Oracle : fouillez, fouinez. . . L'une de ces mthodes, qui s'avre souvent utile et est utilisable avec tous ces objets (ainsi qu'avec les objets que nous verrons par la suite), est la mthode de gestion de dimension. Il ne s'agit pas de la mthode setSize(), mais de la mthode setPreferredSize(). Elle prend en paramtre un objet Dimension, qui, lui, prend deux entiers comme arguments. Voici un exemple :
outonFsetreferredize@new himension@ISHD IPHAAY

En l'utilisant dans notre application, nous obtenons la gure 23.14.

Figure

23.14  Gestion de la taille de nos boutons

An de bien grer notre animation, nous devons amliorer notre mthode go(). Sortons donc de cette mthode les deux entiers dont nous nous servions an de recalculer les coordonnes de notre rond. La boucle innie doit dornavant pouvoir tre interrompue ! Pour russir cela, nous allons dclarer un boolen qui changera d'tat selon le bouton sur lequel on cliquera ; nous l'utiliserons comme paramtre de notre boucle. Voyez ci-dessous le code de notre classe Fenetre.


Copier le code Code web : 263161 

import jvFwtFfordervyoutY import jvFwtFgolorY

313

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


import import import import import import import jvFwtFpontY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme{ privte privte privte privte privte privte privte privte privte nneu pn a new nneu@AY tfutton outon a new tfutton@4qo4AY tfutton outonP a new tfutton@4top4AY tnel ontiner a new tnel@AY tvel lel a new tvel@4ve tvel4AY int ompteur a HY oolen nimted a trueY oolen kD kY int xD yY

puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY outonFddetionvistener@new foutonvistener@AAY outonFsetinled@flseAY outonPFddetionvistener@new foutonPvistener@AAY tnel south a new tnel@AY southFdd@outonAY southFdd@outonPAY ontinerFdd@southD fordervyoutFyrAY pont polie a new pont@4hom4D pontFfyvhD ITAY lelFsetpont@polieAY lelFsetporeground@golorFlueAY lelFsetrorizontlelignment@tvelFgixiAY ontinerFdd@lelD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY go@AY

privte void go@A{ GGves oordonnes de dprt de notre rond x a pnFgetos@AY

314

INTERAGIR AVEC SON BOUTON


y a pnFgetos@AY GGhns et exempleD j9utilise une oule while GGous verrez qu9elle fontionne trs ien while@thisFnimtedA{ if@x ` IAk a flseY if@x b pnFgetidth@AESHAk a trueY if@y ` IAk a flseY if@y b pnFgetreight@AESHAk a trueY if@3kApnFsetos@CCxAY else pnFsetos@EExAY if@3kA pnFsetos@CCyAY else pnFsetos@EEyAY pnFrepint@AY try { hredFsleep@QAY } th @snterruptedixeption eA { eFprinttkre@AY }

lss foutonvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { nimted a trueY outonFsetinled@flseAY outonPFsetinled@trueAY go@AY } } lss foutonPvistener implements etionvistener{ puli void tionerformed@etionivent eA { nimted a flseY outonFsetinled@trueAY outonPFsetinled@flseAY } }

l'excution, vous remarquez que :  le bouton Go n'est pas cliquable et l'autre l'est ;  l'animation se lance ;  l'animation s'arrte lorsque l'on clique sur le bouton Stop ;  le bouton Go devient alors cliquable ;  lorsque vous cliquez dessus, l'animation ne se relance pas ! 315

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS

Comment est-ce possible ?


Comme je l'ai expliqu dans le chapitre traitant des conteneurs, un thread est lanc au dmarrage de notre application : c'est le processus principal du programme . Au dmarrage, l'animation est donc lance dans le mme thread que notre objet Fenetre. Lorsque nous lui demandons de s'arrter, aucun problme : les ressources mmoire sont libres, on sort de la boucle innie et l'application continue fonctionner. Mais lorsque nous redemandons l'animation de se lancer, l'instruction se trouvant dans la mthode actionPerformed() appelle la mthode go() et, tant donn que nous nous trouvons l'intrieur d'une boucle innie, nous restons dans la mthode go() et ne sortons plus de la mthode actionPerformed().

Explication de ce phnomne
Java gre les appels aux mthodes grce ce que l'on appelle vulgairement la pile. Pour expliquer cela, prenons un exemple tout bte ; regardez cet objet :
puli lss estile { puli estile@A{ ystemFoutFprintln@4hut onstruteur4AY methodeI@AY ystemFoutFprintln@4pin onstruteur4AY } puli void methodeI@A{ ystemFoutFprintln@4hut mthode I4AY methodeP@AY ystemFoutFprintln@4pin mthode I4AY } puli void methodeP@A{ ystemFoutFprintln@4hut mthode P4AY methodeQ@AY ystemFoutFprintln@4pin mthode P4AY } puli void methodeQ@A{ ystemFoutFprintln@4hut mthode Q4AY ystemFoutFprintln@4pin mthode Q4AY }

Si vous instanciez cet objet, vous obtenez dans la console la gure 23.15. Je suppose que vous avez remarqu avec stupfaction que l'ordre des instructions est un peu bizarre. Voici ce qu'il se passe : 316

INTERAGIR AVEC SON BOUTON

Figure

23.15  Exemple de pile d'invocations

 l'instanciation, notre objet appelle la mthode 1 ;  cette dernire invoque la mthode 2 ;  celle-ci utilise la mthode 3 : une fois qu'elle a termin, la JVM retourne dans la mthode 2 ;  lorsqu'elle a ni de s'excuter, on remonte la n de la mthode 1, jusqu' la dernire instruction appelante : le constructeur.

Lors de tous les appels, on dit que la JVM empile les invocations sur la pile. Une fois que la dernire mthode empile a termin de s'excuter, la JVM la dpile.
La gure 23.16 prsente un schma rsumant la situation. Dans notre programme, imaginez que la mthode actionPerformed() soit reprsente par la mthode 2, et que notre mthode go() soit reprsente par la mthode 3. Lorsque nous entrons dans la mthode 3, nous entrons dans une boucle innie. . . Consquence directe : nous ne ressortons jamais de cette mthode et la JVM ne dpile plus ! An de pallier ce problme, nous allons utiliser un nouveau thread. Grce cela, la mthode go() se trouvera dans une pile part.

Attends : on arrive pourtant arrter l'animation alors qu'elle se trouve dans une boucle innie. Pourquoi ?
Tout simplement parce que nous ne demandons d'eectuer qu'une simple initialisation de variable dans la gestion de notre vnement ! Si vous crez une deuxime mthode comprenant une boucle innie et que vous l'invoquez lors du clic sur le bouton Stop, vous aurez exactement le mme problme. Je ne vais pas m'terniser l-dessus, nous verrons cela dans un prochain chapitre. prsent, je pense qu'il est de bon ton de vous parler du mcanisme d'coute d'vnements, le fameux pattern observer. 317

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS

Figure

23.16  Empilage et dpilage de mthodes

tre l'coute de ses objets : le design pattern Observer


Le design pattern Observer est utilis pour grer les vnements de vos IHM. C'est une technique de programmation. La connatre n'est pas absolument indispensable, mais cela vous aide mieux comprendre le fonctionnement de Swing et AWT. C'est par ce biais que vos composants eectueront quelque chose lorsque vous les cliquerez ou les survolerez. Je vous propose de dcouvrir son fonctionnement l'aide d'une situation problmatique.

Posons le problme
Sachant que vous tes des dveloppeurs Java chevronns, un de vos amis proches vous demande si vous tes en mesure de l'aider raliser une horloge digitale en Java. Il a en outre la gentillesse de vous fournir les classes utiliser pour la cration de son horloge. Votre ami a l'air de s'y connatre, car ce qu'il vous a fourni est bien structur.

Package com.sdz.vue, classe Fenetre.java


pkge omFsdzFvueY import jvFwtFfordervyoutY import jvFwtFpontY import jvxFswingFtprmeY

318

TRE L'COUTE DE SES OBJETS : LE DESIGN PATTERN OBSERVER


import jvxFswingFtvelY import omFsdzFmodelFrorlogeY puli lss penetre extends tprme{ privte tvel lel a new tvel@AY privte rorloge horlogeY puli penetre@A{ GGyn initilise l tprme thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY thisFsetesizle@flseAY thisFsetize@PHHD VHAY GGyn initilise l9horloge thisFhorloge a new rorloge@AY GGyn initilise le tvel pont polie a new pont@4hEdigitl4D pontFiIpyxD QHAY thisFlelFsetpont@polieAY thisFlelFsetrorizontlelignment@tvelFgixiAY GGyn joute le tvel l tprme thisFgetgontentne@AFdd@thisFlelD fordervyoutFgixiAY } GGwthode min@A lnnt le progrmme puli stti void min@tring rgsA{ penetre fen a new penetre@AY fenFsetisile@trueAY }

Package com.sdz.model, classe Horloge.java


pkge omFsdzFmodelY import jvFutilFglendrY puli lss rorloge{ GGyjet lendrier pour ruprer l9heure ournte privte glendr lY privte tring hour a 44Y puli void run@A { while@trueA{ GGyn rupre l9instne d9un lendrier hque tour GGille v nous permettre de ruprer l9heure tuelle thisFl a glendrFgetsnstne@AY thisFhour a GGves heures thisFlFget@glendrFryypheA C 4 X 4

319

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


C @

A C 4 X 4 C @ GGves seondes @thisFlFget@glendrFigyxhA` IHA c 4H4CthisFlFget@glendrFigyxhA X thisFlFget@glendrFigyxhA AY try { hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY }

GGves minutes thisFlFget@glendrFwsxiA ` IH c 4H4 C thisFlFget@glendrFwsxiA X thisFlFget@glendrFwsxiA

Si vous ne disposez pas de la police d'criture que j'ai utilise, utilisez-en une autre : Arial ou Courrier, par exemple.
Le problme auquel votre ami est confront est simple : il est impossible de faire communiquer l'horloge avec la fentre .

Je ne vois pas o est le problme : il n'a qu' passer son instance de JLabel dans son objet Horloge, et le tour est jou !
En ralit, votre ami, dans son innie sagesse, souhaite  je le cite  que l'horloge ne dpende pas de son interface graphique, juste au cas o il devrait passer d'une IHM swing une IHM awt. Il est vrai que si l'on passe l'objet d'achage dans l'horloge, dans le cas o l'on change le type de l'IHM, toutes les classes doivent tre modies ; ce n'est pas gnial. En fait, lorsque vous procdez de la sorte, on dit que vous couplez des objets : vous rendez un ou plusieurs objets dpendants d'un ou de plusieurs autres objets 5 . Le couplage entre objets est l'un des problmes principaux relatifs la rutilisation des objets. Dans notre cas, si vous utilisez l'objet Horloge dans une autre application, vous serez confronts plusieurs problmes tant donn que cet objet ne s'ache que dans un JLabel.
5. Entendez par l que vous ne pourrez plus utiliser les objets coupls indpendamment des objets auxquels ils sont attachs.

320

TRE L'COUTE DE SES OBJETS : LE DESIGN PATTERN OBSERVER C'est l que le pattern observer entre en jeu : il fait communiquer des objets entre eux sans qu'ils se connaissent rellement ! Vous devez tre curieux de voir comment il fonctionne, je vous propose donc de l'tudier sans plus tarder.

Des objets qui parlent et qui coutent : le pattern observer


Faisons le point sur ce que vous savez de ce pattern pour le moment :  il fait communiquer des objets entre eux ;  c'est un bon moyen d'viter le couplage d'objets. Ce sont deux points cruciaux, mais un autre lment, que vous ne connaissez pas encore, va vous plaire : tout se fait automatiquement ! Comment les choses vont-elles alors se passer ? Rchissons ce que nous voulons que notre horloge digitale eectue : elle doit pouvoir avertir l'objet servant acher l'heure lorsqu'il doit rafrachir son achage. Puisque les horloges du monde entier se mettent jour toutes les secondes, il n'y a aucune raison pour que la ntre ne fasse pas de mme. Ce qui est merveilleux avec ce pattern, c'est que notre horloge ne se contentera pas d'avertir un seul objet que sa valeur a chang : elle pourra en eet mettre plusieurs observateurs au courant ! En fait, pour faire une analogie, interprtez la relation entre les objets implmentant le pattern observer comme un diteur de journal et ses clients (gure 23.17).

Figure

23.17  Livreur de journaux

Grce ce schma, vous pouvez sentir que notre objet dni comme observable pourra tre surveill par plusieurs objets : il s'agit d'une relation dite de un plusieurs vers l'objet Observateur. Avant de vous expliquer plus en dtail le fonctionnement de ce pattern, jetez un il au diagramme de classes de notre application en gure 23.18. Ce diagramme indique que ce ne sont pas les instances d' Horloge ou de JLabel que nous allons utiliser, mais des implmentations d'interfaces. En eet, vous savez que les classes implmentant une interface peuvent tre dnies par le type de l'interface. Dans notre cas, la classe Fenetre implmentera l'interface 321

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS

Figure

23.18  Diagramme de classes du pattern observer

Observateur : nous pourrons la voir comme une classe du type Observateur. Vous avez sans doute remarqu que la deuxime interface  celle ddie l'objet Horloge 

possde trois mthodes :  une permettant d'ajouter des observateurs (nous allons donc grer une collection d'observateurs) ;  une permettant de retirer les observateurs ;  enn, une mettant jour les observateurs. Grce cela, nos objets ne sont plus lis par leurs types, mais par leurs interfaces ! L'interface qui apportera les mthodes de mise jour, d'ajout d'observateurs, etc. travaillera donc avec des objets de type Observateur. Ainsi, le couplage ne s'eectue plus directement, il s'opre par le biais de ces interfaces. Ici, il faut que nos deux interfaces soient couples pour que le systme fonctionne. De mme que, lorsque je vous ai prsent le pattern decorator, nos classes taient trs fortement couples puisqu'elles devaient travailler ensemble : nous devions alors faire en sorte de ne pas les sparer. Voici comment fonctionnera l'application :  nous instancierons la classe Horloge dans notre classe Fenetre ;  cette dernire implmentera l'interface Observateur ;  notre objet Horloge, implmentant l'interface Observable, prviendra les objets spcis de ses changements ;  nous informerons l'horloge que notre fentre l'observe ;  partir de l, notre objet Horloge fera le reste : chaque changement, nous appellerons la mthode mettant tous les observateurs jour. Le code source de ces interfaces se trouve ci-dessous (notez que j'ai cr un package com.sdz.observer). 322

TRE L'COUTE DE SES OBJETS : LE DESIGN PATTERN OBSERVER


Observateur.java
pkge omFsdzFoserverY puli interfe yservteur { puli void updte@tring hourAY }

Observer.java
pkge omFsdzFoserverY puli interfe yservle { puli void ddyservteur@yservteur osAY puli void updteyservteur@AY puli void delyservteur@AY }

Voici maintenant le code de nos deux classes, travaillant ensemble mais n'tant que faiblement couples. Copier le code Code web : 888649 
Horloge.java
pkge omFsdzFmodelY import jvFutilFerryvistY import jvFutilFglendrY import omFsdzFoserverFyservleY import omFsdzFoserverFyservteurY puli lss rorloge implements yservle{ GGyn rupre l9instne d9un lendrier GGille v nous permettre de ruprer l9heure tuelle privte glendr lY privte tring hour a 44Y GGxotre olletion d9oservteurs privte erryvist`yservteurb listyservteur a new erryvist`yservteurb@AY puli void run@A { while@trueA{ thisFl a glendrFgetsnstne@AY thisFhour a GGves heures thisFlFget@glendrFryypheA C 4 X 4 C

323

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


@ GGves minutes thisFlFget@glendrFwsxiA ` IH c 4H4 C thisFlFget@glendrFwsxiA X thisFlFget@glendrFwsxiA

A C 4 X 4 C @ GGves seondes @thisFlFget@glendrFigyxhA` IHA c 4H4CthisFlFget@glendrFigyxhA X thisFlFget@glendrFigyxhA AY GGyn vertit les oservteurs que l9heure t mise jour thisFupdteyservteur@AY try { hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY }

GGejoute un oservteur l liste puli void ddyservteur@yservteur osA { thisFlistyservteurFdd@osAY } GGetire tous les oservteurs de l liste puli void delyservteur@A { thisFlistyservteur a new erryvist`yservteurb@AY } GGevertit les oservteurs que l9ojet oservle hng GGet invoque l mthode updte@A de hque oservteur puli void updteyservteur@A { for@yservteur os X thisFlistyservteur A osFupdte@thisFhourAY }

Fenetre.java
pkge omFsdzFvueY import import import import jvFwtFfordervyoutY jvFwtFpontY jvxFswingFtprmeY jvxFswingFtvelY

import omFsdzFmodelFrorlogeY

324

TRE L'COUTE DE SES OBJETS : LE DESIGN PATTERN OBSERVER


import omFsdzFoserverFyservteurY puli lss penetre extends tprme { privte tvel lel a new tvel@AY privte rorloge horlogeY puli penetre@A{ GGyn initilise l tprme thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY thisFsetesizle@flseAY thisFsetize@PHHD VHAY GGyn initilise l9horloge thisFhorloge a new rorloge@AY GGyn ple un outeur sur l9horloge thisFhorlogeFddyservteur@new yservteur@A{ puli void updte@tring hourA { lelFsetext@hourAY } }AY GGyn initilise le tvel pont polie a new pont@4hEdigitl4D pontFiIpyxD QHAY thisFlelFsetpont@polieAY thisFlelFsetrorizontlelignment@tvelFgixiAY GGyn joute le tvel l tprme thisFgetgontentne@AFdd@thisFlelD fordervyoutFgixiAY thisFsetisile@trueAY thisFhorlogeFrun@AY

GGwthode min@A lnnt le progrmme puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Excutez ce code, vous verrez que tout fonctionne merveille. Vous venez de permettre deux objets de communiquer en n'utilisant presque aucun couplage : flicitations ! Vous pouvez voir que lorsque l'heure change, la mthode updateObservateur() est invoque. Celle-ci parcourt la collection d'objets Observateur et appelle sa mthode update(String hour). La mthode tant rednie dans notre classe Fenetre an de mettre JLabel jour, l'heure s'ache ! J'ai mentionn que ce pattern est utilis dans la gestion vnementielle d'interfaces graphiques. Vous avez en outre remarqu que leurs syntaxes sont identiques. En revanche, je vous ai cach quelque chose : il existe des classes Java permettant d'utiliser le pattern observer sans avoir coder les interfaces. 325

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS

Le pattern observer : le retour


En ralit, il existe une classe abstraite Observable et une interface Observer fournies dans les classes Java. Celles-ci fonctionnent de manire quasiment identique notre faon de procder, seuls quelques dtails dirent. Personnellement, je prfre de loin utiliser un pattern observer  fait maison . Pourquoi cela ? Tout simplement parce que l'objet que l'on souhaite observer doit hriter de la classe Observable. Par consquent, il ne pourra plus hriter d'une autre classe tant donn que Java ne gre pas l'hritage multiple. La gure 23.19 prsente la hirarchie de classes du pattern observer prsent dans Java.

Figure

23.19  Diagramme de classes du pattern observer de Java

Vous remarquez qu'il fonctionne presque de la mme manire que celui que nous avons dvelopp. Il y a toutefois une dirence dans la mthode update(Observable obs, Object obj) : sa signature a chang. Cette mthode prend ainsi deux paramtres :  un objet Observable ;  un Object reprsentant une donne supplmentaire que vous souhaitez lui fournir. Vous connaissez le fonctionnement de ce pattern, il vous est donc facile de comprendre le schma. Je vous invite cependant eectuer vos propres recherches sur son implmentation dans Java : vous verrez qu'il existe des subtilits (rien de mchant, cela dit). 326

CADEAU : UN BOUTON PERSONNALIS OPTIMIS

Cadeau : un bouton personnalis optimis


Terminons par une version amliore de notre bouton qui reprend ce que nous avons appris : Bouton personnalis Code web : 285456 
import import import import import import import import import import import import

jvFwtFgolorY jvFwtFpontwetrisY jvFwtFqrdientintY jvFwtFqrphisY jvFwtFqrphisPhY jvFwtFsmgeY jvFwtFeventFwouseiventY jvFwtFeventFwousevistenerY jvFioFpileY jvFioFsyixeptionY jvxFimgeioFsmgesyY jvxFswingFtfuttonY

puli lss fouton extends tfutton implements wousevistener{ privte tring nmeY privte smge imgY puli fouton@tring strA{ super@strAY thisFnme a strY try { img a smgesyFred@new pile@4fondfoutonFpng4AAY } th @syixeption eA { eFprinttkre@AY } thisFddwousevistener@thisAY } puli void pintgomponent@qrphis gA{ qrphisPh gPd a @qrphisPhAgY qrdientint gp a new qrdientint@HD HD golorFlueD HD PHD golorFynD trueAY gPdFsetint@gpAY gPdFdrwsmge@imgD HD HD thisFgetidth@AD thisFgetreight@AD thisAY gPdFsetgolor@golorFlkAY GGyjet permettnt de onntre les proprits d9une polieD GGdont l tille pontwetris fm a gPdFgetpontwetris@AY GGruteur de l polie d9riture int height a fmFgetreight@AY GGvrgeur totle de l hne psse en prmtre

327

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS


int width a fmFstringidth@thisFnmeAY GGyn lule lors l position du texteD et le tour est jou gPdFdrwtring@thisFnmeD thisFgetidth@A G P E @width G PAD @thisFgetreight@A G PA C @height G RAAY

puli void mousegliked@wouseivent eventA { GGsnutile d9utiliser ette mthode ii } puli void mouseintered@wouseivent eventA { GGxous hngeons le fond de notre imge pour le june GGlors du survolD ve le fihier fondfoutonroverFpng try { img a smgesyFred@new pile@4fondfoutonroverFpng4AAY } th @syixeption eA { eFprinttkre@AY } } puli void mouseixited@wouseivent eventA { GGxous hngeons le fond de notre imge pour le vert GGlorsque nous quittons le outonD ve le fihier fondfoutonFpng try { img a smgesyFred@new pile@4fondfoutonFpng4AAY } th @syixeption eA { eFprinttkre@AY } } puli void mouseressed@wouseivent eventA { GGxous hngeons le fond de notre imge pour le june GGlors du li guheD ve le fihier fondfoutongliFpng try { img a smgesyFred@new pile@4fondfoutongliFpng4AAY } th @syixeption eA { eFprinttkre@AY } } puli void mouseelesed@wouseivent eventA { GGxous hngeons le fond de notre imge pour l9ornge GGlorsque nous relhons le li GGve le fihier fondfoutonroverFpng GGsi l souris est toujours sur le outon if@@eventFget@A b H 88 eventFget@A ` outonFgetreight@AA 88 @eventFget@A b H 88 eventFget@A ` outonFgetidth@AAA{ try {

328

CADEAU : UN BOUTON PERSONNALIS OPTIMIS


img a smgesyFred@new pile@4fondfoutonroverFpng4AAY } th @syixeption eA { eFprinttkre@AY }

} GGi on se trouve l9extrieurD on dessine le fond pr dfut else{ try { img a smgesyFred@new pile@4fondfoutonFpng4AAY } th @syixeption eA { eFprinttkre@AY }

Essayez, vous verrez que cette application fonctionne correctement.

En rsum
 Vous pouvez interagir avec un composant grce votre souris en implmentant l'interface MouseListener.  Lorsque vous implmentez une interface <...>Listener, vous indiquez votre classe qu'elle doit se prparer observer des vnements du type de l'interface. Vous devez donc spcier qui doit observer et ce que la classe doit observer grce aux mthodes de type add<...>Listener(<...>Listener) .  L'interface utilise dans ce chapitre est ActionListener issue du package java.awt.  La mthode implmenter de cette interface est actionPerformed().  Une classe interne est une classe se trouvant l'intrieur d'une classe.  Une telle classe a accs toutes les donnes et mthodes de sa classe externe.  La JVM traite les mthodes appeles en utilisant une pile qui dnit leur ordre d'excution.  Une mthode est empile son invocation, mais n'est dpile que lorsque toutes ses instructions ont ni de s'excuter.  Le pattern observer permet d'utiliser des objets faiblement coupls. Grce ce pattern, les objets restent indpendants.

329

CHAPITRE 23. INTERAGIR AVEC DES BOUTONS

330

Chapitre

24
Dicult :

TP : une calculatrice

h ! a faisait longtemps. . . Un petit TP ! Dans celui-ci, nous allons  enn, vous allez  pouvoir rviser tout ce qui a t vu au cours de cette partie :  les fentres ;  les conteneurs ;  les boutons ;  les interactions ;  les classes internes ; L'objectif est ici de raliser une petite calculatrice basique.

331

CHAPITRE 24. TP : UNE CALCULATRICE

laboration
Nous allons tout de suite voir ce dont notre calculatrice devra tre capable.  Eectuer un calcul simple : 12 + 3.  Faire des calculs la chane, par exemple : 1 + 2 + . . . ; lorsqu'on clique nouveau sur un oprateur, il faut acher le rsultat du calcul prcdent.  Donner la possibilit de tout recommencer zro.  Grer l'exception d'une division par 0 !

Conception
Vous devriez obtenir peu de choses prs la gure 24.1.

Figure

24.1  Calculatrice

Voyons maintenant ce dont nous avons besoin pour parvenir nos ns :  autant de boutons qu'il en faut ;  autant de conteneurs que ncessaire ;  un JLabel pour l'achage ;  un boolen pour savoir si un oprateur a t slectionn ;  un boolen pour savoir si nous devons eacer ce qui gure l'cran et crire un nouveau nombre ;  nous allons utiliser une variable de type double pour nos calculs ;  il va nous falloir des classes internes qui implmenteront l'interface ActionListener ;  et c'est peu prs tout. Pour allger le nombre de classes internes, vous pouvez en crer une qui se chargera d'crire ce qui doit tre ach l'cran. Utilisez la mthode getSource() pour savoir sur quel bouton on a cliqu. Je ne vais pas tout vous dire, il faut que vous cherchiez par vous-mmes : la rexion est trs importante ! En revanche, vous devez savoir que la correction que je vous fournis n'est pas la correction. Il y a plusieurs solutions possibles. Je vous propose seulement l'une d'elles. 332

CORRECTION Allez, au boulot !

Correction
Vous avez bien rchi ? Vous vous tes brl quelques neurones ? Vous avez mrit votre correction !  Copier la correction Code web : 932059  Regardez bien comment tout interagit, et vous comprendrez comment fonctionne ce code.
import import import import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFhimensionY jvFwtFpontY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFforderptoryY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss glultrie extends tprme { privte tnel ontiner a new tnel@AY GGleu stoknt les lments ffiher dns l lultrie tring tstring a {4I4D 4P4D 4Q4D 4R4D 4S4D 4T4D 4U4D 4V4D 4W4D 4H4D 4F4D 4a4D 4g4D 4C4D 4E4D 4B4D 4G4}Y GGn outon pr lment ffiher tfutton tutton a new tfuttontstringFlengthY privte tvel ern a new tvel@AY privte himension dim a new himension@SHD RHAY privte himension dimP a new himension@SHD QIAY privte doule hiffreIY privte oolen liyperteur a flseD updte a flseY privte tring operteur a 44Y puli glultrie@A{ thisFsetize@PRHD PTHAY thisFsetitle@4glulette4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY thisFsetesizle@flseAY GGyn initilise le onteneur ve tous les omposnts initgomposnt@AY GGyn joute le onteneur thisFsetgontentne@ontinerAY

333

CHAPITRE 24. TP : UNE CALCULATRICE


thisFsetisile@trueAY

privte void initgomposnt@A{ GGyn dfinit l polie d9riture utiliser pont polie a new pont@4eril4D pontFfyvhD PHAY ern a new tvel@4H4AY ernFsetpont@polieAY GGyn ligne les informtions droite dns le tvel ernFsetrorizontlelignment@tvelFsqrAY ernFsetreferredize@new himension@PPHD PHAAY tnel operteur a new tnel@AY operteurFsetreferredize@new himension@SSD PPSAAY tnel hiffre a new tnel@AY hiffreFsetreferredize@new himension@ITSD PPSAAY tnel pnirn a new tnel@AY pnirnFsetreferredize@new himension@PPHD QHAAY GGyn prourt le tleu initilis GGfin de rer nos outons for@int i a HY i ` tstringFlengthY iCCA{ tuttoni a new tfutton@tstringiAY tuttoniFsetreferredize@dimAY swith@iA{ GGour hque lment situ l fin du tleu GGet qui n9est ps un hiffre GGon dfinit le omportement voir gre un listener se II X tuttoniFddetionvistener@new iglvistener@AAY hiffreFdd@tuttoniAY rekY se IP X tuttoniFsetporeground@golorFredAY tuttoniFddetionvistener@new esetvistener@AAY operteurFdd@tuttoniAY rekY se IQ X tuttoniFddetionvistener@new lusvistener@AAY tuttoniFsetreferredize@dimPAY operteurFdd@tuttoniAY rekY se IR X tuttoniFddetionvistener@new woinsvistener@AAY tuttoniFsetreferredize@dimPAY operteurFdd@tuttoniAY rekY se IS X tuttoniFddetionvistener@new wultivistener@AAY tuttoniFsetreferredize@dimPAY operteurFdd@tuttoniAY

334

CORRECTION
rekY se IT X tuttoniFddetionvistener@new hivvistener@AAY tuttoniFsetreferredize@dimPAY operteurFdd@tuttoniAY rekY defult X GGr dfutD e sont les premiers lments du tleu GGdon des hiffresD on ffete lors le on listener hiffreFdd@tuttoniAY tuttoniFddetionvistener@new ghiffrevistener@AAY rekY

} } pnirnFdd@ernAY pnirnFsetforder@forderptoryFretevineforder@golorFlkAAY ontinerFdd@pnirnD fordervyoutFxyrAY ontinerFdd@hiffreD fordervyoutFgixiAY ontinerFdd@operteurD fordervyoutFieAY

GGwthode permettnt d9effetuer un lul selon l9oprteur sletionn privte void lul@A{ if@operteurFequls@4C4AA{ hiffreI a hiffreI C houleFvlueyf@ernFgetext@AAFdoulelue@AY ernFsetext@tringFvlueyf@hiffreIAAY } if@operteurFequls@4E4AA{ hiffreI a hiffreI E houleFvlueyf@ernFgetext@AAFdoulelue@AY ernFsetext@tringFvlueyf@hiffreIAAY } if@operteurFequls@4B4AA{ hiffreI a hiffreI B houleFvlueyf@ernFgetext@AAFdoulelue@AY ernFsetext@tringFvlueyf@hiffreIAAY } if@operteurFequls@4G4AA{ try{ hiffreI a hiffreI G houleFvlueyf@ernFgetext@AAFdoulelue@AY ernFsetext@tringFvlueyf@hiffreIAAY } th@erithmetiixeption eA { ernFsetext@4H4AY } } } GGvistener utilis pour les hiffres

335

CHAPITRE 24. TP : UNE CALCULATRICE


GGermet de stoker les hiffres et de les ffiher lss ghiffrevistener implements etionvistener { puli void tionerformed@etionivent eA{ GGyn ffihe le hiffre dditionnel dns le lel tring str a @@tfuttonAeFgetoure@AAFgetext@AY if@updteA{ updte a flseY } else{ if@3ernFgetext@AFequls@4H4AA str a ernFgetext@A C strY } ernFsetext@strAY } } GGvistener ffet u outon a lss iglvistener implements etionvistener { puli void tionerformed@etionivent rgHA{ lul@AY updte a trueY liyperteur a flseY } } GGvistener ffet u outon C lss lusvistener implements etionvistener { puli void tionerformed@etionivent rgHA{ if@liyperteurA{ lul@AY ernFsetext@tringFvlueyf@hiffreIAAY } else{ hiffreI a houleFvlueyf@ernFgetext@AAFdoulelue@AY liyperteur a trueY } operteur a 4C4Y updte a trueY } } GGvistener ffet u outon E lss woinsvistener implements etionvistener { puli void tionerformed@etionivent rgHA{ if@liyperteurA{ lul@AY ernFsetext@tringFvlueyf@hiffreIAAY } else{ hiffreI a houleFvlueyf@ernFgetext@AAFdoulelue@AY

336

CORRECTION
liyperteur a trueY } operteur a 4E4Y updte a trueY

GGvistener ffet u outon B lss wultivistener implements etionvistener { puli void tionerformed@etionivent rgHA{ if@liyperteurA{ lul@AY ernFsetext@tringFvlueyf@hiffreIAAY } else{ hiffreI a houleFvlueyf@ernFgetext@AAFdoulelue@AY liyperteur a trueY } operteur a 4B4Y updte a trueY } } GGvistener ffet u outon G lss hivvistener implements etionvistener { puli void tionerformed@etionivent rgHA{ if@liyperteurA{ lul@AY ernFsetext@tringFvlueyf@hiffreIAAY } else{ hiffreI a houleFvlueyf@ernFgetext@AAFdoulelue@AY liyperteur a trueY } operteur a 4G4Y updte a trueY } } GGvistener ffet u outon de remise zro lss esetvistener implements etionvistener { puli void tionerformed@etionivent rgHA{ liyperteur a flseY updte a trueY hiffreI a HY operteur a 44Y ernFsetext@44AY } }

337

CHAPITRE 24. TP : UNE CALCULATRICE


puli lss win { puli stti void min@tring rgsA { glultrie lulette a new glultrie@AY } }

Je vais vous donner une petite astuce an de crer un .jar excutable en Java.

Gnrer un .jar excutable


Tout d'abord, qu'est-ce qu'un .jar ? C'est une extension propre aux archives Java (Java ARchive). Ce type de chier contient tout ce dont a besoin la JVM pour lancer un programme. Une fois votre archive cre, il vous sut de double-cliquer sur celle-ci pour lancer l'application. C'est le meilleur moyen de distribuer votre programme.

C'est exact pour peu que vous ayez ajout les excutables de votre JRE (prsents dans le rpertoire bin) dans votre variable d'environnement PATH ! Si ce n'est pas le cas, refaites un tour dans le premier chapitre du livre, section  Compilation en ligne de commande , et remplacez le rpertoire du JDK par celui du JRE 1 .
La cration d'un .jar est un jeu d'enfant. Commencez par eectuer un clic droit sur votre projet et choisissez l'option Export, comme le montre la gure 24.2. Vous voici dans la gestion des exports. Eclipse vous demande quel type d'export vous souhaitez raliser (gure 24.3). Comme l'illustre la gure 24.3, slectionnez JAR File puis cliquez sur Next. Vous voici maintenant dans la section qui vous demande les chiers que vous souhaitez inclure dans votre archive (gure 24.4).  Dans le premier cadre, slectionnez tous les chiers qui composeront votre excutable .jar.  Dans le second cadre, indiquez Eclipse l'endroit o crer l'archive et le nom vous souhaitez lui donner.  Ensuite, cliquez sur Next. La page suivante n'est pas trs pertinente ; je la mets cependant en gure 24.5 an de ne perdre personne. Cliquez sur Next : vous arrivez sur la page qui vous demande de spcier l'emplacement de la mthode main dans votre programme (gure 24.6). Cliquez sur Browse... pour acher un pop-up listant les chiers des programmes contenant une mthode main. Ici, nous n'en avons qu'une (gure 24.7). Souvenez-vous qu'il est possible que plusieurs mthodes main soient dclares, mais une seule sera excute !
1. Si vous n'avez pas tlcharg le JDK ; sinon, allez rcuprer ce dernier.

338

GNRER UN .JAR EXCUTABLE

Figure

24.2  Exporter son projet

Figure

24.3  Type d'export choisir

339

CHAPITRE 24. TP : UNE CALCULATRICE

Figure

24.4  Choix des chiers inclure

Figure

24.5  Choix du niveau d'erreurs tolrable

340

GNRER UN .JAR EXCUTABLE

Figure

24.6  Choix du point de dpart du programme

Figure

24.7  Notre mthode main

341

CHAPITRE 24. TP : UNE CALCULATRICE Slectionnez le point de dpart de votre application et validez. La gure 24.8 correspond ce que vous devriez obtenir.

Figure

24.8  Rcapitulatif d'export

Vous pouvez maintenant cliquer sur Finish et voir s'acher un message ressemblant celui de la gure 24.9.

Figure

24.9  Message lors de l'export

Ce type de message n'est pas alarmant : il vous signale qu'il existe des lments qu'Eclipse ne juge pas trs clairs. Ils n'empcheront toutefois pas votre application de fonctionner, contrairement un message d'erreur que vous reprerez facilement : il est en rouge. 342

GNRER UN .JAR EXCUTABLE Une fois cette tape valide, vous pouvez voir avec satisfaction qu'un chier .jar a bien t gnr dans le dossier spci (gure 24.10).

Figure

24.10  Fichier excutable .jar

Double-cliquez sur ce chier : votre calculatrice se lance !

343

CHAPITRE 24. TP : UNE CALCULATRICE

344

Chapitre

25
Dicult :

Excuter des tches simultanment

es threads sont des ls d'excution de notre programme. Lorsque nous en crons plusieurs, nous pouvons excuter des tches simultanment. Nous en tions rests notre animation qui bloque, et je vous avais dit que la solution tait d'utiliser un deuxime Thread. Dans ce chapitre, nous allons voir comment crer une (ou plusieurs) nouvelle(s) pile(s) de fonctions grce ces fameux threads. Il existe une classe Thread dans Java permettant leur gestion. Vous allez voir qu'il existe deux faons de crer un nouveau thread.

345

CHAPITRE 25. EXCUTER DES TCHES SIMULTANMENT

Une classe hrite de Thread


Je vous le rpte encore : lorsque vous excutez votre programme, un thread est lanc ! Dites-vous que le thread correspond la pile et que chaque nouveau thread cr gnre une pile d'excution. Pour le moment, nous n'allons pas travailler avec notre IHM et allons revenir en mode console. Crez un nouveau projet et une classe contenant la mthode main. Essayez ce code :
puli lss est { puli stti void min@tring rgsA { ystemFoutFprintln@4ve nom du thred prinipl est 4 C hredFurrenthred@AFgetxme@AAY } }

Vous devriez obtenir ceci :


Le nom du thread principal est main

Non, vous ne rvez pas : il s'agit bien de notre mthode main, le thread principal de notre application ! Voyez un thread comme une machine bien huile capable d'eectuer les tches que vous lui spciez. Une fois instanci, un thread attend son lancement. Ds que c'est fait, il invoque sa mthode run() qui va lui permettre de connatre les tches qu'il a eectuer. Nous allons maintenant apprendre crer un nouveau thread. Je l'avais mentionn dans l'introduction, il existe deux manires de faire :  crer une classe hritant de la classe Thread ;  crer une implmentation de l'interface Runnable et instancier un objet Thread avec l'implmentation de cette interface. Comme je vous le disais, nous allons opter pour la premire solution. Tout ce que nous avons faire, c'est rednir la mthode run() de notre objet an qu'il sache ce qu'il doit faire. Puisque nous allons en utiliser plusieurs, autant pouvoir les direncier : nous allons leur donner des noms. Crons donc une classe grant tout cela qui contient un constructeur comprenant un String en paramtre pour spcier le nom du thread. Cette classe doit galement comprendre une mthode getName() an de retourner ce nom. La classe Thread se trouvant dans le package java.lang, aucune instruction import n'est ncessaire. En voici le code :
puli lss esthred extends hred { puli esthred@tring nmeA{ super@nmeAY } puli void run@A{ for@int i a HY i ` IHY iCCA ystemFoutFprintln@thisFgetxme@AAY

346

UNE CLASSE HRITE DE THREAD


}

Testez maintenant ce code plusieurs fois :


puli lss est { puli stti void min@tring rgsA { esthred t a new esthred@4e4AY esthred tP a new esthred@4 f4AY tFstrt@AY tPFstrt@AY } }

Voici quelques captures d'cran de mes tests conscutifs en gure 25.1.

Figure

25.1  Essai de plusieurs Thread

Vous pouvez voir que l'ordre d'excution est souvent alatoire, car Java utilise un ordonnanceur. Vous devez savoir que si vous utilisez plusieurs threads dans une application, ceux-ci ne s'excutent pas toujours en mme temps ! En fait, l'ordonnanceur gre les threads de faon alatoire : il va en faire tourner un pendant un certain temps, puis un autre, puis revenir au premier, etc., jusqu' ce qu'ils soient termins. Lorsque 347

CHAPITRE 25. EXCUTER DES TCHES SIMULTANMENT l'ordonnanceur passe d'un thread un autre, le thread interrompu est mis en sommeil tandis que l'autre est en veil.

Notez qu'avec les processeurs multi-coeurs aujourd'hui, il est dsormais possible d'excuter deux tches exactement en mme temps. Tout dpend donc de votre ordinateur.
Un thread peut prsenter plusieurs tats.  NEW : lors de sa cration.  RUNNABLE : lorsqu'on invoque la mthode start(), le thread est prt travailler.  TERMINATED : lorsque le thread a eectu toutes ses tches ; on dit aussi qu'il est mort. Vous ne pouvez alors plus le relancer par la mthode start().  TIMED_WAITING : lorsque le thread est en pause (quand vous utilisez la mthode sleep(), par exemple).  WAITING : lorsque le thread est en attente indnie.  BLOCKED : lorsque l'ordonnanceur place un thread en sommeil pour en utiliser un autre, il lui impose cet tat. Un thread est considr comme termin lorsque la mthode run() est te de sa pile d'excution. En eet, une nouvelle pile d'excution contient sa base la mthode run() de notre thread. Une fois celle-ci dpile, notre nouvelle pile est dtruite ! En fait, le thread principal cre un second thread qui se lance et construit une pile dont la base est sa mthode run() ; celle-ci appelle une mthode, l'empile, eectue toutes les oprations demandes, et une fois qu'elle a termin, elle dpile cette dernire. La mthode run() prend n, la pile est alors dtruite. Nous allons modier notre classe TestThread an d'acher les tats de nos threads que nous pouvons rcuprer grce la mthode getState(). Voici notre classe TestThread modie :
puli lss esthred extends hred { hred tY puli esthred@tring nmeA{ super@nmeAY ystemFoutFprintln@4sttut du thred 4 C nme C 4 a 4 CthisFgettte@AAY thisFstrt@AY ystemFoutFprintln@4sttut du thred 4 C nme C 4 a 4 CthisFgettte@AAY } puli esthred@tring nmeD hred tA{ super@nmeAY thisFt a tY ystemFoutFprintln@4sttut du thred 4 C nme C 4 a 4 CthisFgettte@AAY thisFstrt@AY ystemFoutFprintln@4sttut du thred 4 C nme C 4 a 4 CthisFgettte@AAY } puli void run@A{

348

UNE CLASSE HRITE DE THREAD


for@int i a HY i ` IHY iCCA{ ystemFoutFprintln@4sttut 4 C thisFgetxme@A C 4 a 4 CthisFgettte@AAY if@t 3a nullAystemFoutFprintln@4sttut de 4 C tFgetxme C 4 pendnt le thred 4 C thisFgetxme@A C4 a 4 CtFgettte@AAY }

puli void sethred@hred tA{ thisFt a tY }

Ainsi que notre main :


puli lss est { puli stti void min@tring rgsA { esthred t a new esthred@4e4AY esthred tP a new esthred@4 f4D tAY try { hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY } ystemFoutFprintln@4sttut du thred 4 C tFgetxme@A C 4 a 4 C tFgettte@AAY ystemFoutFprintln@4sttut du thred 4 C tPFgetxme@A C 4 a 4 CtPFgettte@AAY } }

La gure 25.2 reprsente un jeu d'essais.

Figure

25.2  Test avec plusieurs threads simultans

Dans notre classe TestThread, nous avons ajout quelques instructions d'achage an de visualiser l'tat courant de nos objets. Mais nous avons aussi ajout un constructeur 349

CHAPITRE 25. EXCUTER DES TCHES SIMULTANMENT supplmentaire prenant un Thread en paramtre an d'obtenir l'tat de notre premier thread lors de l'excution du second. Dans le jeu d'essais, vous pouvez voir les dirents statuts qu'ont pris les threads. Ainsi, le premier est dans l'tat BLOCKED lorsque le second est en cours de traitement, ce qui justie ce que je vous disais : les threads ne s'excutent pas en mme temps ! Vous pouvez voir aussi que les oprations eectues par nos threads sont en fait codes dans la mthode run(). Reprenez l'image que j'ai montre prcdemment :  un thread est une machine bien huile capable d'eectuer les tches que vous lui spciez . Faire hriter un objet de Thread permet de crer un nouveau thread trs facilement. Vous pouvez cependant procder diremment : rednir uniquement ce que doit eectuer le nouveau thread grce l'interface Runnable. Dans ce cas, ma mtaphore prend tout son sens : vous ne rednissez que ce que doit faire la machine, et non pas la machine tout entire !

Utiliser l'interface Runnable


Ne rednir que les tches que le nouveau thread doit eectuer comprend un autre avantage : la classe dont nous disposons n'hrite d'aucune autre ! Eh oui : dans notre test prcdent, la classe TestThread ne pourra plus hriter d'une classe, tandis qu'avec une implmentation de Runnable, rien n'empche notre classe d'hriter de JFrame, par exemple. . . Trve de bavardages : codons notre implmentation de Runnable. Vous ne devriez avoir aucun problme y parvenir, sachant qu'il n'y a que la mthode run() rednir. An d'illustrer cela, nous allons utiliser un exemple que j'ai trouv intressant lorsque j'ai appris me servir des threads : nous allons crer un objet CompteEnBanque contenant une somme d'argent par dfaut (disons 100), une mthode pour retirer de l'argent (retraitArgent()) et une mthode retournant le solde ( getSolde()). Cependant, avant de retirer de l'argent, nous vrierons que nous ne sommes pas dcouvert. . . Notre thread va eectuer autant d'oprations que nous le souhaitons. La gure 25.3 reprsente le diagramme de classes rsumant la situation. Je rsume :  notre application peut contenir un ou plusieurs objets Thread ;  ceux-ci ne peuvent tre constitus que d'un objet de type Runnable ;  dans notre cas, les objets Thread contiendront une implmentation de Runnable : RunImpl ;  cette implmentation possde un objet CompteEnBanque. Voici les codes source. . .
RunImpl.java
puli lss unsmpl implements unnle { privte gompteinfnque Y

350

UTILISER L'INTERFACE RUNNABLE

Figure

25.3  Thread et compte en banque

puli unsmpl@gompteinfnque A{ thisF a Y } puli void run@A { for@int i a HY i ` PSY iCCA{ if@Fgetolde@A b HA{ Fretritergent@PAY ystemFoutFprintln@4etrit effetu4AY } } }

CompteEnBanque.java
puli lss gompteinfnque { privte int solde a IHHY puli int getolde@A{ if@thisFsolde ` HA ystemFoutFprintln@4ous tes douvert 34AY return thisFsoldeY }

351

CHAPITRE 25. EXCUTER DES TCHES SIMULTANMENT

puli void retritergent@int retritA{ solde a solde E retritY ystemFoutFprintln@4olde a 4 C soldeAY }

Test.java
puli lss est { puli stti void min@tring rgsA { gompteinfnque a new gompteinfnque@AY hred t a new hred@new unsmpl@AAY tFstrt@AY } }

Ce qui nous donne la gure 25.4.

Figure

25.4  Premier test de retrait d'argent

Rien d'extraordinaire ici, une simple boucle aurait fait la mme chose. Ajoutons un nom notre implmentation et crons un deuxime thread utilisant un deuxime compte. Il faut penser modier l'implmentation an que nous puissions connatre le thread qui travaille :
puli lss unsmpl implements unnle { privte gompteinfnque Y privte tring nmeY puli unsmpl@gompteinfnque D tring nmeA{ thisF a Y thisFnme a nmeY }

352

UTILISER L'INTERFACE RUNNABLE

puli void run@A { for@int i a HY i ` SHY iCCA{ if@Fgetolde@A b HA{ Fretritergent@PAY ystemFoutFprintln@4etrit effetu pr 4 C thisFnmeAY } } }

puli lss est { puli stti void min@tring rgsA { gompteinfnque a new gompteinfnque@AY gompteinfnque P a new gompteinfnque@AY hred t a new hred@new unsmpl@D 4gysoy4AAY hred tP a new hred@new unsmpl@PD 4ro4AAY tFstrt@AY tPFstrt@AY

Jusqu'ici, rien de perturbant : nous avons utilis deux instances distinctes de RunImpl utilisant elles-mmes deux instances distinctes de CompteEnBanque. Mais que se passeraitil si nous utilisions la mme instance de CompteEnBanque pour deux threads dirents ? Testez plusieurs fois le code que voici :
puli lss est { puli stti void min@tring rgsA { gompteinfnque a new gompteinfnque@AY hred t a new hred@new unsmpl@D 4gysoy4AAY hred tP a new hred@new unsmpl@D 4ro4AAY tFstrt@AY tPFstrt@AY

La gure 25.5 reprsente deux morceaux de rsultats obtenus lors de l'excution. Vous pouvez voir des incohrences monumentales ! J'imagine que vous pensiez comme moi que le compte aurait t dbit par pas de deux jusqu' la n sans obtenir d'aberrations de ce genre, puisque nous utilisons le mme objet. . . Eh bien, non ! Pourquoi ? Tout simplement parce que l'ordonnanceur de Java place les threads en sommeil quand il le dsire, et lorsque le thread qui tait en sommeil se rveille, il reprend son travail l o il l'avait laiss ! Voyons comment rsoudre ce problme. 353

CHAPITRE 25. EXCUTER DES TCHES SIMULTANMENT

Figure

25.5  Retrait multithread

Synchroniser ses threads


Tout est dans le titre ! En fait, ce qu'il faut faire, c'est indiquer la JVM qu'un thread est en train d'utiliser des donnes qu'un autre thread est susceptible d'altrer. Ainsi, lorsque l'ordonnanceur met en sommeil un thread qui traitait des donnes utilisables par un autre thread, ce premier thread garde la priorit sur les donnes et tant qu'il n'a pas termin son travail, les autres threads n'ont pas la possibilit d'y toucher. Cela s'appelle synchroniser les threads . Cette opration est trs dlicate et demande beaucoup de comptences en programmation. . . Voici quoi ressemble notre mthode retraitArgent() synchronise :
puli lss gompteinfnque { GGve dut du ode ne hnge ps puli synhronized void retritergent@int retritA{ solde a solde E retritY ystemFoutFprintln@4olde a 4 C soldeAY }

Il vous sut d'ajouter dans la dclaration de la mthode le mot cl synchronized, grce auquel la mthode est inaccessible un thread si elle est dj utilise par un autre thread. Ainsi, les threads cherchant utiliser des mthodes dj prises en charge par un autre thread sont placs dans une  liste d'attente . Je rcapitule une nouvelle fois, en me servant d'un exemple simple. Je serai reprsent par le thread A, vous par le thread B, et notre boulangerie favorite par la mthode synchronise M. Voici ce qu'il se passe :  le thread A (moi) appelle la mthode M ;  je commence par demander une baguette : la boulangre me la pose sur le comptoir et commence calculer le montant ;  c'est l que le thread B (vous) cherche aussi utiliser la mthode M ; cependant, elle est dj occupe par un thread (moi) ;  vous tes donc mis en attente ; 354

CONTRLER SON ANIMATION  l'action revient sur moi (thread A) ; au moment de payer, je dois chercher de la monnaie dans ma poche ;  au bout de quelques instants, je m'endors ;  l'action revient sur le thread B (vous). . . mais la mthode M n'est toujours pas libre du thread A, vous tes donc remis en attente ;  on revient sur le thread A qui arrive enn payer et quitter la boulangerie : la mthode M est maintenant libre ;  le thread B (vous) peut enn utiliser la mthode M ;  et l, les threads C, D, E et F entrent dans la boulangerie ;  et ainsi de suite. Je pense que grce cela, vous avez d comprendre. . . Dans un contexte informatique, il peut tre pratique et scuris d'utiliser des threads et des mthodes synchronises lors d'accs des services distants tels qu'un serveur d'applications ou un SGBD 1 . Je vous propose maintenant de retourner notre animation, qui n'attend plus qu'un petit thread pour fonctionner correctement !

Contrler son animation


partir d'ici, il n'y a rien de bien compliqu. Il nous sut de crer un nouveau thread lorsqu'on clique sur le bouton Go en lui passant une implmentation de Runnable en paramtre qui, elle, va appeler la mthode go() (n'oublions pas de remettre le boolen de contrle true). Voici le code de notre classe Fenetre utilisant le thread en question :
import import import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFhimensionY jvFwtFpontY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme{ privte nneu pn a new nneu@AY privte tfutton outon a new tfutton@4qo4AY privte tfutton outonP a new tfutton@4top4AY privte tnel ontiner a new tnel@AY privte tvel lel a new tvel@4ve tvel4AY privte int ompteur a HY privte oolen nimted a trueY privte oolen kD kY

1. Systme de Gestion de Base de Donnes.

355

CHAPITRE 25. EXCUTER DES TCHES SIMULTANMENT


privte int xD yY privte hred tY puli penetre@A{ GGve onstruteur n9 ps hng } privte void go@A{ GGv mthode n9 ps hng } puli lss foutonvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { nimted a trueY t a new hred@new lyenimtion@AAY tFstrt@AY outonFsetinled@flseAY outonPFsetinled@trueAY } } lss foutonPvistener implements etionvistener{ puli void tionerformed@etionivent eA { nimted a flseY outonFsetinled@trueAY outonPFsetinled@flseAY } } lss lyenimtion implements unnle{ puli void run@A { go@AY } }

Copier ce code Code web : 636432  Voil, vous avez enn le contrle sur votre animation ! Nous allons prsent pouvoir l'agrmenter un peu dans les chapitres suivants.

En rsum
 Un nouveau thread permet de crer une nouvelle pile d'excution.  La classe Thread et l'interface Runnable se trouvent dans le package java.lang, aucun import spcique n'est donc ncessaire pour leur utilisation.  Un thread se lance lorsqu'on invoque la mthode start().  Cette dernire invoque automatiquement la mthode run(). 356

CONTRLER SON ANIMATION  Les oprations que vous souhaitez eectuer dans une autre pile d'excution sont placer dans la mthode run(), qu'il s'agisse d'une classe hritant de Thread ou d'une implmentation de Runnable.  Pour protger l'intgrit des donnes accessibles plusieurs threads, utilisez le mot cl synchronized dans la dclaration de vos mthodes.  Un thread est dclar mort lorsqu'il a dpil la mthode run() de sa pile d'excution.  Les threads peuvent prsenter plusieurs tats : NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING et TERMINATED.

357

CHAPITRE 25. EXCUTER DES TCHES SIMULTANMENT

358

Chapitre

26
Dicult :

Les champs de formulaire

ontinuons explorer les objets que nous propose swing. Ils sont varis et s'utilisent souvent de la mme manire que les boutons. En fait, maintenant que nous avons compris le fonctionnement du pattern observer, nous travaillerons avec des interfaces et devrons donc implmenter des mthodes pour grer les vnements avec nos composants. Allons-y !

359

CHAPITRE 26. LES CHAMPS DE FORMULAIRE

Les listes : l'objet JComboBox


Premire utilisation
Comme l'accoutume, nous utiliserons d'abord cet objet dans un contexte exempt de tout code superu. Crons donc un projet avec une classe contenant la mthode main() et une classe hrite de JFrame. Dans cet exemple, nous aurons bien sr besoin d'une liste, faites-en une. Cependant, vous ne manquerez pas de constater que notre objet est ridiculement petit. Vous connaissez le remde : il sut de lui spcier une taille !
import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFhimensionY jvxFswingFtgomofoxY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme { privte tnel ontiner a new tnel@AY privte tgomofox omo a new tgomofox@AY privte tvel lel a new tvel@4ne gomofox4AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY omoFsetreferredize@new himension@IHHD PHAAY tnel top a new tnel@AY topFdd@lelAY topFdd@omoAY ontinerFdd@topD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY

La gure 26.1 correspond au rsultat de ce code. En revanche, cette liste est vide ! Pour rsoudre ce problme, il sut d'utiliser la mthode addItem(Object obj). 360

LES LISTES : L'OBJET JCOMBOBOX

Figure

26.1  Premire JComboBox

Sachez que lorsque l'objet ache les lments ajouts, il appelle leur mthode toString(). Dans cet exemple, nous avons utilis des objets String, mais essayez avec un autre objet et vous constaterez le rsultat. . .
Voici le nouveau code :
GGves imports restent inhngs puli lss penetre extends tprme { GGves vriles d9instne restent inhnges puli penetre@A{ GGFFF omoFsetreferredize@new himension@IHHD PHAAY omoFddstem@4yption I4AY omoFddstem@4yption P4AY omoFddstem@4yption Q4AY omoFddstem@4yption R4AY } GGFFF

Vous pouvez voir ce que a donne en gure 26.2.

Figure

26.2  JComboBox contenant des donnes

Pour initialiser une JComboBox, vous pouvez utiliser le constructeur prenant un tableau d'objets en paramtre an de renseigner tous les lments d'un coup. Ceci est donc quivalent au code prcdent :
tring t a {4yption I4D 4yption P4D 4yption Q4D 4yption R4}Y omo a new tgomofox@tAY

361

CHAPITRE 26. LES CHAMPS DE FORMULAIRE Vous pouvez assigner un choix par dfaut avec la mthode setSelectedIndex(int index). Vous avez aussi la possibilit de changer la couleur du texte, la couleur de fond ou la police, exactement comme avec un JLabel. Maintenant que nous savons comment fonctionne cet objet, nous allons apprendre communiquer avec lui.

L'interface

ItemListener

Cette interface possde une mthode rednir. Celle-ci est appele lorsqu'un lment a chang d'tat. Puisqu'un exemple est toujours plus loquent, voici un code implmentant cette interface :
GGves utres imports import jvFwtFeventFstemiventY import jvFwtFeventFstemvistenerY puli lss penetre extends tprme { GGves vriles d9instne restent inhnges puli penetre@A{ GGve dut ne hnge ps GGsiD nous hngeons juste l fon d9initiliser l tgomofox tring t a {4yption I4D 4yption P4D 4yption Q4D 4yption R4}Y omo a new tgomofox@tAY GGejout du listener omoFddstemvistener@new stemtte@AAY omoFsetreferredize@new himension@IHHD PHAAY omoFsetporeground@golorFlueAY } GGv fin reste inhnge

GGglsse interne implmentnt l9interfe stemvistener lss stemtte implements stemvistener{ puli void itemtteghnged@stemivent eA { ystemFoutFprintln@4vnement dlenh sur X 4 C eFgetstem@AAY } }

Dans mon exemple, j'ai cliqu sur Option 2, puis Option 3, puis Option 4, ce qui correspond la gure 26.3. Vous voyez que lorsque nous cliquons sur une autre option, notre objet commence par modier l'tat de l'option prcdente (l'tat passe en DESELECTED) avant de changer celui de l'option choisie (celle-ci passe l'tat SELECTED). Nous pouvons donc suivre trs facilement l'tat de nos lments grce cette interface ; cependant, pour plus 362

LES LISTES : L'OBJET JCOMBOBOX

Figure

26.3  Interaction avec la JComboBox

de simplicit, nous utiliserons l'interface ActionListener an de rcuprer l'option slectionne. Voici un code implmentant cette interface :
GGves utres imports import jvFwtFeventFetioniventY import jvFwtFeventFetionvistenerY puli lss penetre extends tprme { GGves vriles d9instne restent inhnges puli penetre@A{ GGve dut ne hnge ps tring t a {4yption I4D 4yption P4D 4yption Q4D 4yption R4}Y omo a new tgomofox@tAY GGejout du listener omoFddstemvistener@new stemtte@AAY omoFddetionvistener@new stemetion@AAY omoFsetreferredize@new himension@IHHD PHAAY omoFsetporeground@golorFlueAY GGv fin reste inhnge } GGv lsse interne stemtte reste inhnge lss stemetion implements etionvistener{ puli void tionerformed@etionivent eA { ystemFoutFprintln@4etionvistener X tion sur 4 C omoFgeteletedstem@AAY } }

Le rsultat se trouve en gure 26.4. Vous constatez qu'en utilisant cette mthode, nous pouvons rcuprer l'option sur laquelle l'action a t eectue. L'appel de la mthode getSelectedItem() retourne la valeur de l'option slectionne ; une fois rcupre, nous pouvons travailler avec notre liste ! Maintenant que nous savons comment rcuprer les informations dans une liste, je vous invite continuer notre animation. 363

CHAPITRE 26. LES CHAMPS DE FORMULAIRE

Figure

26.4  ActionListener et JComboBox

Changer la forme de notre animation


Comme le titre l'indique, nous allons faire en sorte que notre animation ne se contente plus d'acher un rond : nous pourrons dsormais choisir la forme que nous voulons acher. Bien sr, je ne vais pas vous faire raliser toutes les formes possibles et imaginables ; je vous en fournis quelques-unes et, si le cur vous en dit, vous pouvez ajouter des formes de votre composition. Trs bien : pour raliser cela, nous devons dynamiser un peu notre classe Panneau an qu'elle peigne une forme en fonction de notre choix. Pour y parvenir, nous allons ajouter une variable d'instance de type String qui contiendra l'intitul de la forme que nous souhaitons dessiner  appelons-la forme  ainsi qu'un mutateur permettant de rednir cette variable. Notre mthode paintComponent() doit pouvoir dessiner la forme demande ; ainsi, trois cas de gure se prolent :  soit nous intgrons les instructions if dans cette mthode et l'objet Graphics dessinera en fonction de la variable ;  soit nous dveloppons une mthode prive appele dans la mthode paintComponent() et qui dessinera la forme demande ;  soit nous utilisons le pattern strategy an d'encapsuler la faon dont nous dessinerons nos formes dans notre animation. Le pattern strategy est de loin la meilleure solution, mais an de ne pas alourdir nos exemples, nous travaillerons  l'ancienne . Nous allons donc dvelopper une mthode prive  appelons-la draw(Graphics g)  qui aura pour tche de dessiner la forme voulue. Nous passerons l'objet Graphics dans la mthode paintComponent() de sorte que cette dernire puisse l'utiliser ; c'est donc dans cette mthode que nous placerons nos conditions. Je vous propose les formes suivantes :  le rond, forme par dfaut ;  le carr ;  le triangle ;  l'toile (soyons fous). Cela signie que notre liste contiendra ces quatre choix et que le rond gurera en premier lieu. Nous crerons aussi une implmentation d' ActionListener dans une classe interne pour grer les actions de notre liste. Je l'ai appele FormeListener (c'est 364

LES LISTES : L'OBJET JCOMBOBOX fou ce que je suis original). Ce que vous obtiendrez est reprsent la gure 26.5.

Figure

26.5  Toutes les formes dnies

Essayez de raliser ces formes vous-mmes : il n'y a l rien de compliqu, je vous assure ! Bon, l'toile est peut-tre un peu plus complexe que les autres, mais ce n'est pas insurmontable. Copier les codes Code web : 267428 


Classe Panneau
import import import import import jvFwtFgolorY jvFwtFpontY jvFwtFqrdientintY jvFwtFqrphisY jvFwtFqrphisPhY

import jvxFswingFtnelY puli lss nneu extends tnel { privte int pos a ESHY privte int pos a ESHY privte tring forme a 4yxh4Y puli void pintgomponent@qrphis gA{ GGyn hoisit une ouleur de fond pour le retngle gFsetgolor@golorFwhiteAY GGyn le dessine de sorte qu9il oupe toute l surfe gFfillet@HD HD thisFgetidth@AD thisFgetreight@AAY

365

CHAPITRE 26. LES CHAMPS DE FORMULAIRE


GGyn redfinit une ouleur pour le rond gFsetgolor@golorFredAY GGyn dlgue l mthode de dessin l mthode drw@A drw@gAY

privte void drw@qrphis gA{ if@thisFformeFequls@4yxh4AA{ gFfillyvl@posD posD SHD SHAY } if@thisFformeFequls@4gei4AA{ gFfillet@posD posD SHD SHAY } if@thisFformeFequls@4sexqvi4AA{ GGglul des sommets GGve sommet I se situe l moiti du t suprieur du rr int sI a pos C PSY int sI a posY GGve sommet P se situe en s droite int sP a pos C SHY int sP a pos C SHY GGve sommet Q se situe en s guhe int sQ a posY int sQ a pos C SHY GGxous rons deux tleux de oordonnes int pts a {sID sPD sQ}Y int pts a {sID sPD sQ}Y GGxous utilisons l mthode fillolygon@A gFfillolygon@ptsD ptsD QAY } if@thisFformeFequls@4iysvi4AA{ GGour l9toileD on se ontente de trer des lignes dns le rr GGorrespondnt peu prs une toileFFF GGwis e ode peut tre mlior 3 int sI a pos C PSY int sI a posY int sP a pos C SHY int sP a pos C SHY gFdrwvine@sID sID sPD sPAY int sQ a posY int sQ a pos C IUY gFdrwvine@sPD sPD sQD sQAY int sR a pos C SHY int sR a pos C IUY gFdrwvine@sQD sQD sRD sRAY int sS a posY int sS a pos C SHY gFdrwvine@sRD sRD sSD sSAY gFdrwvine@sSD sSD sID sIAY }

366

LES LISTES : L'OBJET JCOMBOBOX


} puli void setporme@tring formA{ thisFforme a formY } puli int getos@A { return posY } puli void setos@int posA { thisFpos a posY } puli int getos@A { return posY } puli void setos@int posA { thisFpos a posY }

Classe Fenetre
import import import import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvFwtFeventFstemiventY jvFwtFeventFstemvistenerY jvxFswingFtfuttonY jvxFswingFtgomofoxY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme{ privte nneu pn a new nneu@AY privte tfutton outon a new tfutton@4qo4AY privte tfutton outonP a new tfutton@4top4AY privte tnel ontiner a new tnel@AY privte tvel lel a new tvel@4ghoix de l forme4AY privte int ompteur a HY privte oolen nimted a trueY privte oolen kD kY privte int xD yY privte hred tY

367

CHAPITRE 26. LES CHAMPS DE FORMULAIRE


privte tgomofox omo a new tgomofox@AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY outonFddetionvistener@new foutonvistener@AAY outonPFddetionvistener@new foutonPvistener@AAY outonPFsetinled@flseAY tnel south a new tnel@AY southFdd@outonAY southFdd@outonPAY ontinerFdd@southD fordervyoutFyrAY omoFddstem@4yxh4AY omoFddstem@4gei4AY omoFddstem@4sexqvi4AY omoFddstem@4iysvi4AY omoFddetionvistener@new pormevistener@AAY tnel top a new tnel@AY topFdd@lelAY topFdd@omoAY ontinerFdd@topD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY

privte void go@A{ x a pnFgetos@AY y a pnFgetos@AY while@thisFnimtedA{ if@x ` IA k a flseY if@x b pnFgetidth@A E SHA k a trueY if@y ` IA k a flseY if@y b pnFgetreight@A E SHA k a trueY if@3kA pnFsetos@CCxAY else pnFsetos@EExAY if@3kA pnFsetos@CCyAY else pnFsetos@EEyAY pnFrepint@AY try { hredFsleep@QAY } th @snterruptedixeption eA {

368

LES LISTES : L'OBJET JCOMBOBOX


eFprinttkre@AY

GGglsse outnt notre outon puli lss foutonvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { nimted a trueY t a new hred@new lyenimtion@AAY tFstrt@AY outonFsetinled@flseAY outonPFsetinled@trueAY } } lss foutonPvistener implements etionvistener{ puli void tionerformed@etionivent eA { nimted a flseY outonFsetinled@trueAY outonPFsetinled@flseAY } } lss lyenimtion implements unnle{ puli void run@A { go@AY } } lss pormevistener implements etionvistener{ puli void tionerformed@etionivent eA { GGv mthode retourne un yjet puisque nous pssons GGdes yjet dns une liste GGsl fut don utiliser l mthode totring@A GGpour retourner un tring @ou utiliser un stA pnFsetporme@omoFgeteletedstem@AFtotring@AAY } }

Et voil le travail ! Vous avez vu : il n'y avait rien de sorcier. En fait, tant donn que vous avez l'habitude d'utiliser des objets graphiques et des implmentations d'interfaces, les choses vont maintenant s'acclrer, car le principe est le mme pour tous les objets graphiques de base. 369

CHAPITRE 26. LES CHAMPS DE FORMULAIRE

Les cases cocher : l'objet JCheckBox


Premire utilisation
Crez un projet vide avec une classe contenant une mthode main() et une classe hritant de JFrame. Cela fait, nous allons utiliser notre nouvel objet. Celui-ci peut tre instanci avec un String en paramtre qui servira de libell. Nous pouvons galement cocher la case par dfaut en appelant la mthode setSelected(Boolean bool) laquelle nous passons true. Cet objet possde, comme tous les autres, une multitude de mthodes nous simpliant la vie ; je vous invite aussi fouiner un peu. . . Nous crerons directement une implmentation de l'interface ActionListener, vous connaissez bien la dmarche. Contrlons galement que notre objet est coch l'aide de la mthode isSelected() qui retourne un boolen. Voici un code mettant tout cela en uvre :
import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtghekfoxY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme { privte tnel ontiner a new tnel@AY privte tghekfox hekI a new tghekfox@4gse I4AY privte tghekfox hekP a new tghekfox@4gse P4AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY tnel top a new tnel@AY hekIFddetionvistener@new ttevistener@AAY hekPFddetionvistener@new ttevistener@AAY topFdd@hekIAY topFdd@hekPAY ontinerFdd@topD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY } lss ttevistener implements etionvistener{ puli void tionerformed@etionivent eA {

370

LES CASES COCHER : L'OBJET JCHECKBOX


ystemFoutFprintln@4soure X 4 C @@tghekfoxAeFgetoure@AAFgetext@A C 4 E tt X 4 C @@tghekfoxAeFgetoure@AAFiseleted@AAY

Le rsultat se trouve en gure 26.6.

Figure

26.6  Nos cases cocher

Ici, je me suis amus cocher et dcocher mes cases. Il n'y a rien de bien dicile, a devient routinier, non ?

Un pseudomorphing pour notre animation


Nous allons utiliser cet objet an que nos formes changent de taille et proposent un pseudo-eet de morphing. Premirement, la taille de notre forme est xe, il nous faut changer cela. Allez, hop, une variable de type int dans notre classe Panneau  disons drawSize  initialise 50. Tout comme avec le dplacement, nous devons savoir lorsqu'il faut augmenter ou rduire la taille de notre forme : nous utiliserons donc la mme mthode que celle que nous avions dveloppe ce moment-l. Un JCheckBox sera ncessaire pour savoir si le  mode morphing  est activ. En ce qui concerne la taille, si on la rduit ou l'augmente d'une unit chaque rafrachissement, l'eet de morphing sera ultra rapide. Donc, pour ralentir l'eet, nous utiliserons une mthode retournant 1 ou 0 selon le nombre de rafrachissements. Cela implique que nous aurons besoin d'une variable pour les dnombrer. Nous eectuerons une augmentation ou une rduction toutes les dix fois. Pour bien sparer les deux cas de gure, nous insrerons une deuxime mthode de dessin dans la classe Panneau qui aura pour rle de dessiner le morphing ; appelons-la drawMorph(Graphics g) . Lorsque nous cocherons la case, le morphing s'activera, et il se dsactivera une fois dcoche. La classe Panneau devra donc disposer d'un mutateur pour le boolen de morphing. 371

CHAPITRE 26. LES CHAMPS DE FORMULAIRE Souvenez-vous que nous grons la collision avec les bords dans notre classe Fenetre. Cependant, en  mode morphing , la taille de notre forme n'est plus constante : il faudra grer ce nouveau cas de gure dans notre mthode go(). Notre classe Panneau devra possder un accesseur permettant de retourner la taille actuelle de la forme. Vous avez dsormais toutes les cls en main pour russir cette animation. La gure 26.7 donne un aperu de ce que vous devriez obtenir (je n'ai reprsent que le rond et le triangle, mais a fonctionne avec toutes les formes).

Figure

26.7  Morphing

Copier les codes Code web : 305023 

Fichier Panneau.java
import import import import import import jvFwtFgolorY jvFwtFpontY jvFwtFqrdientintY jvFwtFqrphisY jvFwtFqrphisPhY jvxFswingFtnelY

puli lss nneu extends tnel { privte int pos a ESHY privte int pos a ESHY privte int drwize a SHY GGn oolen pour le mode morphing GGn utre pour svoir si l tille doit tre rduite privte oolen morph a flseD redue a flseY privte tring forme a 4yxh4Y GGve ompteur de rfrhissements privte int inrement a HY puli void pintgomponent@qrphis gA{

372

LES CASES COCHER : L'OBJET JCHECKBOX


gFsetgolor@golorFwhiteAY gFfillet@HD HD thisFgetidth@AD thisFgetreight@AAY gFsetgolor@golorFredAY GGi le mode morphing est tivD on peint le morphing if@thisFmorphA drwworph@gAY GGinonD on peint le mode norml else drw@gAY

privte void drw@qrphis gA{ if@thisFformeFequls@4yxh4AA{ gFfillyvl@posD posD SHD SHAY } if@thisFformeFequls@4gei4AA{ gFfillet@posD posD SHD SHAY } if@thisFformeFequls@4sexqvi4AA{ int sI a pos C SHGPY int sI a posY int sP a pos C SHY int sP a pos C SHY int sQ a posY int sQ a pos C SHY int pts a {sID sPD sQ}Y int pts a {sID sPD sQ}Y gFfillolygon@ptsD ptsD QAY } if@thisFformeFequls@4iysvi4AA{ int sI a pos C SHGPY int sI a posY int sP a pos C SHY int sP a pos C SHY gFdrwvine@sID sID sPD sPAY int sQ a posY int sQ a pos C SHGQY gFdrwvine@sPD sPD sQD sQAY int sR a pos C SHY int sR a pos C SHGQY gFdrwvine@sQD sQD sRD sRAY int sS a posY int sS a pos C SHY gFdrwvine@sRD sRD sSD sSAY gFdrwvine@sSD sSD sID sIAY } } GGwthode qui peint le morphing privte void drwworph@qrphis gA{

373

CHAPITRE 26. LES CHAMPS DE FORMULAIRE


GGyn inrmente inrementCCY GGyn regrde si on doit rduire ou non if@drwize ba SHA redue a trueY if@drwize `a IHA redue a flseY if@redueA drwize a drwize E getsedize@AY else drwize a drwize C getsedize@AY if@thisFformeFequls@4yxh4AA{ gFfillyvl@posD posD drwizeD drwizeAY } if@thisFformeFequls@4gei4AA{ gFfillet@posD posD drwizeD drwizeAY } if@thisFformeFequls@4sexqvi4AA{ int sI a pos C drwizeGPY int sI a posY int sP a pos C drwizeY int sP a pos C drwizeY int sQ a posY int sQ a pos C drwizeY int pts a {sID sPD sQ}Y int pts a {sID sPD sQ}Y gFfillolygon@ptsD ptsD QAY } if@thisFformeFequls@4iysvi4AA{ int sI a pos C drwizeGPY int sI a posY int sP a pos C drwizeY int sP a pos C drwizeY gFdrwvine@sID sID sPD sPAY int sQ a posY int sQ a pos C drwizeGQY gFdrwvine@sPD sPD sQD sQAY int sR a pos C drwizeY int sR a pos C drwizeGQY gFdrwvine@sQD sQD sRD sRAY int sS a posY int sS a pos C drwizeY gFdrwvine@sRD sRD sSD sSAY gFdrwvine@sSD sSD sID sIAY }

GGetourne le nomre retrnher ou jouter pour le morphing privte int getsedize@A{ int res a HY GGi le nomre de tours est de dixD

374

LES CASES COCHER : L'OBJET JCHECKBOX


GGon rinitilise l9inrment et on retourne I if@inrement G IH aa IA{ inrement a HY res a IY } return resY

puli int gethrwize@A{ return drwizeY } puli oolen isworph@A{ return morphY } puli void setworph@oolen oolA{ thisFmorph a oolY GGyn rinitilise l tille drwize a SHY } puli void setporme@tring formA{ thisFforme a formY } puli int getos@A { return posY } puli void setos@int posA { thisFpos a posY } puli int getos@A { return posY } puli void setos@int posA { thisFpos a posY }

Fichier Fenetre.java
import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY

375

CHAPITRE 26. LES CHAMPS DE FORMULAIRE


import import import import import import jvxFswingFtfuttonY jvxFswingFtghekfoxY jvxFswingFtgomofoxY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY

puli lss penetre extends tprme{ privte privte privte privte privte privte privte privte privte privte privte nneu pn a new nneu@AY tfutton outon a new tfutton@4qo4AY tfutton outonP a new tfutton@4top4AY tnel ontiner a new tnel@AY tvel lel a new tvel@4ghoix de l forme4AY int ompteur a HY oolen nimted a trueY oolen kD kY int xD yY hred tY tgomofox omo a new tgomofox@AY

privte tghekfox morph a new tghekfox@4worphing4AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY outonFddetionvistener@new foutonvistener@AAY outonPFddetionvistener@new foutonPvistener@AAY outonPFsetinled@flseAY tnel south a new tnel@AY southFdd@outonAY southFdd@outonPAY ontinerFdd@southD fordervyoutFyrAY omoFddstem@4yxh4AY omoFddstem@4gei4AY omoFddstem@4sexqvi4AY omoFddstem@4iysvi4AY omoFddetionvistener@new pormevistener@AAY morphFddetionvistener@new worphvistener@AAY tnel top a new tnel@AY topFdd@lelAY topFdd@omoAY topFdd@morphAY ontinerFdd@topD fordervyoutFxyrAY

376

LES CASES COCHER : L'OBJET JCHECKBOX


thisFsetgontentne@ontinerAY thisFsetisile@trueAY

privte void go@A{ x a pnFgetos@AY y a pnFgetos@AY while@thisFnimtedA{ GGi le mode morphing est tivD on utilise GGl tille tuelle de l forme if@pnFisworph@AA{ if@x ` IAk a flseY if@x b pnFgetidth@A E pnFgethrwize@AA k a trueY if@y ` IAk a flseY if@y b pnFgetreight@A E pnFgethrwize@AA k a trueY } GGinonD on fit omme d9hitude else{ if@x ` IAk a flseY if@x b pnFgetidth@AESHA k a trueY if@y ` IAk a flseY if@y b pnFgetreight@AESHA k a trueY } if@3kA pnFsetos@CCxAY else pnFsetos@EExAY if@3kA pnFsetos@CCyAY else pnFsetos@EEyAY pnFrepint@AY try { hredFsleep@QAY } th @snterruptedixeption eA { eFprinttkre@AY

puli lss foutonvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { nimted a trueY t a new hred@new lyenimtion@AAY tFstrt@AY outonFsetinled@flseAY outonPFsetinled@trueAY } lss foutonPvistener implements etionvistener{ puli void tionerformed@etionivent eA {

377

CHAPITRE 26. LES CHAMPS DE FORMULAIRE


nimted a flseY outonFsetinled@trueAY outonPFsetinled@flseAY

lss lyenimtion implements unnle{ puli void run@A { go@AY } } lss pormevistener implements etionvistener{ puli void tionerformed@etionivent eA { pnFsetporme@omoFgeteletedstem@AFtotring@AAY } } lss worphvistener implements etionvistener{ puli void tionerformed@etionivent eA { GGi l se est oheD on tive le mode morphing if@morphFiseleted@AApnFsetworph@trueAY GGinonD on ne fit rien else pnFsetworph@flseAY } }

Alors, qu'en pensez-vous ? J'aime bien, moi. . . Vous voyez, l'utilisation des JCheckBox est trs simple. Je vous propose maintenant d'tudier un de ses cousins !

Le petit cousin : l'objet

JRadioButton

Le voici, le cousin loign. . . Le principe est de proposer au moins deux choix, mais de ne permettre d'en slectionner qu'un la fois. L'instanciation se fait de la mme manire que pour un JCheckBox ; d'ailleurs, nous utiliserons l'exemple du dbut de ce chapitre en remplaant les cases cocher par des boutons radio. Voici le code correspondant :
import import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtghekfoxY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY jvxFswingFtdiofuttonY

378

LES CASES COCHER : L'OBJET JCHECKBOX


puli lss penetre extends tprme { privte tnel ontiner a new tnel@AY privte tdiofutton jrI a new tdiofutton@4dio I4AY privte tdiofutton jrP a new tdiofutton@4dio P4AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY tnel top a new tnel@AY jrIFddetionvistener@new ttevistener@AAY jrPFddetionvistener@new ttevistener@AAY topFdd@jrIAY topFdd@jrPAY ontinerFdd@topD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY } lss ttevistener implements etionvistener{ puli void tionerformed@etionivent eA { ystemFoutFprintln@4soure X 4 C @@tdiofuttonAeFgetoure@AAFgetext@A C 4 E tt X 4 C @@tdiofuttonAeFgetoure@AAFiseleted@AAY } }

Le rsultat est reprsent en gure 26.8.

Figure

26.8  Test avec un groupe de boutons

Vous pouvez voir que cet objet s'utilise de la mme manire que le prcdent. Le problme, ici, c'est que nous pouvons slectionner les deux options (alors que ce n'est normalement pas possible). . . Pour qu'un seul bouton radio soit slectionn la fois, nous devons dnir un groupe de boutons l'aide de ButtonGroup. Nous y ajouterons nos boutons radio, et seule une option pourra alors tre slectionne. 379

CHAPITRE 26. LES CHAMPS DE FORMULAIRE


GGves utres imports import jvxFswingFfuttonqroupY puli lss penetre extends tprme { GGves utres vriles privte futtonqroup g a new futtonqroup@AY puli penetre@A{ GGves utres instrutions jrIFseteleted@trueAY jrIFddetionvistener@new ttevistener@AAY jrPFddetionvistener@new ttevistener@AAY GGyn joute les outons u groupe gFdd@jrIAY gFdd@jrPAY topFdd@jrIAY topFdd@jrPAY ontinerFdd@topD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY } lss ttevistener implements etionvistener{ puli void tionerformed@etionivent eA { ystemFoutFprintln@4soure X 4 C jrIFgetext@A C 4 E tt X 4 C jrIFiseleted@AAY ystemFoutFprintln@4soure X 4 C jrPFgetext@A C 4 E tt X 4 C jrPFiseleted@AAY } }

Voyez le rsultat en gure 26.9.

Figure

26.9  Test des boutons radio

380

LES CHAMPS DE TEXTE : L'OBJET JTEXTFIELD

Les champs de texte : l'objet JTextField


Premire utilisation
Je pense que vous savez ce que vous avez faire. . . Si ce n'est pas dj fait, crez un nouveau projet contenant les classes habituelles. Comme l'indique le titre de cette partie, nous allons utiliser l'objet JTextField. Vous vous en doutez, cet objet propose lui aussi des mthodes de redimensionnement, de changement de couleur. . . De ce fait, je commence avec un exemple complet. Lisez et testez ce code :
GGves imports hituels import jvxFswingFtextpieldY puli lss penetre extends tprme { privte tnel ontiner a new tnel@AY privte textpield jtf a new textpield@4leur pr dfut4AY privte tvel lel a new tvel@4n textpield4AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY tnel top a new tnel@AY pont polie a new pont@4eril4D pontFfyvhD IRAY jtfFsetpont@polieAY jtfFsetreferredize@new himension@ISHD QHAAY jtfFsetporeground@golorFfviAY topFdd@lelAY topFdd@jtfAY ontinerFdd@topD fordervyoutFxyrAY thisFsetgontentne@ontinerAY thisFsetisile@trueAY }

Cela donne la gure 26.10.

Figure

26.10  Exemple de champ de texte

Nous pouvons initialiser le contenu avec la mthode setText(String str) ou le rcuprer grce la mthode getText(). Il existe un objet trs ressemblant celui-ci, 381

CHAPITRE 26. LES CHAMPS DE FORMULAIRE en un peu plus to. En fait, cet objet permet de crer un JTextField format pour recevoir un certain type de donnes saisies (date, pourcentage. . .). Voyons cela tout de suite.

Un objet plus restrictif : le

JFormattedTextField

Grce ce type d'objet, nous pourrons viter beaucoup de contrles et de casts sur le contenu de nos zones de texte. Si vous avez essay de rcuprer le contenu du JTextField utilis ci-dessus (lors du clic sur un bouton, par exemple), vous avez d vous rendre compte que le texte qu'il contenait importait peu, mais un jour, vous aurez sans doute besoin d'une zone de texte qui n'accepte qu'un certain type de donnes. Avec l'objet JFormattedTextField, nous nous en approchons (mais vous verrez que vous pourrez faire encore mieux). Cet objet retourne une valeur uniquement si celle-ci correspond ce que vous avez autoris. Je m'explique : si vous voulez que votre zone de texte contienne par exemple des entiers et rien d'autre, c'est possible ! En revanche, ce contrle ne s'eectue que lorsque vous quittez le champ en question. Vous pouvez ainsi saisir des lettres dans un objet n'acceptant que des entiers, mais la mthode getText() ne renverra alors rien, car le contenu sera eac, les donnes ne correspondent pas aux attentes de l'objet. Voici un code et deux exemples, ainsi que leur rendu (gure 26.11).
GGves imports hituels puli lss penetre extends tprme { privte tnel ontiner a new tnel@AY privte tpormttedextpield jtf a new tpormttedextpield@xumerpormtFgetsntegersnstne@AAY privte tpormttedextpield jtfP a new tpormttedextpield@xumerpormtFgeterentsnstne@AAY privte tvel lel a new tvel@4n textpield4AY privte tfutton a new tfutton @4yu4AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY tnel top a new tnel@AY pont polie a new pont@4eril4D pontFfyvhD IRAY jtfFsetpont@polieAY jtfFsetreferredize@new himension@ISHD QHAAY jtfFsetporeground@golorFfviAY jtfPFsetreferredize@new himension@ISHD QHAAY Fddetionvistener@new foutonvistener@AAY topFdd@lelAY topFdd@jtfAY topFdd@jtfPAY

382

LES CHAMPS DE TEXTE : L'OBJET JTEXTFIELD


topFdd@AY thisFsetgontentne@topAY thisFsetisile@trueAY

lss foutonvistener implements etionvistener{ puli void tionerformed@etionivent eA { ystemFoutFprintln@4i X jtf 4 C jtfFgetext@AAY ystemFoutFprintln@4i X jtfP 4 C jtfPFgetext@AAY } }

Figure

26.11  Exemple valide gauche et invalide droite

Vous voyez qu'en plus, notre objet met automatiquement la saisie en forme lorsqu'elle est valide : il espace les nombres tous les trois chires an d'en faciliter la lecture. Voici ce que vous pouvez utiliser dans ce genre de champ :  NumberFormat avec  getIntegerInstance()  getPercentInstance()  getNumberInstance()  DateFormat avec  getTimeInstance()  getDateInstance()  MessageFormat Sans entrer dans les dtails, vous pouvez aussi utiliser un objet MaskFormatter qui permet d'attribuer un format de longueur xe votre zone de texte. C'est trs pratique lorsque vous souhaitez introduire un numro de tlphone, un numro de scurit sociale. . . Vous devez dnir ce format avec un paramtre lors de l'instanciation du masque l'aide de mtacaractres. Ceux-ci indiquent votre objet MaskFormatter ce que le contenu de votre zone de texte contiendra. Voici la liste de ces mtacaractres :  # : indique un chire ;  ' : indique un caractre d'chappement ;  U : indique une lettre (les minuscules sont automatiquement changes en majuscules) ;  L : indique une lettre (les majuscules sont automatiquement changes en minuscules) ;  A : indique un chire ou une lettre ; 383

CHAPITRE 26. LES CHAMPS DE FORMULAIRE  ? : indique une lettre ;  * : indique que tous les caractres sont accepts ;  H : indique que tous les caractres hexadcimaux sont accepts (0 9, a f et A F).

L'instanciation d'un tel objet peut lever une ParseException. Vous devez donc l'entourer d'un bloc try{...}catch(ParseException e){...} .
Voici ce quoi ressemblerait un format tlphonique :
try{ wskpormtter tel a new wskpormtter@455 55 55 55 554AY GGyu enore wskpormtter telP a new wskpormtter@455E55E55E55E554AY GGous pouvez ensuite le psser votre zone de texte tpormttedextpield jtf a new tpormttedextpield@telPAY }th@rseixeption eA{eFprinttkre@AY}

Vous voyez qu'il n'y a l rien de compliqu. . . Je vous invite essayer cela dans le code prcdent, vous constaterez qu'avec le mtacaractre utilis dans notre objet MaskFormatter, nous sommes obligs de saisir des chires. La gure 26.12 montre le rsultat aprs avoir cliqu sur le bouton.

Figure

26.12  Essai avec un MaskFormatter

Je ne sais pas pour le numro de tlphone amricain, mais le numro franais est loin d'tre un numro de tlphone valide. Nous voici confronts un problme qui nous hantera tant que nous programmerons : l'intgrit de nos donnes ! Comme le montre l'exemple prcdent, nous pouvons suggrer l'utilisateur ce qu'il doit renseigner comme donnes dans les champs, mais nous ne devons pas leur faire aveuglment conance ! C'est simple : on part du principe de ne jamais faire conance l'utilisateur. Nous sommes donc obligs d'eectuer une multitude de contrles supplmentaires. Pour ce faire, nous pouvons : 384

CONTRLE DU CLAVIER : L'INTERFACE KEYLISTENER  tester chaque lment du numro ;  tester le numro en entier ;  dans le cas o nous n'utilisons pas de MaskFormatter, vrier en plus que les saisies sont numriques ;  utiliser une expression rgulire ;  empcher la saisie d'un type de caractres ;  etc. En gros, nous devons vrier l'intgrit de nos donnes (dans le cas qui nous intresse, l'intgrit de nos chanes de caractres) pendant ou aprs la saisie. Je ne vous cache pas que cela prendra une grande part de votre temps lorsque vous coderez vos propres logiciels, mais c'est le mtier qui veut a. Avant de terminer ce chapitre (assez consquent, je l'avoue), je vous propose de voir comment nous pouvons rcuprer les vnements du clavier. Nous avons appris interagir avec la souris, mais pas avec le clavier.

Contrle du clavier : l'interface KeyListener


Nous connaissons dj :  l'interface MouseListener qui interagit avec la souris ;  l'interface ActionListener qui interagit lors d'un clic sur un composant ;  l'interface ItemListener qui coute les vnements sur une liste droulante. Voici prsent l'interface KeyListener. Comme l'indique le titre, elle nous permet d'intercepter les vnements clavier lorsque l'on :  presse une touche ;  relche une touche ;  tape sur une touche. Vous savez ce qu'il vous reste faire : crer une implmentation de cette interface dans votre projet. Crez une classe interne qui l'implmente et utilisez l'astuce d'Eclipse pour gnrer les mthodes ncessaires. Vous constatez qu'il y en a trois :  keyPressed(KeyEvent event), appele lorsqu'on presse une touche ;  keyReleased(KeyEvent event), appele lorsqu'on relche une touche (c'est ce moment que le composant se voit aecter la valeur de la touche) ;  keyTyped(KeyEvent event), appele entre les deux mthodes cites ci-dessus. Comme vous vous en doutez, l'objet KeyEvent nous permettra d'obtenir des informations sur les touches qui ont t utilises. Parmi celles-ci, nous utiliserons :  getKeyCode() : retourne le code de la touche ;  getKeyChar() : retourne le caractre correspondant la touche. Nous pouvons aussi dterminer lorsque certaines touches de contrle ont t utilises (SHIFT, CTRL. . .), connatre le composant l'origine de l'vnement, etc. Nous n'en parlerons pas ici, mais ce genre d'information est facile trouver sur Internet. 385

CHAPITRE 26. LES CHAMPS DE FORMULAIRE Pour des raisons de simplicit, nous n'utiliserons pas un JFormattedTextField mais un JTextField sans MaskFormatter. Ainsi, nous n'aurons pas nous proccuper des tirets de notre champ. Pour commencer, nous allons examiner l'ordre dans lequel se droulent les vnements clavier ; il est vrai que ceux-ci se produisent si rapidement que nous n'avons pas le temps de les voir dler. J'ai donc ajout une pause la n de chaque mthode de l'implmentation an de mieux observer l'ordre d'excution. Voici le code source que nous allons utiliser (il est presque identique aux prcdents, rassurez-vous) :
import import import import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFhimensionY jvFwtFpontY jvFwtFeventFueyiventY jvFwtFeventFueyvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY jvxFswingFtextpieldY

puli lss penetre extends tprme { privte privte privte privte tnel ontiner a new tnel@AY textpield jtfY tvel lel a new tvel@4lphone p4AY tfutton a new tfutton @4yu4AY

puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD ISHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY jtf a new textpield@AY tnel top a new tnel@AY pont polie a new pont@4eril4D pontFfyvhD IRAY jtfFsetpont@polieAY jtfFsetreferredize@new himension@ISHD QHAAY jtfFsetporeground@golorFfviAY GGyn joute l9outeur notre omposnt jtfFddueyvistener@new glviervistener@AAY topFdd@lelAY topFdd@jtfAY

386

CONTRLE DU CLAVIER : L'INTERFACE KEYLISTENER


topFdd@AY thisFsetgontentne@topAY thisFsetisile@trueAY

lss glviervistener implements ueyvistener{ puli void keyressed@ueyivent eventA { ystemFoutFprintln@4gode touhe presse X 4 C eventFgetueygode@A C 4 E rtre touhe presse X 4 C eventFgetueyghr@AAY puse@AY } puli void keyelesed@ueyivent eventA { ystemFoutFprintln@4gode touhe relhe X 4 C eventFgetueygode@A C 4 E rtre touhe relhe X 4 C eventFgetueyghr@AAY puse@AY } puli void keyyped@ueyivent eventA { ystemFoutFprintln@4gode touhe tpe X 4 C eventFgetueygode@A C 4 E rtre touhe tpe X 4 C eventFgetueyghr@AAY puse@AY }

privte void puse@A{ try { hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY } } puli stti void min@tring rgsA{ new penetre@AY }

La gure 26.13 ache une petite srie d'essais de ce code. Vous pouvez maintenant vous rendre compte de l'ordre dans lequel les vnements du clavier sont grs : en premier, lorsqu'on presse la touche, en deuxime, lorsqu'elle est tape, et enn, lorsqu'elle est relche. Dans le cas qui nous intresse, nous souhaitons que lorsque l'utilisateur saisit un caractre interdit, celui-ci soit automatiquement retir de la zone de saisie. Pour cela, nous procderons un traitement spcique dans la mthode keyReleased(KeyEvent event). 387

CHAPITRE 26. LES CHAMPS DE FORMULAIRE

Figure

26.13  Premier test de l'interface KeyListener

Si vous avez eectu beaucoup de tests de touches, vous avez d remarquer que les codes des touches correspondant aux chires du pav numrique sont compris entre 96 et 105. partir de l, c'est simple : il nous sut de supprimer le caractre tap de la zone de saisie si son code n'est pas compris dans cet intervalle. Toutefois, un problme se pose avec cette mthode : ceux qui possdent un ordinateur portable sans pav numrique ne pourront rien saisir alors qu'il est possible d'obtenir des chires en appuyant sur MAJ + &, , ', ( ou -. Ce souci nous amne opter pour une autre solution : nous crerons une mthode dont le type de retour sera un boolen nous indiquant si la saisie est numrique ou non. Comment ? Tout simplement en excutant un Integer.parseInt(value) , le tout envelopp dans un try{...}catch(NumberFormatException ex){} . Si nous essayons de convertir un caractre  a  en entier, l'exception sera leve et nous retournerons alors false (true dans le cas contraire).

La mthode parseInt() prend un String en paramtre. La mthode getKeyChar(), elle, renvoie un char. Il faudra donc penser faire la conversion. . .
Voici notre implmentation quelque peu modie :
lss glviervistener implements ueyvistener{ puli void keyelesed@ueyivent eventA { if@3isxumeri@eventFgetueyghr@AAA jtfFsetext@jtfFgetext@AFreple @tringFvlueyf@eventFgetueyghr@AAD 44AAY }

388

CONTRLE DU CLAVIER : L'INTERFACE KEYLISTENER


GGsnutile de redfinir es mthodes GGxous n9en vons plus l9utilit 3 puli void keyressed@ueyivent eventA {} puli void keyyped@ueyivent eventA {} GGetourne true si le prmtre est numrique GGetourne flse dns le s ontrire privte oolen isxumeri@hr rA{ try { sntegerFprsesnt@tringFvlueyf@rAAY } th @xumerpormtixeption eA { return flseY } return trueY }

Vous vous apercevez que les lettres simples sont dsormais interdites la saisie : mission accomplie ! Cependant, les caractres spciaux comme  ,  , etc. ne sont pas pris en charge par cette mthode. . . Par consquent, leur saisie reste possible.

En rsum
 L'objet JComboBox se trouve dans le package javax.swing.  Vous pouvez ajouter des lments dans une liste avec la mthode addItem(Object obj).  Vous pouvez aussi instancier une liste avec un tableau de donnes.  L'interface ItemListener permet de grer les tats de vos lments.  Vous pouvez aussi utiliser l'interface ActionListener.  La mthode getSelectedItem() retourne une variable de type Object : pensez donc eectuer un cast, ou utiliser la mthode toString() si les lments sont des chanes de caractres.  Les objets JCheckBox, JRadioButton et ButtonGroup sont prsents dans le package javax.swing.  Vous pouvez dterminer si l'un de ces composants est slectionn grce la mthode isSelected(). Cette mthode retourne true si l'objet est slectionn, false dans le cas contraire.  Vous pouvez restreindre le nombre de choix un parmi plusieurs rponses en utilisant la classe ButtonGroup.  Vous pouvez ajouter des boutons un groupe de boutons grce la mthode add(AbstractButton button) .  Par dfaut, un JTextField accepte tous les types de caractres.  Un JFormattedTextField correspond, pour simplier, un JTextField plus restrictif.  On peut restreindre la saisie dans ces objets en utilisant l'objet MaskFormatter. 389

CHAPITRE 26. LES CHAMPS DE FORMULAIRE  An de contrler les vnements clavier, l'utilisation d'une implmentation de l'interface KeyListener est ncessaire.

390

Chapitre

27
Dicult :

Les menus et botes de dialogue

oici deux lments trs utiles l'laboration de programmes orant plusieurs fonctionnalits que nous allons voir ici. Ces deux types d'objets se retrouvent souvent dans les direntes applications que vous pourrez trouver sur le Net. Vous verrez que la manire d'utiliser les menus ressemble beaucoup celle que vous avez dj vue et qu'il sufra de se familiariser avec l'objet pour pouvoir faire des choses sympa. Quant l'utilisation de botes de dialogue, c'est un peu particulier, mais tout aussi simple.

391

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE

Les botes de dialogue


Les botes de dialogue, c'est certain, vous connaissez ! Cependant, an de nous assurer que nous parlons de la mme chose, voici une petite description de ce qu'est une bote de dialogue. Il s'agit d'une petite fentre pouvant servir plusieurs choses :  acher une information (message d'erreur, d'avertissement. . .) ;  demander une validation, une rfutation ou une annulation ;  demander l'utilisateur de saisir une information dont le systme a besoin ;  ... Vous pouvez voir qu'elles peuvent servir beaucoup de choses. Il faut toutefois les utiliser avec parcimonie : il est assez pnible pour l'utilisateur qu'une application ouvre une bote de dialogue chaque notication, car toute bote ouverte doit tre ferme ! Pour ce point je vous laisse seuls juges de leur utilisation.

Les botes d'information


L'objet que nous allons utiliser tout au long de ce chapitre est le JOptionPane, un objet assez complexe au premier abord, mais fort pratique. La gure 27.1 vous montre quoi ressemblent des botes de dialogues  informatives .

Figure

27.1  Exemple de botes de dialogue

Ces botes ne sont pas destines participer de quelconques oprations : elles achent juste un message l'attention de l'utilisateur. Voici le code utilis pour obtenir ces botes :
typtionne jopID jopPD jopQY GGfote du messge d9informtion jopI a new typtionne@AY jopIFshowwessgehilog@nullD 4wessge informtif4D 4snformtion4D typtionneF sxpywesyxwieqiAY GGfote du messge prventif jopP a new typtionne@AY jopPFshowwessgehilog@nullD 4wessge prventif4D 4ettention4D typtionneF exsxqwieqiAY GGfote du messge d9erreur

392

LES BOTES DE DIALOGUE


jopQ a new typtionne@AY jopQFshowwessgehilog@nullD 4wessge d9erreur4D 4irreur4D typtionneF iywieqiAY

Ces trois botes ne s'achent pas en mme temps, tout simplement parce qu'en Java (mais aussi dans les autres langages), les botes de dialogue sont dites modales. Cela signie que lorsqu'une bote fait son apparition, celle-ci bloque toute interaction avec un autre composant, et ceci tant que l'utilisateur n'a pas mis n au dialogue ! Maintenant, voyons de plus prs comment construire un tel objet. Ici, nous avons utilis la mthode : showMessageDialog(Component parentComponent, String message, String title, int messageType); .  Component parentComponent : correspond au composant parent ; ici, il n'y en a aucun, nous mettons donc null.  String message : permet de renseigner le message acher dans la bote de dialogue.  String title : permet de donner un titre l'objet.  int messageType : permet de savoir s'il s'agit d'un message d'information, de prvention ou d'erreur. Vous avez sans doute remarqu que, mis part le texte et le titre, seul ce champ variait entre nos trois objets ! Il existe deux autres mthodes showMessageDialog() pour cet objet : une qui prend deux paramtres en moins (le titre et le type de message), et une qui prend un paramtre en plus (l'icne utiliser). Je pense qu'il est inutile de dtailler la mthode avec les paramtres en moins, mais voici des exemples de botes avec des icnes dnies par nos soins.
import jvxFswingFsmgesonY import jvxFswingFtyptionneY puli lss est { puli stti void min@tring rgsA { typtionne jopID jopPD jopQY jopI a new typtionne@AY smgeson img a new smgeson@4imgesGinformtionFpng4AY jopIFshowwessgehilog@nullD 4wessge informtif4D 4snformtion4D typtionneFsxpywesyxwieqiD imgAY jopP a new typtionne@AY img a new smgeson@4imgesGwrningFpng4AY jopPFshowwessgehilog@nullD 4wessge prventif4D 4ettention4D typtionneFexsxqwieqiD imgAY jopQ a new typtionne@AY img a new smgeson@4imgesGerreurFpng4AY jopQFshowwessgehilog@nullD 4wessge d9erreur4D 4irreur4D typtionneFiywieqiD imgAY } }

Ces images ont t trouves sur Google puis ranges dans un dossier  images  la 393

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE racine du projet Eclipse. Je vous invite tlcharger vos propres images et faire vos tests. Vous remarquerez aussi l'emploi de l'objet ImageIcon, qui lit le chier image l'emplacement spci dans son constructeur. La gure 27.2 reprsente le rsultat obtenu.

Figure

27.2  Image personnalise dans une bote de dialogue

Ce type de bote est trs utile pour signaler l'utilisateur qu'une opration s'est termine ou qu'une erreur est survenue. L'exemple le plus simple qui me vient en tte est le cas d'une division par zro : on peut utiliser une bote de dialogue dans le bloc catch. Voici les types de botes que vous pouvez acher (ces types restent valables pour tout ce qui suit).  JOptionPane.ERROR_MESSAGE  JOptionPane.INFORMATION_MESSAGE  JOptionPane.PLAIN_MESSAGE  JOptionPane.QUESTION_MESSAGE  JOptionPane.WARNING_MESSAGE Je pense que vous voyez dsormais l'utilit de telles botes de dialogue. Nous allons donc poursuivre avec les botes de conrmation.

Les botes de conrmation


Comme leur nom l'indique, ces dernires permettent de valider, d'invalider ou d'annuler une dcision. Nous utiliserons toujours l'objet JOptionPane, mais ce sera cette fois avec la mthode showConfirmDialog(), une mthode qui retourne un entier correspondant l'option que vous aurez choisie dans cette bote :  Yes ;  No ;  Cancel. Comme exemple, nous pouvons prendre notre animation dans sa version la plus rcente. Nous pourrions utiliser une bote de conrmation lorsque nous cliquons sur l'un des boutons contrlant l'animation ( Go ou Stop). Pour ceux qui n'auraient pas conserv leur projet, les sources compltes de cet exemple sont disponibles sur le Site du Zro. 394

LES BOTES DE DIALOGUE Copier les sources Code web : 872889  Voici les modications de notre classe Fenetre :
GGves utres imports n9ont ps hng import jvxFswingFtyptionneY puli lss penetre extends tprme{ privte nneu pn a new nneu@AY privte tfutton outon a new tfutton@4qo4AY privte tfutton outonP a new tfutton@4top4AY privte tnel ontiner a new tnel@AY privte tvel lel a new tvel@4ghoix de l forme4AY privte int ompteur a HY privte oolen nimted a trueY privte oolen kD kY privte int xDy Y privte hred tY privte tgomofox omo a new tgomofox@AY privte tghekfox morph a new tghekfox@4worphing4AY puli penetre@A{ GGien de hng ii } privte void go@A{ GGgette mthode n9 ps hng non plus } puli lss foutonvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { typtionne jop a new typtionne@AY int option a jopFshowgonfirmhilog@nullD 4oulezEvous lner l9nimtion c4D 4vnement de l9nimtion4D typtionneFixyysyxD typtionneFisyxwieqiAY if@option aa typtionneFyuysyxA{ nimted a trueY t a new hred@new lyenimtion@AAY tFstrt@AY outonFsetinled@flseAY outonPFsetinled@trueAY }

395

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


lss foutonPvistener implements etionvistener{ puli void tionerformed@etionivent eA { typtionne jop a new typtionne@AY int option a jopFshowgonfirmhilog@nullD 4oulezEvous rrter l9nimtion c4D 4errt de l9nimtion4D typtionneFixygexgivysyxD typtionneFisyxwieqiAY if@option 3a typtionneFxyysyx 88 option 3a typtionneFgexgivysyx 88 option 3a typtionneFgvyihysyxA{ nimted a flseY outonFsetinled@trueAY outonPFsetinled@flseAY

lss lyenimtion implements unnle{ puli void run@A { go@AY } } lss pormevistener implements etionvistener{ GGien de hng } lss worphvistener implements etionvistener{ GGien de hng }

Les instructions intressantes se trouvent ici :


GGFFF typtionne jop a new typtionne@AY int option a jopFshowgonfirmhilog@nullD 4oulezEvous lner l9nimtion c4D 4vnement de l9nimtion4D typtionneFixyysyxD typtionneFisyxwieqiAY if@option aa typtionneFyuysyxA{ nimted a trueY t a new hred@new lyenimtion@AAY tFstrt@AY outonFsetinled@flseAY outonPFsetinled@trueAY } GGFFF

396

LES BOTES DE DIALOGUE


GGFFF typtionne jop a new typtionne@AY int option a jopFshowgonfirmhilog@nullD 4oulezEvous rrter l9nimtion c4D 4errt de l9nimtion4D typtionneFixygexgivysyxD typtionneFisyxwieqiAY if@option 3a typtionneFxyysyx 88 option 3a typtionneFgexgivysyx 88 option 3a typtionneFgvyihysyxA{ nimted a flseY outonFsetinled@trueAY outonPFsetinled@flseAY }

Voyons ce qu'il se passe ici :  nous initialisons notre objet JOptionPane : rien d'tonnant ;  en revanche, plutt que d'acher directement la bote, nous aectons le rsultat que renvoie la mthode showConfirmDialog() une variable de type int ;  nous nous servons de cette variable an de savoir quel bouton a t cliqu (oui ou non). En fait, lorsque vous cliquez sur l'un des deux boutons prsents dans cette bote, vous pouvez aecter une valeur de type int :  correspondant l'entier JOptionPane.OK_OPTION , qui vaut 0 1 ;  correspondant l'entier JOptionPane.NO_OPTION , qui vaut 1 ;  correspondant l'entier JOptionPane.CANCEL_OPTION pour la bote apparaissant lors du clic sur  Stop , qui vaut 2 ;  correspondant l'entier JOptionPane.CLOSED_OPTION pour la mme bote que cidessus et qui vaut -1. En eectuant un test sur la valeur de notre entier, nous pouvons en dduire le bouton sur lequel on a cliqu et agir en consquence ! La gure 27.3 reprsente deux copies d'cran du rsultat obtenu.

Les botes de saisie


Je suis sr que vous avez devin quoi peuvent servir ces botes. . . Oui, tout fait, nous allons pouvoir y saisir du texte ! Et mieux encore : nous pourrons mme obtenir une bote de dialogue qui propose des choix dans une liste droulante. Vous savez dj que nous allons utiliser l'objet JOptionPane, et les plus curieux d'entre vous ont srement d jeter un il aux autres mthodes proposes par cet objet. . . Ici, nous allons utiliser la mthode showInputDialog(Component parent, String message, String title, int messageType) , qui retourne une chane de caractres. Voici un code la mettant en uvre et la gure 27.4 reprsentant son rsultat :
1. JOptionPane.YES_OPTION a la mme valeur.

397

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE

Figure

27.3  JOptionPane avec notre animation

import jvxFswingFtyptionneY puli lss est { puli stti void min@tring rgsA { typtionne jop a new typtionne@AD jopP a new typtionne@AY tring nom a jopFshowsnputhilog@nullD 4euillez dliner votre identit 34D 4qendrmerie ntionle 34D typtionneFisyxwieqiAY jopPFshowwessgehilog@nullD 4otre nom est 4 C nomD 4sdentit4D typtionneFsxpywesyxwieqiAY } }

Figure

27.4  Exemple de bote de saisie

Rien d'extraordinaire. . . Maintenant, voyons comment on intgre une liste dans une bote de ce genre. Vous allez voir, c'est simplissime !
import jvxFswingFtyptionneY puli lss est { puli stti void min@tring rgsA { tring sexe a {4msulin4D 4fminin4D 4indtermin4}Y typtionne jop a new typtionne@AD jopP a new typtionne@AY tring nom a @tringAjopFshowsnputhilog@nullD

398

LES BOTES DE DIALOGUE


4euillez indiquer votre sexe 34D 4qendrmerie ntionle 34D typtionneFisyxwieqiD nullD sexeD sexePAY jopPFshowwessgehilog@nullD 4otre sexe est 4 C nomD 4itt ivil4D typtionneFsxpywesyxwieqiAY

Ce code a pour rsultat la gure 27.5.

Figure

27.5  Liste dans une bote de dialogue

Voici un petit dtail des paramtres utiliss dans cette mthode :  les quatre premiers, vous connaissez ;  le deuxime null correspond l'icne que vous souhaitez passer ;  ensuite, vous devez passer un tableau de String an de remplir la combo (l'objet JComboBox) de la bote ;  le dernier paramtre correspond la valeur par dfaut de la liste droulante.

Cette mthode retourne un objet de type Object, comme si vous rcupriez la valeur directement dans la combo ! Du coup, n'oubliez pas de faire un cast.
Voici maintenant une variante de ce que vous venez de voir : nous allons utiliser ici la mthode showOptionDialog(). Celle-ci fonctionne peu prs comme la mthode prcdente, sauf qu'elle prend un paramtre supplmentaire et que le type de retour n'est pas un objet mais un entier. Ce type de bote propose un choix de boutons correspondant aux lments passs en paramtres (tableau de String) au lieu d'une combo ; elle prend aussi une valeur par dfaut, mais retourne l'indice de l'lment dans la liste au lieu de l'lment lui-mme. Je pense que vous vous y connaissez assez pour comprendre le code suivant :
import jvxFswingFtyptionneY puli lss est { puli stti void min@tring rgsA {

399

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


tring sexe a {4msulin4D 4fminin4D 4indtermin4}Y typtionne jop a new typtionne@AD jopP a new typtionne@AY int rng a jopFshowyptionhilog@nullD 4euillez indiquer votre sexe 34D 4qendrmerie ntionle 34D typtionneFixygexgivysyxD typtionneFisyxwieqiD nullD sexeD sexePAY jopPFshowwessgehilog@nullD 4otre sexe est 4 C sexerngD 4itt ivil4D typtionneFsxpywesyxwieqiAY

Ce qui nous donne la gure 27.6.

Figure

27.6  Bote multi-boutons

Voil, vous en avez termin avec les botes de saisie. Cependant, vous avez d vous demander s'il n'tait pas possible d'ajouter des composants ces botes. C'est vrai : vous pourriez avoir besoin de plus de renseignements, sait-on jamais. . . Je vous propose donc de voir comment crer vos propres botes de dialogue !

Des botes de dialogue personnalises


Je me doute que vous tes impatients de faire vos propres botes de dialogue. Comme il est vrai que dans certains cas, vous en aurez besoin, allons-y gaiement ! Je vais vous rvler un secret bien gard : les botes de dialogue hritent de la classe JDialog. Vous avez donc devin que nous allons crer une classe drive de cette dernire. Commenons par crer un nouveau projet. Crez une nouvelle classe dans Eclipse, appelons-la ZDialog, faites-la hriter de la classe cite ci-dessus, et mettez-y le code suivant :
import jvxFswingFthilogY import jvxFswingFtprmeY puli lss hilog extends thilog { puli hilog@tprme prentD tring titleD oolen modlA{ GGyn ppelle le onstruteur de thilog orrespondnt

400

LES BOTES DE DIALOGUE


super@prentD titleD modlAY GGyn spifie une tille thisFsetize@PHHD VHAY GGv position thisFsetvotioneltiveo@nullAY GGv ote ne devr ps tre redimensionnle thisFsetesizle@flseAY GGinfin on l9ffihe thisFsetisile@trueAY GGout ei ressemle e que nous fisons depuis le dut ve notre tprmeF

Maintenant, crons une classe qui va tester notre ZDialog :


import import import import import jvFwtFplowvyoutY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY

puli lss penetre extends tprme { privte tfutton outon a new tfutton@4eppel l hilog4AY puli penetre@A{ thisFsetitle@4w tprme4AY thisFsetize@QHHD IHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY thisFgetgontentne@AFsetvyout@new plowvyout@AAY thisFgetgontentne@AFdd@outonAY outonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { hilog zd a new hilog@nullD 4gouou les rys4D trueAY } }AY } thisFsetisile@trueAY

puli stti void min@tring minA{ penetre fen a new penetre@AY }

La gure 27.7 vous prsente le rsultat ; bon, c'est un dbut. Je pense que vous avez devin le rle des paramtres du constructeur, mais je vais tout de mme les expliciter : 401

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE

Figure

27.7  Votre premire bote personnalise

 JFrame Parent correspond l'objet parent ;  String title correspond au titre de notre bote ;  boolean modal correspond la modalit ; true : bote modale, false : bote non modale. Rien de compliqu. . . Il est donc temps d'ajouter des composants notre objet. Par contre, vous conviendrez que si nous prenons la peine de construire un tel composant, nous attendons plus qu'une simple rponse une question ouverte (oui/non), une chane de caractres ou encore un choix dans une liste. . . Nous en voulons bien plus ! Plusieurs saisies, avec plusieurs listes en mme temps ! Vous avez vu que nous devrons rcuprer les informations choisies dans certains cas, mais pas dans tous : nous allons donc devoir dterminer ces dirents cas, ainsi que les choses faire. Partons du fait que notre bote comprendra un bouton  OK  et un bouton  Annuler  : dans le cas o l'utilisateur clique sur  OK , on rcupre les informations, si l'utilisateur clique sur  Annuler , on ne rcupre rien. Et il faudra aussi tenir compte de la modalit de notre bote : la mthode setVisible(false); met n au dialogue ! Ceci signie galement que le dialogue s'entame au moment o l'instruction setVisible(true); est excute. C'est pourquoi nous allons sortir cette instruction du constructeur de l'objet et la mettre dans une mthode part. Maintenant, il faut que l'on puisse indiquer notre bote de renvoyer les informations ou non. C'est pour cela que nous allons utiliser un boolen  appelons-le sendData  initialis false, mais qui passera true si on clique sur  OK .
GGgs o notre hilog renverr le ontenu GGh9un textpield nomm jtf puli tring showhilog@A{ thisFsendht a flseY GGhut du dilogue thisFsetisile@trueAY GGve dilogue prend fin GGi on liqu sur yuD on envoieD sinon on envoie une hne vide 3 return @thisFsendhtAc jtfFgetext@A X 44Y }

Il nous reste un dernier point grer. . . 402

LES BOTES DE DIALOGUE

Comment rcuprer les informations saisies dans notre bote depuis notre fentre, vu que nous voulons obtenir plusieurs informations ?
C'est vrai qu'on ne peut retourner qu'une valeur la fois. . . Mais il peut y avoir plusieurs solutions ce problme.  Dans le cas o nous n'avons qu'un composant, nous pouvons adapter la mthode showZDialog() au type de retour du composant utilis.  Dans notre cas, nous voulons plusieurs composants, donc plusieurs valeurs. Vous pouvez :  retourner une collection de valeurs ( ArrayList) ;  faire des accesseurs dans votre ZDialog ;  crer un objet dont le rle est de collecter les informations dans votre bote et de retourner cet objet ;  ... Nous allons opter pour un objet qui collectera les informations et que nous retournerons la n de la mthode showZDialog(). Avant de nous lancer dans sa cration, nous devons savoir ce que nous allons mettre dans notre bote. . . J'ai choisi de vous faire programmer une bote permettant de spcier les caractristiques d'un personnage de jeu vido :  son nom (un champ de saisie) ;  son sexe (une combo) ;  sa taille (un champ de saisie) ;  sa couleur de cheveux (une combo) ;  sa tranche d'ge (des boutons radios).

Pour ce qui est du placement des composants, l'objet JDialog se comporte exactement comme un objet JFrame (BorderLayout par dfaut, ajout d'un composant au conteneur. . .).
Nous pouvons donc crer notre objet contenant les informations de notre bote de dialogue, je l'ai appel ZDialogInfo. Copier ces codes Code web : 298393 


puli lss hilogsnfo { privte tring nomD sexeD geD heveuxD tilleY puli hilogsnfo@A{} puli hilogsnfo@tring nomD tring sexeD tring geD tring heveuxD tring tilleA{ thisFnom a nomY thisFsexe a sexeY thisFge a geY thisFheveux a heveuxY

403

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


thisFtille a tilleY

puli tring totring@A{ tring strY if@thisFnom 3a null 88 thisFsexe 3a null 88 thisFtille 3a null 88 thisFge 3a null 88 thisFheveux 3a nullA{ str a 4hesription de l9ojet snfohilog4Y str Ca 4xom X 4 C thisFnom C 4n4Y str Ca 4exe X 4 C thisFsexe C 4n4Y str Ca 4ege X 4 C thisFge C 4n4Y str Ca 4gheveux X 4 C thisFheveux C 4n4Y str Ca 4ille X 4 C thisFtille C 4n4Y } else{ str a 4euune informtion 34Y } return strY }

L'avantage avec cette mthode, c'est que nous n'avons pas nous soucier d'une ventuelle annulation de la saisie : l'objet d'information renverra toujours quelque chose. Voici le code source de notre bote perso :
import import import import import import import import import import import import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvFwtFhimensionY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFforderptoryY jvxFswingFsmgesonY jvxFswingFtfuttonY jvxFswingFtgomofoxY jvxFswingFthilogY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtnelY jvxFswingFtdiofuttonY jvxFswingFfuttonqroupY jvxFswingFtextpieldY

puli lss hilog extends thilog { privte hilogsnfo zsnfo a new hilogsnfo@AY privte oolen sendhtY privte tvel nomvelD sexevelD heveuxvelD gevelD tillevelD tillePvelD ionY privte tdiofutton trnheID trnhePD trnheQD trnheRY

404

LES BOTES DE DIALOGUE


privte tgomofox sexeD heveuxY privte textpield nomD tilleY puli hilog@tprme prentD tring titleD oolen modlA{ super@prentD titleD modlAY thisFsetize@SSHD PUHAY thisFsetvotioneltiveo@nullAY thisFsetesizle@flseAY thisFsethefultgloseypertion@thilogFhyxyrsxqyxgvyiAY thisFinitgomponent@AY } puli hilogsnfo showhilog@A{ thisFsendht a flseY thisFsetisile@trueAY return thisFzsnfoY } privte void initgomponent@A{ GGsne ion a new tvel@new smgeson@4imgesGioneFjpg4AAY tnel pnson a new tnel@AY pnsonFsetfkground@golorFwhiteAY pnsonFsetvyout@new fordervyout@AAY pnsonFdd@ionAY GGve nom tnel pnxom a new tnel@AY pnxomFsetfkground@golorFwhiteAY pnxomFsetreferredize@new himension@PPHD THAAY nom a new textpield@AY nomFsetreferredize@new himension@IHHD PSAAY pnxomFsetforder@forderptoryFreteitledforder@4xom du personnge4AAY nomvel a new tvel@4isir un nom X4AY pnxomFdd@nomvelAY pnxomFdd@nomAY GGve sexe tnel pnexe a new tnel@AY pnexeFsetfkground@golorFwhiteAY pnexeFsetreferredize@new himension@PPHD THAAY pnexeFsetforder@forderptoryFreteitledforder@4exe du personnge4AAY sexe a new tgomofox@AY sexeFddstem@4wsulin4AY sexeFddstem@4pminin4AY sexeFddstem@4sndtermin4AY sexevel a new tvel@4exe X 4AY pnexeFdd@sexevelAY pnexeFdd@sexeAY

405

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE

GGv9ge tnel pnege a new tnel@AY pnegeFsetfkground@golorFwhiteAY pnegeFsetforder@forderptoryFreteitledforder@4ege du personnge4AAY pnegeFsetreferredize@new himension@RRHD THAAY trnheI a new tdiofutton@4IS E PS ns4AY trnheIFseteleted@trueAY trnheP a new tdiofutton@4PT E QS ns4AY trnheQ a new tdiofutton@4QT E SH ns4AY trnheR a new tdiofutton@4C de SH ns4AY futtonqroup g a new futtonqroup@AY gFdd@trnheIAY gFdd@trnhePAY gFdd@trnheQAY gFdd@trnheRAY pnegeFdd@trnheIAY pnegeFdd@trnhePAY pnegeFdd@trnheQAY pnegeFdd@trnheRAY GGv tille tnel pnille a new tnel@AY pnilleFsetfkground@golorFwhiteAY pnilleFsetreferredize@new himension@PPHD THAAY pnilleFsetforder@forderptoryF reteitledforder@4ille du personnge4AAY tillevel a new tvel@4ille X 4AY tillePvel a new tvel@4 m4AY tille a new textpield@4IVH4AY tilleFsetreferredize@new himension@WHD PSAAY pnilleFdd@tillevelAY pnilleFdd@tilleAY pnilleFdd@tillePvelAY GGv ouleur des heveux tnel pngheveux a new tnel@AY pngheveuxFsetfkground@golorFwhiteAY pngheveuxFsetreferredize@new himension@PPHD THAAY pngheveuxFsetforder@forderptoryF reteitledforder@4gouleur de heveux du personnge4AAY heveux a new tgomofox@AY heveuxFddstem@4flond4AY heveuxFddstem@4frun4AY heveuxFddstem@4oux4AY heveuxFddstem@4fln4AY heveuxvel a new tvel@4gheveux4AY pngheveuxFdd@heveuxvelAY pngheveuxFdd@heveuxAY

406

LES BOTES DE DIALOGUE

tnel ontent a new tnel@AY ontentFsetfkground@golorFwhiteAY ontentFdd@pnxomAY ontentFdd@pnexeAY ontentFdd@pnegeAY ontentFdd@pnilleAY ontentFdd@pngheveuxAY tnel ontrol a new tnel@AY tfutton okfouton a new tfutton@4yu4AY okfoutonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { zsnfo a new hilogsnfo@nomFgetext@AD @tringAsexeFgeteletedstem@AD getege@AD @tringAheveuxFgeteletedstem@A Dgetille@AAY setisile@flseAY } puli tring getege@A{ return @trnheIFiseleted@AA @trnhePFiseleted@AA @trnheQFiseleted@AA @trnheRFiseleted@AA trnheIFgetext@AY } c c c c trnheIFgetext@A trnhePFgetext@A trnheQFgetext@A trnheRFgetext@A X X X X

}AY

puli tring getille@A{ return @tilleFgetext@AFequls@44AA c 4IVH4 X tilleFgetext@AY }

tfutton nelfouton a new tfutton@4ennuler4AY nelfoutonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { setisile@flseAY } }AY ontrolFdd@okfoutonAY ontrolFdd@nelfoutonAY thisFgetgontentne@AFdd@pnsonD fordervyoutFiAY thisFgetgontentne@AFdd@ontentD fordervyoutFgixiAY thisFgetgontentne@AFdd@ontrolD fordervyoutFyrAY

J'ai ajout une image, mais vous n'y tes nullement obligs ! Voici le code source per407

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE mettant de tester cette bote :
import import import import import import jvFwtFplowvyoutY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtyptionneY

puli lss penetre extends tprme { privte tfutton outon a new tfutton@4eppel l hilog4AY puli penetre@A{ thisFsetitle@4w tprme4AY thisFsetize@QHHD IHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY thisFgetgontentne@AFsetvyout@new plowvyout@AAY thisFgetgontentne@AFdd@outonAY outonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { hilog zd a new hilog@nullD 4gouou les rys4D trueAY hilogsnfo zsnfo a zdFshowhilog@AY typtionne jop a new typtionne@AY jopFshowwessgehilog@nullD zsnfoFtotring@AD 4snformtions personnge4D typtionneFsxpywesyxwieqiAY } }AY thisFsetisile@trueAY } puli stti void min@tring minA{ penetre fen a new penetre@AY }

Ce qu'on obtient est montr la gure 27.8. Voil : nous venons de voir comment utiliser des botes de dialogue. En route pour l'utilisation des menus, prsent !

Les menus
Faire son premier menu
Vous vous rappelez que j'ai mentionn qu'une MenuBar fait partie de la composition de l'objet JFrame. Le moment est venu pour vous d'utiliser un composant de ce genre. Nanmoins, celui-ci appartient au package java.awt. Dans ce chapitre nous utiliserons 408

LES MENUS

Figure

27.8  Direntes copies d'cran de test

son homologue, l'objet JMenuBar, issu dans le package javax.swing. Pour travailler avec des menus, nous aurons besoin :  de l'objet JMenu, le titre principal d'un point de menu (Fichier, dition. . .) ;  d'objets JMenuItem, les lments composant nos menus. An de permettre des interactions avec nos futurs menus, nous allons devoir implmenter l'interface ActionListener que vous connaissez dj bien. Ces implmentations serviront couter les objets JMenuItem : ce sont ces objets qui dclencheront l'une ou l'autre opration. Les JMenu, eux, se comportent automatiquement : si on clique sur un titre de menu, celui-ci se droule tout seul et, dans le cas o nous avons un tel objet prsent dans un autre JMenu, une autre liste se droulera toute seule ! Je vous propose d'enlever tous les composants (boutons, combos, etc.) de notre animation et de grer tout cela par le biais d'un menu. Avant de nous lancer dans cette tche, voici une application de tout cela, histoire de vous familiariser avec les concepts et leur syntaxe.
import import import import import import import jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFfuttonqroupY jvxFswingFtghekfoxwenustemY jvxFswingFtprmeY jvxFswingFtwenuY jvxFswingFtwenufrY

409

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


import jvxFswingFtwenustemY import jvxFswingFtdiofuttonwenustemY puli lss penetre extends tprme { privte twenufr menufr a new twenufr@AY privte twenu testI a new twenu@4pihier4AY privte twenu testIP a new twenu@4ous fiher4AY privte twenu testP a new twenu@4idition4AY privte privte privte privte twenustem twenustem twenustem twenustem itemI itemP itemQ itemR a a a a new new new new twenustem@4yuvrir4AY twenustem@4permer4AY twenustem@4vner4AY twenustem@4errter4AY

privte tghekfoxwenustem jmiI a new tghekfoxwenustem@4ghoix I4AY privte tghekfoxwenustem jmiP a new tghekfoxwenustem@4ghoix P4AY privte tdiofuttonwenustem jrmiI a new tdiofuttonwenustem@4dio I4AY privte tdiofuttonwenustem jrmiP a new tdiofuttonwenustem@4dio P4AY puli stti void min@tring rgsA{ penetre zpen a new penetre@AY } puli penetre@A{ thisFsetize@RHHD PHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY GGyn initilise nos menus thisFtestIFdd@itemIAY GGyn joute les lments dns notre sousEmenu thisFtestIPFdd@jmiIAY thisFtestIPFdd@jmiPAY GGejout d9un sprteur thisFtestIPFddeprtor@AY GGyn met nos rdios dns un futtonqroup futtonqroup g a new futtonqroup@AY gFdd@jrmiIAY gFdd@jrmiIAY GGyn prsletionne l premire rdio jrmiIFseteleted@trueAY thisFtestIPFdd@jrmiIAY thisFtestIPFdd@jrmiPAY GGejout du sousEmenu dns notre menu thisFtestIFdd@thisFtestIPAY GGejout d9un sprteur

410

LES MENUS
thisFtestIFddeprtor@AY itemPFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { ystemFexit@HAY } }AY thisFtestIFdd@itemPAY thisFtestPFdd@itemQAY thisFtestPFdd@itemRAY GGv9ordre d9jout v dterminer l9ordre d9pprition GGdns le menu de guhe droite GGve premier jout ser tout guhe de l rre de menu et GGinversement pour le dernier thisFmenufrFdd@testIAY thisFmenufrFdd@testPAY thisFsettwenufr@menufrAY thisFsetisile@trueAY

L'action attache au JMenutItem  Fermer  permet de quitter l'application. Ce que donne le code est ach la gure 27.9.

Figure

27.9  Premier menu

Vous voyez qu'il n'y a rien de dicile dans l'laboration d'un menu. Je vous propose donc d'en crer un pour notre animation. Allons-y petit petit : nous ne grerons les vnements que par la suite. Pour le moment, nous allons avoir besoin :  d'un menu  Animation pour lancer, interrompre (par dfaut setEnabled(false)) ou quitter l'animation ;  d'un menu  Forme an de slectionner le type de forme utiliser (sous-menu + une radio par forme) et de permettre d'activer le mode morphing (case cocher) ;  d'un menu  propos avec un joli  ?  qui va ouvrir une bote de dialogue. N'eacez surtout pas les implmentations pour les vnements : retirez seulement les composants qui les utilisent. Ensuite, crez votre menu ! Voici un code qui ne devrait pas trop direr de ce que vous avez crit : 411

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE




Code du menu Code web : 432568 


import import import import import import import import import import import import import import import import import

jvFwtFfordervyoutY jvFwtFgolorY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFfuttonqroupY jvxFswingFtfuttonY jvxFswingFtghekfoxY jvxFswingFtghekfoxwenustemY jvxFswingFtgomofoxY jvxFswingFtprmeY jvxFswingFtvelY jvxFswingFtwenuY jvxFswingFtwenufrY jvxFswingFtwenustemY jvxFswingFtyptionneY jvxFswingFtnelY jvxFswingFtdiofuttonwenustemY

puli lss penetre extends tprme{ privte nneu pn a new nneu@AY privte tnel ontiner a new tnel@AY privte int ompteur a HY privte oolen nimted a trueY privte oolen kD kY privte int xDy Y privte hred tY privte twenufr menufr a new twenufr@AY privte twenu nimtion a new twenu@4enimtion4AD forme a new twenu@4porme4AD typeporme a new twenu@4ype de forme4AD ropos a new twenu@4 propos4AY privte twenustem rreter a new quitter a new roposstem a lner a new twenustem@4vner l9nimtion4AD twenustem@4errter l9nimtion4AD twenustem@4uitter4AD new twenustem@4c4AY

privte tghekfoxwenustem morph a new tghekfoxwenustem@4worphing4AY privte tdiofuttonwenustem rre a new tdiofuttonwenustem@4grr4AD rond a new tdiofuttonwenustem@4ond4AD tringle a new tdiofuttonwenustem@4ringle4AD etoile a new tdiofuttonwenustem@4itoile4AY privte futtonqroup g a new futtonqroup@AY

412

LES MENUS
puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY ontinerFdd@pnD fordervyoutFgixiAY thisFsetgontentne@ontinerAY thisFinitwenu@AY thisFsetisile@trueAY

privte void initwenu@A{ GGwenu nimtion nimtionFdd@lnerAY rreterFsetinled@flseAY nimtionFdd@rreterAY nimtionFddeprtor@AY GGour quitter l9pplition quitterFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eventA{ ystemFexit@HAY } }AY nimtionFdd@quitterAY GGwenu forme gFdd@rreAY gFdd@tringleAY gFdd@rondAY gFdd@etoileAY typepormeFdd@rondAY typepormeFdd@rreAY typepormeFdd@tringleAY typepormeFdd@etoileAY rondFseteleted@trueAY formeFdd@typepormeAY formeFdd@morphAY GGwenu propos roposFdd@roposstemAY GGejout des menus dns l rre de menus menufrFdd@nimtionAY

413

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


menufrFdd@formeAY menufrFdd@roposAY GGejout de l rre de menus sur l fentre thisFsettwenufr@menufrAY

privte void go@A{ GGien n9 hng ii } puli lss foutonvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { typtionne jop a new typtionne@AY int option a jopFshowgonfirmhilog@nullD 4oulezEvous lner l9nimtion c4D 4vnement de l9nimtion4D typtionneFixyysyxD typtionneFisyxwieqiAY if@option aa typtionneFyuysyxA{ lnerFsetinled@flseAY rreterFsetinled@trueAY nimted a trueY t a new hred@new lyenimtion@AAY tFstrt@AY }

lss foutonPvistener

implements etionvistener{

puli void tionerformed@etionivent eA { typtionne jop a new typtionne@AY int option a jopFshowgonfirmhilog@nullD 4oulezEvous rrter l9nimtion c4D 4errt de l9nimtion4D typtionneFixygexgivysyxD typtionneFisyxwieqiAY if@option 3a typtionneFxyysyx 88 option 3a typtionneFgexgivysyx 88 option 3a typtionneFgvyihysyxA{ nimted a flseY GGyn remple nos outons pr nos twenustem lnerFsetinled@trueAY rreterFsetinled@flseAY }

414

LES MENUS

lss lyenimtion implements unnle{ puli void run@A { go@AY } } lss pormevistener implements etionvistener{ puli void tionerformed@etionivent eA { GGyn ommente ette ligne pour l9instnt GGBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB GGpnFsetporme@omoFgeteletedstem@AFtotring@AAY } } lss worphvistener implements etionvistener{ puli void tionerformed@etionivent eA { GGi l se est oheD tivtion du mode morphing if@morphFiseleted@AApnFsetworph@trueAY GGinon rien 3 else pnFsetworph@flseAY } }

Vous devriez obtenir la gure 27.10.

Figure

27.10  Notre menu et son animation

Il ne reste plus qu' faire communiquer nos menus et notre animation ! Pour cela, rien de plus simple, il sut d'indiquer nos MenuItem qu'on les coute. En fait, cela revient faire comme si nous cliquions sur des boutons ( l'exception des cases cocher et des radios o, l, nous pouvons utiliser une implmentation d' ActionListener ou de ItemListener), nous utiliserons donc la premire mthode. An que l'application fonctionne bien, j'ai apport deux modications mineures dans la classe Panneau :  ajout d'une instruction dans une condition.
GGt9i jout X || thisFformeFequls@4ge4A if@thisFformeFequls@4gei4A || thisFformeFequls@4ge4AA{ gFfillet@posD posD SHD SHAY }

Ainsi, on accepte les deux graphies !

415

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE  ajout d'un toUpperCase().

Ainsi, on s'assure que cette chane de caractres est en majuscules. Voici le code de notre animation avec un beau menu pour tout contrler :


puli void setporme@tring formA{ thisFforme a formFtoppergse@AY }

Code de l'animation Code web : 210234 

GGves imports puli lss penetre extends tprme{ GGv dlrtion des vriles reste inhnge puli penetre@A{ GGve onstruteur est inhng } privte void initwenu@A{ GGwenu enimtion GGejout du listener pour lner l9nimtion lnerFddetionvistener@new trtenimtionvistener@AAY nimtionFdd@lnerAY GGejout du listener pour rrter l9nimtion rreterFddetionvistener@new topenimtionvistener@AAY rreterFsetinled@flseAY nimtionFdd@rreterAY nimtionFddeprtor@AY quitterFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eventA{ ystemFexit@HAY } }AY nimtionFdd@quitterAY GGwenu porme gFdd@rreAY gFdd@tringleAY gFdd@rondAY gFdd@etoileAY GGyn re un nouvel outeurD inutile de rer R instnes diffrentes pormevistener fl a new pormevistener@AY rreFddetionvistener@flAY rondFddetionvistener@flAY

416

LES MENUS
tringleFddetionvistener@flAY etoileFddetionvistener@flAY typepormeFdd@rondAY typepormeFdd@rreAY typepormeFdd@tringleAY typepormeFdd@etoileAY rondFseteleted@trueAY formeFdd@typepormeAY GGejout du listener pour le morphing morphFddetionvistener@new worphvistener@AAY formeFdd@morphAY GGwenu propos GGejout de e que doit fire le 4c4 roposstemFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { typtionne jop a new typtionne@AY smgeson img a new smgeson@4imgesGysoyFgif4AY tring mess a 4weri 3 n t9espre que vous vous musez ien 3 n4Y mess Ca 4te rois qu9il est temps d9jouter des lrteurs et des 4C4mnmoniques dns tout FFFn4Y mess Ca 4n ellezD qy les rys 34Y jopFshowwessgehilog@nullD messD 4 propos4D typtionneFsxpywesyxwieqiD imgAY } }AY roposFdd@roposstemAY GGejout des menus dns l rre de menus menufrFdd@nimtionAY menufrFdd@formeAY menufrFdd@roposAY GGejout de l rre de menus sur l fentre thisFsettwenufr@menufrAY

privte void go@A{ GGsdem } puli lss trtenimtionvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { GGsdem

417

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


}

GBB B outeur du menu uitter B duthor grery BG lss topenimtionvistener implements etionvistener{ puli void tionerformed@etionivent eA { GGsdem } } lss lyenimtion implements unnle{ puli void run@A { go@AY } } GBB B oute les menus porme B duthor grery BG lss pormevistener implements etionvistener{ puli void tionerformed@etionivent eA { pnFsetporme@@@tdiofuttonwenustemAeFgetoure@AAFgetext@AAY } } GBB B oute le menu worphing B duthor grery BG lss worphvistener implements etionvistener{ puli void tionerformed@etionivent eA { GGi l se est oheD tivtion du mode morphing if@morphFiseleted@AApnFsetworph@trueAY GGinon rien 3 else pnFsetworph@flseAY } }

Comme je l'ai indiqu dans le dialogue du menu  propos , je crois qu'il est temps d'ajouter des raccourcis clavier notre application ! Vous tes prts ? 418

LES MENUS

Les raccourcis clavier


nouveau, il est trs simple d'insrer des raccourcis clavier. Pour ajouter un  acclrateur  2 sur un JMenu, nous appellerons la mthode setAccelerator(); et pour ajouter un mnmonique 3 sur un JMenuItem, nous nous servirons de la mthode setMnemonic();. Attribuons le mnmonique  A  au menu  Animation , le mnmonique  F  pour le menu  Forme  et enn  P  pour  propos . Vous allez voir, c'est trs simple : il vous sut d'invoquer la mthode setMnemonic(char mnemonic); sur le JMenu que vous dsirez. Ce qui nous donne, dans notre cas :
privte void initwenu@A{ GGwenu nimtion GGve dut de l mthode reste inhng GGejout des menus dns l rre de menus et jout de mnmoniques 3 nimtionFsetwnemoni@9e9AY menufrFdd@nimtionAY formeFsetwnemoni@9p9AY menufrFdd@formeAY roposFsetwnemoni@99AY menufrFdd@roposAY GGejout de l rre de menus sur l fentre thisFsettwenufr@menufrAY

Nous avons prsent les lettres correspondant au mnmonique soulignes dans nos menus. Et il y a mieux : si vous tapez ALT + <la lettre>, le menu correspondant se droule ! La gure 27.11 correspond ce que j'obtiens.

Figure

27.11  Mnmonique sur votre menu

Sachez que vous pouvez aussi mettre des mnmoniques sur les objets JMenuItem. Je dois galement vous dire qu'il existe une autre faon d'ajouter un mnmonique sur un JMenu (mais c'est uniquement valable avec un JMenu) : en passant le mnmonique en deuxime paramtre du constructeur de l'objet, comme ceci JMenu menu = new JMenu("Fichier", 'F'); //Ici, ce menu aura le mnmonique F .
2. Raccourcis clavier des lments de menu 3. Raccourcis permettant de simuler le clic sur un point de menu.

419

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE Oui, je sais, c'est simple, trs simple, mme. Pour ajouter des acclrateurs, c'est quasiment pareil, si ce n'est que nous devrons utiliser un nouvel objet : KeyStroke. Cet objet permet de dterminer la touche utilise ou utiliser. C'est grce cet objet que nous allons pouvoir construire des combinaisons de touches pour nos acclrateurs ! Nous allons commencer par attribuer un simple caractre comme acclrateur notre JMenuItem  Lancer en utilisant la mthode getKeyStroke(char caracter); de l'objet KeyStroke. Ajoutez cette ligne de code au dbut de la mthode initMenu() (vous aurez besoin des packages javax.swing.KeyStroke et java.awt.event.ActionEvent ) :
GGgette instrution joute l9lrteur 99 notre ojet lnerFseteelertor@ueytrokeFgetueytroke@99AAY

Testez votre application, un petit  c  est apparu ct du menu  Lancer . La gure 27.12 illustre le phnomne.

Figure

27.12  Un acclrateur sur votre menu

Appuyez sur la touche  c  de votre clavier : celle-ci a le mme eet qu'un clic sur le menu  Lancer  !

Attention : si vous mettez le caractre  C , vous serez obligs d'appuyer

simultanment sur SHIFT

+ c

ou d'activer la touche MAJ !

Si le principe est bon, dites-vous aussi que maintenant, presser la touche c lancera systmatiquement votre animation ! C'est l'une des raisons pour laquelle les acclrateurs sont, en gnral, des combinaisons de touches du genre CTRL + c ou encore CTRL + SHIFT + S. Pour cela, nous allons utiliser une mthode getKeyStroke() un peu dirente : elle ne prendra pas le caractre de notre touche en argument, mais son code ainsi qu'une ou plusieurs touche(s) composant la combinaison. Pour obtenir le code d'une touche, nous utiliserons l'objet KeyEvent, un objet qui stocke tous les codes des touches ! Dans le code qui suit, je cre un acclrateur CTRL + L pour le menu  Lancer  et un acclrateur CTRL + SHIFT + A pour le menu  Arrter  :
lnerFseteelertor@ueytrokeFgetueytroke@ueyiventFuvD ueyiventFgvweuAAY nimtionFdd@lnerAY

420

LES MENUS
GGejout du listener pour rrter l9nimtion rreterFddetionvistener@new topenimtionvistener@AAY rreterFsetinled@flseAY rreterFseteelertor@ueytrokeFgetueytroke@ueyiventFueD ueyiventFgvhyxweu C ueyiventFrsphyxweuAAY nimtionFdd@rreterAY

La gure 27.13 prsente le rsultat obtenu.

Figure

27.13  Combinaison de touches pour un acclrateur

J'imagine que vous tes perturbs par KeyEvent.VK_L et les appels du mme genre. En fait, la classe KeyEvent rpertorie tous les codes de toutes les touches du clavier. Une grande majorit d'entre eux sont sous la forme VK_<le caractre ou le nom de la touche>. Lisez-le ainsi : Value of Key <nom de la touche>. part certaines touches de contrle comme CTRL, ALT, SHIFT. . . vous pouvez facilement retrouver le code d'une touche grce cet objet ! Ensuite, vous avez d remarquer qu'en tapant KeyEvent.CTRL_DOWN_MASK , Eclipse vous a propos quasiment la mme chose (gure 27.14).

Figure

27.14  Versions direntes

Vous pouvez aisment voir qu'Eclipse vous dit que la version CTRL_DOWN_MASK est la plus rcente et qu'il est vivement conseill de l'utiliser ! Vous voil donc avec un menu comprenant des mnmoniques et des acclrateurs. Il est maintenant temps de voir comment crer un menu contextuel !

Faire un menu contextuel


Vous avez dj fait le plus dur, je suis sr que vous n'allez pas tarder vous en rendre compte. Nous allons simplement utiliser un autre objet, un JPopupMenu, dans 421

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE lequel nous mettrons nos JMenuItem ou/et JMenu. Bon il faudra tout de mme indiquer notre menu contextuel comment et o s'acher, mais vous verrez que c'est trs simple. Maintenant que vous commencez bien connatre les bases de la programmation vnementielle, nous passons la vitesse suprieure !

Les points importants de notre menu contextuel


 Dans le cas d'oprations identiques celles accessibles par le menu, nous devrons crer des objets qui s'tendent ces deux menus.  Le menu contextuel ne doit s'acher que dans la zone o l'animation s'excute, pas dans le menu !  Il ne doit s'acher que lorsqu'on fait un clic droit, et rien d'autre ! Nous allons mettre dans notre menu contextuel les actions  Lancer l'animation ,  Arrter l'animation  ainsi que deux nouveauts :  changer la couleur du fond de notre animation ;  changer la couleur de notre forme. Avant d'implmenter les deux nouvelles fonctionnalits, nous allons travailler sur les deux premires. Lorsque nous lancerons l'animation, nous devrons mettre les deux menus  Lancer l'animation  dans l'tat setEnabled(false); et les deux menus  Arrter l'animation  dans l'tat setEnabled(true); (et pour l'arrter, il faudra faire l'inverse). Comme je vous l'ai dit plus haut, nous allons utiliser le mme objet qui coute pour les deux menus. Il nous faudra crer une vritable instance de ces objets et signaler l'application que ces objets coutent non seulement le menu du haut, mais aussi le menu contextuel. Nous avons parfaitement le droit de le faire : plusieurs objets peuvent couter un mme composant et plusieurs composants peuvent avoir le mme objet qui les coute ! Vous tes presque prts crer votre menu contextuel, il ne vous manque que ces informations :  comment indiquer notre panneau quand et o acher le menu contextuel ;  comment lui spcier qu'il doit le faire uniquement suite un clic droit. Le dclenchement de l'achage du pop-up doit se faire lors d'un clic de souris. Vous connaissez une interface qui gre ce type d'vnement : l'interface MouseListener. Nous allons donc indiquer notre panneau qu'un objet du type de cette interface va l'couter !

Tout comme dans le chapitre sur les zones de saisie, il existe une classe qui contient toutes les mthodes de ladite interface : la classe MouseAdapter. Vous pouvez implmenter celle-ci an de ne rednir que la mthode dont vous avez besoin ! C'est cette solution que nous allons utiliser.
Si vous prfrez, vous pouvez utiliser l'vnement mouseClicked, mais je pensais plutt mouseReleased(), pour une raison simple laquelle vous n'avez peut-tre pas pens : si ces deux vnements sont quasiment identiques, dans un certain cas, seul l'vnement mouseClicked() sera appel. Il s'agit du cas o vous cliquez sur une zone, dplacez 422

LES MENUS votre souris en dehors de la zone tout en maintenant le clic et relchez le bouton de la souris. C'est pour cette raison que je prfre utiliser la mthode mouseReleased(). Ensuite, pour prciser o acher le menu contextuel, nous allons utiliser la mthode show(Component invoker, int x, int y); de la classe JPopupMenu.  Component invoker : dsigne l'objet invoquant le menu contextuel, dans notre cas, l'instance de Panneau.  int x : coordonne x du menu.  int y : coordonne y du menu. Souvenez-vous que vous pouvez dterminer les coordonnes de la souris grce l'objet pass en paramtre de la mthode mouseReleased(MouseEvent event) . Je suis sr que vous savez comment vous y prendre pour indiquer au menu contextuel de s'acher et qu'il ne vous manque plus qu' dtecter le clic droit. C'est l que l'objet MouseEvent va vous sauver la mise ! En eet, il possde une mthode isPopupTrigger() qui renvoie vrai s'il s'agit d'un clic droit. Vous avez toutes les cartes en main pour laborer votre menu contextuel (rappelez-vous que nous ne grons pas encore les nouvelles fonctionnalits). Je vous laisse quelques instants de rexion. . . Vous avez ni ? Nous pouvons comparer nos codes ? Je vous invite consulter le code ci-dessous (il ne vous montre que les nouveauts). Copier ce code Code web : 962850 
GGves imports hituels import jvxFswingFtopupwenuY puli lss penetre extends tprme{ GGxos vriles hituelles GGv dlrtion pour le menu ontextuel privte topupwenu jpm a new topupwenu@AY privte twenu kground a new twenu@4gouleur de fond4AY privte twenu ouleur a new twenu@4gouleur de l forme4AY privte twenustem lunh a new twenustem@4vner l9nimtion4AY privte twenustem stop a new twenustem@4errter l9nimtion4AY privte twenustem rouge a new twenustem@4ouge4AD leu a new twenustem@4fleu4AD vert a new twenustem@4ert4AD rougefk a new twenustem@4ouge4AD leufk a new twenustem@4fleu4AD vertfk a new twenustem@4ert4AY GGyn re des listeners gloux privte topenimtionvistener stopenimtionanew topenimtionvistener@AY privte trtenimtionvistener strtenimtionanew trtenimtionvistener@AY

423

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY GGyn initilise le menu stop stopFsetinled@flseAY GGyn ffete les outeurs stopFddetionvistener@stopenimtionAY lunhFddetionvistener@strtenimtionAY GGyn re et on psse l9outeur pour ffiher le menu ontextuel GGgrtion d9une implmenttion de wouseedpter GGve redfinition de l mthode dqute pnFddwousevistener@new wouseedpter@A{ puli void mouseelesed@wouseivent eventA{ GGeulement s9il s9git d9un li droit GGif@eventFgetfutton@A aa wouseiventFfyxQA if@eventFisopuprigger@AA{ kgroundFdd@rougefkAY kgroundFdd@leufkAY kgroundFdd@vertfkAY ouleurFdd@rougeAY ouleurFdd@leuAY ouleurFdd@vertAY jpmFdd@lunhAY jpmFdd@stopAY jpmFdd@ouleurAY jpmFdd@kgroundAY GGv mthode qui v ffiher le menu jpmFshow@pnD eventFget@AD eventFget@AAY

}AY

ontinerFdd@pnD fordervyoutFgixiAY thisFsetgontentne@ontinerAY thisFinitwenu@AY thisFsetisile@trueAY } privte void initwenu@A{

424

LES MENUS
GGejout du listener pour lner l9nimtion GGeixsyxD vi vsixi i qvyfev 333 lnerFddetionvistener@strtenimtionAY GGyn ttriue l9lerteur lnerFseteelertor@ueytrokeFgetueytroke@ueyiventFuvD ueyiventFgvweuAAY nimtionFdd@lnerAY GGejout du listener pour rrter l9nimtion GGvsixi e grexqi sgs es rreterFddetionvistener@stopenimtionAY rreterFsetinled@flseAY rreterFseteelertor@ueytrokeFgetueytroke@ueyiventFueD ueyiventFgvhyxweu C ueyiventFrsphyxweuAAY nimtionFdd@rreterAY } GGve reste est inhng

privte void go@A{ GGv mthode n9 ps hng } puli lss trtenimtionvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { typtionne jop a new typtionne@AY int option a jopFshowgonfirmhilog@nullD 4oulezEvous lner l9nimtion c4D 4vnement de l9nimtion4D typtionneFixyysyxD typtionneFisyxwieqiAY if@option aa typtionneFyuysyxA{ lnerFsetinled@flseAY rreterFsetinled@trueAY GGyn joute l9instrution pour le menu ontextuel lunhFsetinled@flseAY stopFsetinled@trueAY nimted a trueY t a new hred@new lyenimtion@AAY tFstrt@AY

GBB B outeur du menu uitter

425

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


B duthor grery BG lss topenimtionvistener

implements etionvistener{

puli void tionerformed@etionivent eA { typtionne jop a new typtionne@AY int option a jopFshowgonfirmhilog@nullD 4oulezEvous rrter l9nimtion c4D 4errt de l9nimtion4D typtionneFixygexgivysyxD typtionneFisyxwieqiAY if@option 3a typtionneFxyysyx 88 option 3a typtionneFgexgivysyx 88 option 3a typtionneFgvyihysyxA{ nimted a flseY GGyn remple nos outons pr nos twenustem lnerFsetinled@trueAY rreterFsetinled@flseAY GGyn joute l9instrution pour le menu ontextuel lunhFsetinled@trueAY stopFsetinled@flseAY

lss lyenimtion implements unnle{ GGsnhng } lss pormevistener implements etionvistener{ GGsnhng } lss worphvistener implements etionvistener{ GGsnhng }

La gure 27.15 vous montre ce que j'obtiens. Il est beau, il est fonctionnel notre menu contextuel ! Je sens que vous tes prts pour mettre les nouvelles options en place, mme si je me doute que certains d'entre vous ont dj fait ce qu'il fallait. Allez, il n'est pas trs dicile de coder ce genre de choses (surtout que vous tes habitus, maintenant). Dans notre classe Panneau, nous utilisons des couleurs prdnies. Ainsi, il nous sut de mettre ces couleurs dans des variables et de permettre leur modication. Rien de dicile ici, voici donc les codes sources de nos deux classes. 426

LES MENUS

Figure

27.15  Menu contextuel

Copier ce code Code web : 628644 

Panneau.java
import jvFwtFgolorY GGves utres imports puli lss nneu extends tnel { GGves vriles dfinies uprvnt ne hngent ps GGyn y joute nos deux ouleurs privte golor ouleurporme a golorFredY privte golor ouleurpond a golorFwhiteY puli void pintgomponent@qrphis gA{ GGeffettion de l ouleur de fond gFsetgolor@ouleurpondAY gFfillet@HD HD thisFgetidth@AD thisFgetreight@AAY GGeffettion de l ouleur de l forme gFsetgolor@ouleurpormeAY GGi le mode morphing est tivD on peint le morphing if@thisFmorphA drwworph@gAY GGinonD mode norml else drw@gAY

GGwthode qui redfinit l ouleur du fond puli void setgouleurpond@golor olorA{ thisFouleurpond a olorY } GGwthode qui redfinit l ouleur de l forme puli void setgouleurporme@golor olorA{ thisFouleurporme a olorY }

427

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE

GGves utres mthodes sont inhnges }

Fenetre.java
GGxos imports hituels puli lss penetre extends tprme{ GGxos vriles n9ont ps hng GGyn re des listeners gloux privte topenimtionvistener stopenimtion a new topenimtionvistener@AY privte trtenimtionvistener strtenimtion a new trtenimtionvistener@A GGeve des listeners pour les ouleurs privte gouleurpondvistener ggolor a new gouleurpondvistener@AY privte gouleurpormevistener frmgolor a new gouleurpormevistener@AY puli penetre@A{ thisFsetitle@4enimtion4AY thisFsetize@QHHD QHHAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY ontinerFsetfkground@golorFwhiteAY ontinerFsetvyout@new fordervyout@AAY GGyn initilise le menu stop stopFsetinled@flseAY GGyn ffete les outeurs stopFddetionvistener@stopenimtionAY lunhFddetionvistener@strtenimtionAY GGyn ffete les outeurs ux points de menu rougeFddetionvistener@frmgolorAY leuFddetionvistener@frmgolorAY vertFddetionvistener@frmgolorAY lnFddetionvistener@frmgolorAY rougefkFddetionvistener@ggolorAY leufkFddetionvistener@ggolorAY vertfkFddetionvistener@ggolorAY lnfkFddetionvistener@ggolorAY GGyn re et on psse l9outeur pour ffiher le menu ontextuel GGgrtion d9une implmenttion de wouseedpter GGve redfinition de l mthode dqute pnFddwousevistener@new wouseedpter@A{ puli void mouseelesed@wouseivent eventA{

428

LES MENUS
GGeulement s9il s9git d9un li droit if@eventFisopuprigger@AA{ kgroundFdd@lnfkAY kgroundFdd@rougefkAY kgroundFdd@leufkAY kgroundFdd@vertfkAY ouleurFdd@lnAY ouleurFdd@rougeAY ouleurFdd@leuAY ouleurFdd@vertAY jpmFdd@lunhAY jpmFdd@stopAY jpmFdd@ouleurAY jpmFdd@kgroundAY GGv mthode qui v ffiher le menu jpmFshow@pnD eventFget@AD eventFget@AAY

}AY

ontinerFdd@pnD fordervyoutFgixiAY thisFsetgontentne@ontinerAY thisFinitwenu@AY thisFsetisile@trueAY

privte void initwenu@A{ GGve menu n9 ps hng } privte void go@A{ GGv mthode go@A est identique } GGves lsses internes X GG Eb trtenimtionvistener GG Eb topenimtionvistener GG Eb lyenimtion GG Eb pormevistener GG Eb worphvistener GGsont inhnges 3 GGoute le hngement de ouleur du fond lss gouleurpondvistener implements etionvistener{ puli void tionerformed@etionivent eA { if@eFgetoure@A aa vertfkA

429

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


pnFsetgouleurpond@golorFgreenAY else if @eFgetoure@A aa leufkA pnFsetgouleurpond@golorFlueAY else if@eFgetoure@A aa rougefkA pnFsetgouleurpond@golorFredAY else pnFsetgouleurpond@golorFwhiteAY

GGoute le hngement de ouleur du fond lss gouleurpormevistener implements etionvistener{ puli void tionerformed@etionivent eA { if@eFgetoure@A aa vertA pnFsetgouleurporme@golorFgreenAY else if @eFgetoure@A aa leuA pnFsetgouleurporme@golorFlueAY else if@eFgetoure@A aa rougeA pnFsetgouleurporme@golorFredAY else pnFsetgouleurporme@golorFwhiteAY } }

Et voici quelques rsultats obtenus (gure 27.16).

Figure

27.16  Changement de couleur via le menu contextuel

Vous conviendrez que les menus et les menus contextuels peuvent s'avrer vraiment utiles et ergonomiques ! En plus, ils sont relativement simples implmenter (et utiliser). Cependant, vous avez sans doute remarqu qu'il y a beaucoup de clics superus, que ce soit pour utiliser un menu ou menu contextuel : il faut au moins un clic pour acher leur contenu (sauf dans le cas de l'acclrateur). Pour contrer ce genre de chose, il existe un concept trs puissant : la barre d'outils ! 430

LES MENUS

Les barres d'outils


La gure 27.17 reprsente un exemple de barre d'outils (il s'agit de la partie encadre).

Figure

27.17  Exemple de barre d'outils

Pour faire simple, la barre d'outils sert eectuer des actions disponibles dans le menu, mais sans devoir fouiller dans celui-ci ou mmoriser le raccourci clavier (acclrateur) qui y est li. Elle permet donc des actions rapides. Elle est gnralement compose d'une multitude de boutons, une image appose sur chacun d'entre eux symbolisant l'opration qu'il peut eectuer. Pour crer et utiliser une barre d'outils, nous allons utiliser l'objet JToolBar. Je vous rassure tout de suite, cet objet fonctionne comme un menu classique, une dirence prs : celui-ci prend des boutons ( JButton) en arguments, et il n'y a pas d'endroit spcique o incorporer votre barre d'outils (il faudra l'expliciter lors de sa cration). Tout d'abord, il nous faut des images mettre sur nos boutons. . . J'en ai fait de toutes simples (gure 27.18), mais libre vous d'en choisir d'autres.

Figure

27.18  Images pour la barre d'outils

Au niveau des actions grer, pour le lancement de l'animation et l'arrt, il faudra penser diter le comportement des boutons de la barre d'outils comme on l'a fait pour les deux actions du menu contextuel. Concernant les boutons pour les formes, c'est un peu plus dlicat. Les autres composants qui ditaient la forme de notre animation taient des boutons radios. Or, ici, nous avons des boutons standard. Outre le fait qu'il va falloir une instance prcise de la classe FormeListener, nous aurons modier un peu son comportement. . . Il nous faut savoir si l'action vient d'un bouton radio du menu ou d'un bouton de la barre d'outils : c'est l'objet ActionEvent qui nous permettra d'accder cette information. Nous n'allons pas tester tous les boutons radio un par un, pour ces composants, le systme utilis jusque-l tait trs bien. Non, nous allons simplement vrier si celui qui a dclench l'action est un JRadioButtonMenuItem , et si c'est le cas, nous testerons les boutons. Rappelez-vous le chapitre sur la rexivit ! La mthode getSource() nous retourne un objet, il est donc possible de connatre la classe de celui-ci avec la mthode getClass() et par consquent d'en obtenir le nom grce la mthode getName(). Il va falloir qu'on pense mettre jour le bouton radio slectionn dans le menu. Et l, pour votre plus grand bonheur, je connais une astuce qui marche pas mal du tout : lors du clic sur un bouton de la barre d'outils, il sut de dclencher l'vnement sur le bouton radio correspondant ! Dans la classe AbstractButton, dont hritent tous 431

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE les boutons, il y a la mthode doClick(). Cette mthode dclenche un vnement identique un vrai clic de souris sur le composant ! Ainsi, plutt que de grer la mme faon de faire deux endroits, nous allons rediriger l'action eectue sur un composant vers un autre. Vous avez toutes les cartes en main pour raliser votre barre d'outils. N'oubliez pas que vous devez spcier sa position sur le conteneur principal ! Bon. Faites des tests, comparez, codez, eacez. . . au nal, vous devriez avoir quelque chose comme ceci : Copier ce code Code web : 400998 
import jvxFswingFtoolfrY GGxos imports hituels puli lss penetre extends tprme{ GGves vriles delres prdemment GGgrtion de notre rre d9outils privte toolfr toolfr a new toolfr@AY GGves outons de l rre d9outils privte tfutton ply a new tfutton@new smgeson@4imgesGplyFjpg4AAD nel a new tfutton@new smgeson@4imgesGstopFjpg4AAD squre a new tfutton@new smgeson@4imgesGrrFjpg4AAD tri a new tfutton@new smgeson@4imgesGtringleFjpg4AAD irle a new tfutton@new smgeson@4imgesGrondFjpg4AAD str a new tfutton@new smgeson@4imgesGtoileFjpg4AAY privte golor fondfouton a golorFwhiteY privte pormevistener fvistener a new pormevistener@AY puli penetre@A{ GGv seule nouveut est l mthode iEdessous thisFinitoolfr@AY thisFsetisile@trueAY } privte void initoolfr@A{ thisFnelFsetinled@flseAY thisFnelFddetionvistener@stopenimtionAY thisFnelFsetfkground@fondfoutonAY thisFplyFddetionvistener@strtenimtionAY thisFplyFsetfkground@fondfoutonAY thisFtoolfrFdd@plyAY thisFtoolfrFdd@nelAY thisFtoolfrFddeprtor@AY GGejout des visteners

432

LES MENUS
thisFirleFddetionvistener@fvistenerAY thisFirleFsetfkground@fondfoutonAY thisFtoolfrFdd@irleAY thisFsqureFddetionvistener@fvistenerAY thisFsqureFsetfkground@fondfoutonAY thisFtoolfrFdd@squreAY thisFtriFsetfkground@fondfoutonAY thisFtriFddetionvistener@fvistenerAY thisFtoolfrFdd@triAY thisFstrFsetfkground@fondfoutonAY thisFstrFddetionvistener@fvistenerAY thisFtoolfrFdd@strAY } thisFdd@toolfrD fordervyoutFxyrAY

privte void initwenu@A{ GGwthode inhnge } privte void go@A{ GGwthode inhnge } puli lss trtenimtionvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { GGoujours l mme ote de dilogueFFF if@option aa typtionneFyuysyxA{ lnerFsetinled@flseAY rreterFsetinled@trueAY GGyx etyi v9sxgsyx y vi wix gyxiiv GGBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB lunhFsetinled@flseAY stopFsetinled@trueAY plyFsetinled@flseAY nelFsetinled@trueAY nimted a trueY t a new hred@new lyenimtion@AAY tFstrt@AY

433

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE


GBB B outeur du menu uitter B duthor grery BG lss topenimtionvistener implements etionvistener{ puli void tionerformed@etionivent eA { GGoujours l mme ote de dilogueFFF if@option 3a typtionneFxyysyx 88 option 3a typtionneFgexgivysyx 88 option 3a typtionneFgvyihysyxA{ nimted a flseY GGyn remple nos outons pr nos wenustem lnerFsetinled@trueAY rreterFsetinled@flseAY GGyx etyi v9sxgsyx y vi wix gyxiiv GGBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB lunhFsetinled@trueAY stopFsetinled@flseAY plyFsetinled@trueAY nelFsetinled@flseAY

lss pormevistener implements etionvistener{ puli void tionerformed@etionivent eA { GGi l9tion vient d9un outon rdio du menu if@eFgetoure@AFgetglss@AFgetxme@A Fequls@4jvxFswingFtdiofuttonwenustem4AA pnFsetporme@@@tdiofuttonwenustemAeFgetoure@AAFgetext@AAY else{ if@eFgetoure@A aa squreA{ rreFdoglik@AY } else if@eFgetoure@A aa triA{ tringleFdoglik@AY } else if@eFgetoure@A aa strA{ etoileFdoglik@AY } else{ rondFdoglik@AY } }

434

LES MENUS
} GGves lsses internes X GG Eb gouleurpondvistener GG Eb gouleurpormevistener GG Eb lyenimtion GG Eb worphvistener GGsont inhnges 3 }

Vous devez obtenir une IHM semblable la gure 27.19.

Figure

27.19  Votre barre d'outils

Elle n'est pas jolie, votre IHM, maintenant ? Vous avez bien travaill, surtout qu' prsent, je vous explique peut-tre les grandes lignes, mais je vous force aussi rchir par vous-mmes ! Eh oui, vous avez appris penser en orient objet et connaissez les points principaux de la programmation vnementielle. Maintenant, il vous reste simplement acqurir des dtails techniques spciques (par exemple, la manire d'utiliser certains objets). Pour ceux qui l'auraient remarqu, la barre d'outils est dplaable ! Si vous cliquez sur la zone mise en vidence la gure 27.20, vous pourrez la repositionner.

Figure

27.20  Zone de dplacement

Il sut de maintenir le clic et de faire glisser votre souris vers la droite, la gauche ou encore le bas. Vous verrez alors un carr se dplacer et, lorsque vous relcherez le bouton, votre barre aura chang de place, comme le montre la gure 27.21. Elles sont fortes ces barres d'outils, tout de mme ! En plus de tout a, vous pouvez utiliser autre chose qu'un composant sur une barre d'outils. . . 435

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE

Figure

27.21  Dplacement de la barre d'outils

Utiliser les actions abstraites


Nous avons vu prcdemment comment centraliser des actions sur dirents composants. Il existe une classe abstraite qui permet de grer ce genre de choses, car elle peut s'adapter beaucoup de composants (en gnral ceux qui ne font qu'une action, comme un bouton, une case cocher, mais pas une liste). Le rle de cette classe est d'attribuer automatiquement une action un ou plusieurs composants. Le principal avantage de ce procd est que plusieurs composants travaillent avec une implmentation de la classe AbstractAction, mais son gros inconvnient rside dans le fait que vous devrez programmer une implmentation par action :  une action pour la couleur de la forme en rouge ;  une action pour la couleur de la forme en bleu ;  une action pour la couleur de la forme en vert ;  une action pour la couleur du fond en rouge ;  une action pour la couleur du fond en bleu ;  ... Cela peut tre trs lourd faire, mais je laisse votre bon sens dterminer s'il est pertinent d'utiliser cette mthode ou non ! Voici comment s'implmente cette classe :
puli lss penetre extends tprme{ GGxous pouvons utiliser les tions strites diretement dns un tfutton privte tfutton outonI a new tfutton@new ougeetion@4etionouge4D new smgeson@4imgesGrougeFjpg4AAY GGyu rer une instne onrte privte ougeetion ret a new ougeetion@4etionouge4D new smgeson@4imgesGrougeFjpg4AAY privte toolfr toolfr a new toolfr@AY GGFFF

436

LES MENUS

GGtiliser une tion diretement dns une rre d9outils privte void initoolfr@A{ toolfrFdd@retAY } GGFFF lss ougeetion extends estrtetion{ GGgonstruteur ve le nom uniquement puli ougeetion@tring nmeA{super@nmeAY} GGve onstruteur prend le nom et une ine en prmtre puli ougeetion@tring nmeD smgesonA{super@nmeD imgAY} puli void tionerformed@etioniventA{ GGous onnissez l mrhe suivre }

Vous pouvez voir que cela peut tre trs pratique. Dsormais, si vous ajoutez une action sur une barre d'outils, celle-ci cre automatiquement un bouton correspondant ! Utiliser les actions abstraites plutt que des implmentations de telle ou telle interface est un choix qui vous revient. Nous pouvons d'ailleurs trs bien appliquer ce principe au code de notre animation, mais vous constaterez qu'il s'alourdira, nous viterons donc de le faire. . . Mais comme je vous le disais, c'est une question de choix et de conception.

En rsum
 Les botes de dialogue s'utilisent, l'exception des botes personnalises, avec l'objet JOptionPane.  La mthode showMessageDialog() permet d'acher un message informatif.  La mthode showConfirmDialog() permet d'acher une bote attendant une rponse une question ouverte (oui/non).  La mthode cite ci-dessus retourne un entier correspondant au bouton sur lequel vous avez cliqu.  La mthode showInputDialog() ache une bote attendant une saisie clavier ou une slection dans une liste.  Cette mthode retourne soit un String dans le cas d'une saisie, soit un Object dans le cas d'une liste.  La mthode showOptionDialog() ache une bote attendant que l'utilisateur eectue un clic sur une option.  Celle-ci retourne l'indice de l'lment sur lequel vous avez cliqu ou un indice ngatif dans tous les autres cas .  Les botes de dialogue sont dites modales : aucune interaction hors de la bote n'est possible tant que celle-ci n'est pas ferme ! 437

CHAPITRE 27. LES MENUS ET BOTES DE DIALOGUE  Pour faire une bote de dialogue personnalise, vous devez crer une classe hrite de JDialog.  Pour les botes personnalises, le dialogue commence lorsque setVisible(true) est invoque et se termine lorsque la mthode setVisible(false) est appele.  L'objet servant insrer une barre de menus sur vos IHM swing est un JMenuBar.  Dans cet objet, vous pouvez mettre des objets JMenu an de crer un menu droulant.  L'objet cit ci-dessus accepte des objets JMenu, JMenuItem, JCheckBoxMenuItem et JRadioButtonMenuItem .  An d'interagir avec vos points de menu, vous pouvez utiliser une implmentation de l'interface ActionListener.  Pour faciliter l'accs aux menus de la barre de menus, vous pouvez ajouter des mnmoniques ceux-ci.  L'ajout d'acclrateurs permet de dclencher des actions, le plus souvent par des combinaisons de touches.  An de rcuprer les codes des touches du clavier, vous devrez utiliser un objet KeyStroke ainsi qu'un objet KeyEvent.  Un menu contextuel fonctionne comme un menu normal, la dirence qu'il s'agit d'un objet JPopupMenu. Vous devez toutefois spcier le composant sur lequel doit s'acher le menu contextuel.  La dtection du clic droit se fait grce la mthode isPopupTrigger() de l'objet MouseEvent.  L'ajout d'une barre d'outils ncessite l'utilisation de l'objet JToolBar.

438

Chapitre

28
Dicult :

TP : l'ardoise magique

N
    

ous voil partis pour un nouveau TP. Les objectifs de celui-ci sont : d'utiliser les menus, les acclrateurs et les mnmoniques ; d'ajouter une barre d'outils ; de crer des implmentations et de savoir les utiliser sur plusieurs composants ; d'utiliser des classes anonymes ; etc.

439

CHAPITRE 28. TP : L'ARDOISE MAGIQUE

Cahier des charges


Voici les recommandations. Vous devez faire une sorte d'ardoise magique. Celle-ci devra tre compose d'un JPanel amlior (a sent l'hritage. . .) sur lequel vous pourrez tracer des choses en cliquant et en dplaant la souris. Vos tracs devront tre eectus point par point, je vous laisse apprcier leur taille. Par contre, vous devrez pouvoir utiliser deux sortes de  pinceaux  :  un carr ;  un rond. Vous aurez aussi la possibilit de changer la couleur de vos traits. Les couleurs que j'ai choisies sont :  le bleu ;  le rouge ;  le vert. Il faut obligatoirement :  un menu avec acclrateurs et mnmoniques ;  une barre d'outils avec les formes et les couleurs ;  un menu  Quitter  et un menu  Effacer  ;  que les formes et les couleurs soient accessibles via le menu ! La gure 28.1 vous montre ce que j'ai obtenu.

Figure

28.1  Points de menu

Et voil ce que j'ai fait rien que pour vous (gure 28.2).

Vous allez utiliser la mthode repaint() de votre composant ; cependant, souvenez-vous que celle-ci est appele automatiquement lors du redimensionnement de votre fentre, de la rduction et de l'agrandissement. . . Vous allez devoir grer ce cas de gure, sans quoi votre zone de dessin s'eacera chaque redimensionnement !
Je vous conseille de crer une classe Point qui va contenir les informations relatives un point trac (couleur, taille, position. . .). Il va falloir que vous griez une collection de points (gnrique) dans votre classe drive de JPanel ! 440

PRREQUIS

Figure

28.2  L'auteur s'exprime

J'en ai presque trop dit. . . Concernant les images utilises, je vous laisse le soin d'en trouver. Avant de vous lancer dans votre code, vous devez savoir quelques petites choses. . .

Prrequis
An de faire les tracs, il va falloir dtecter le mouvement de la souris. Je ne vous en ai pas encore parl auparavant, mais vous avez l'habitude d'utiliser des interfaces de gestion d'vnements, maintenant. . . An de dtecter les mouvements de la souris, vous allez devoir utiliser l'interface MouseMotionListener ; celle-ci contient deux mthodes :  mouseMoved(MouseEvent e) , qui dtecte le mouvement de la souris sur le composant ;  mouseDragged(MouseEvent e) , qui fonctionne comme mouseMoved, sauf que vous devrez avoir cliqu sur le composant et maintenir ce clic enfonc pendant le mouvement (exactement ce dont vous avez besoin). Voil : vous allez devoir crer une implmentation de cette interface pour russir dessiner sur votre conteneur ! Ne vous prcipitez pas, rchissez bien ce dont vous avez besoin, comment utiliser vos implmentations, etc. Un code bien rchi est un code rapidement oprationnel ! 441

CHAPITRE 28. TP : L'ARDOISE MAGIQUE C'est vous, maintenant. . . vos claviers.

Correction
Je vous propose une des corrections possibles. Voir la correction Code web : 601012  Vous constaterez que c'est un code assez simple. Cet exercice n'a rien de dicile et a surtout le mrite de vous faire travailler un peu tout ce que vous avez vu jusqu'ici. . .


Point.java
GG gv C rsp C y pour gnrer les imports puli lss oint { GGgouleur du point privte golor olor a golorFredY GGille privte int size a IHY GGosition sur l9xe X initilis u dehors du onteneur privte int x a EIHY GGosition sur l9xe X initilis u dehors du onteneur privte int y a EIHY GGype de point privte tring type a 4yxh4Y GG gonstruteur pr dfut puli oint@A{} puli oint@int xD int yD int sizeD golor olorD tring typeA{ thisFsize a sizeY thisFx a xY thisFy a yY thisFolor a olorY thisFtype a typeY } GG eggii puli golor getgolor@A { return olorY } puli void setgolor@golor olorA { thisFolor a olorY } puli int getize@A { return sizeY

442

CORRECTION
} puli void setize@int sizeA { thisFsize a sizeY } puli int get@A { return xY } puli void set@int xA { thisFx a xY } puli int get@A { return yY } puli void set@int yA { thisFy a yY } puli tring getype@A { return typeY } puli void setype@tring typeA { thisFtype a typeY }

DrawPanel.java
GG gv C rsp C y pour gnrer les imports puli lss hrwnel extends tnel{ GGgouleur du pointeur privte golor pointergolor a golorFredY GGporme du pointeur privte tring pointerype a 4gsgvi4Y GGosition du pointeur privte int pos a EIHD old a EIHY GGosition du pointeur privte int pos a EIHD old a EIHY GGour svoir si on doit dessiner ou non privte oolen ersing a trueY GGille du pointeur privte int pointerize a ISY GGgolletion de points 3 privte erryvist`ointb points a new erryvist`ointb@AY puli hrwnel@A{ thisFddwousevistener@new wouseedpter@A{ puli void mouseressed@wouseivent eA{ pointsFdd@new oint@eFget@A E @pointerize G PAD eFget@A E

443

CHAPITRE 28. TP : L'ARDOISE MAGIQUE


@pointerize G PAD pointerizeD pointergolorD pointerypeAAY

}AY

repint@AY

thisFddwousewotionvistener@new wousewotionvistener@A{ puli void mousehrgged@wouseivent eA { GGyn rupre les oordonnes de l souris GGet on enlve l moiti de l tille du pointeur GGpour entrer le tr pointsFdd@new oint@eFget@A E @pointerize G PAD eFget@A E @pointerize G PAD pointerizeD pointergolorD pointerypeAAY repint@AY } }AY } GG ous l onnissez mintenntD elleEl puli void pintgomponent@qrphis gA { gFsetgolor@golorFwhiteAY gFfillet@HD HD thisFgetidth@AD thisFgetreight@AAY GGi on doit efferD on ne psse ps dns le else ab ps de dessin if@thisFersingA{ thisFersing a flseY } else{ GGyn prourt notre olletion de points for@oint p X thisFpointsA { GGyn rupre l ouleur gFsetgolor@pFgetgolor@AAY GGelon le type de point if@pFgetype@AFequls@4ei4AA{ gFfillet@pFget@AD pFget@AD pFgetize@AD pFgetize@AAY } else{ gFfillyvl@pFget@AD pFget@AD pFgetize@AD pFgetize@AAY } puli void mousewoved@wouseivent eA {}

444

CORRECTION
GGiffe le ontenu puli void erse@A{ thisFersing a trueY thisFpoints a new erryvist`ointb@AY repint@AY } GGhfinit l ouleur du pointeur puli void setointergolor@golor A{ thisFpointergolor a Y } GGhfinit l forme du pointeur puli void setointerype@tring strA{ thisFpointerype a strY }

Fenetre.java
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme { GG vi wix privte twenufr menufr a new twenufr@AY twenu fihier a new twenu@4pihier4AD edition a new twenu@4idition4AD forme a new twenu@4porme du pointeur4AD ouleur a new twenu@4gouleur du pointeur4AY twenustem nouveu a new twenustem@4iffer4AD quitter a new twenustem@4uitter4AD rond a new twenustem@4ond4AD rre a new twenustem@4grr4AD leu a new twenustem@4fleu4AD rouge a new twenustem@4ouge4AD vert a new twenustem@4ert4AY

GG ve fei h9ysv toolfr toolfr a new toolfr@AY tfutton squre a new tfutton@new smgeson@4imgesGrrFjpg4AAD irle a new tfutton@new smgeson@4imgesGrondFjpg4AAD red a new tfutton@new smgeson@4imgesGrougeFjpg4AAD green a new tfutton@new smgeson@4imgesGvertFjpg4AAD lue a new tfutton@new smgeson@4imgesGleuFjpg4AAY GG vi gyi

445

CHAPITRE 28. TP : L'ARDOISE MAGIQUE


privte pormevistener fvistener a new pormevistener@AY privte gouleurvistener vistener a new gouleurvistener@AY GGxotre zone de dessin privte hrwnel drwnel a new hrwnel@AY puli penetre@A{ thisFsetize@UHHD SHHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY GGyn initilise le menu thisFinitwenu@AY GGsdem pour l rre d9outils thisFinitoolfr@AY GGyn positionne notre zone de dessin thisFgetgontentne@AFdd@drwnelD fordervyoutFgixiAY thisFsetisile@trueAY

GGsnitilise le menu privte void initwenu@A{ nouveuFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { drwnelFerse@AY } }AY nouveuFseteelertor@ ueytrokeFgetueytroke@ ueyiventFuxD ueyiventFgvhyxweuAAY quitterFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { ystemFexit@HAY } }AY quitterFseteelertor@ ueytrokeFgetueytroke@ ueyiventFuD ueyiventFgvhyxweuAAY fihierFdd@nouveuAY fihierFddeprtor@AY fihierFdd@quitterAY fihierFsetwnemoni@9p9AY rreFddetionvistener@fvistenerAY rondFddetionvistener@fvistenerAY formeFdd@rondAY formeFdd@rreAY

446

CORRECTION

rougeFddetionvistener@vistenerAY vertFddetionvistener@vistenerAY leuFddetionvistener@vistenerAY ouleurFdd@rougeAY ouleurFdd@vertAY ouleurFdd@leuAY editionFsetwnemoni@9i9AY editionFdd@formeAY editionFddeprtor@AY editionFdd@ouleurAY menufrFdd@fihierAY menufrFdd@editionAY } thisFsettwenufr@menufrAY

GGsnitilise l rre d9outils privte void initoolfr@A{ tnel pnneu a new tnel@AY squreFddetionvistener@fvistenerAY irleFddetionvistener@fvistenerAY redFddetionvistener@vistenerAY greenFddetionvistener@vistenerAY lueFddetionvistener@vistenerAY toolfrFdd@squreAY toolfrFdd@irleAY toolfrFddeprtor@AY toolfrFdd@redAY toolfrFdd@lueAY toolfrFdd@greenAY } thisFgetgontentne@AFdd@toolfrD fordervyoutFxyrAY

GGgyi y vi grexqiwix hi pywi lss pormevistener implements etionvistener{ puli void tionerformed@etionivent eA { if@eFgetoure@AFgetglss@AFgetxme@AFequls@4jvxFswingF twenustem4AA{ if@eFgetoure@AaarreAdrwnelFsetointerype@4ei4AY else drwnelFsetointerype@4gsgvi4AY } else{ if@eFgetoure@AaasqureAdrwnelFsetointerype@4ei4AY

447

CHAPITRE 28. TP : L'ARDOISE MAGIQUE


else drwnelFsetointerype@4gsgvi4AY

GGgyi y vi grexqiwix hi gyvi lss gouleurvistener implements etionvistener{ puli void tionerformed@etionivent eA { ystemFoutFprintln@eFgetoure@AFgetglss@AFgetxme@AAY if@eFgetoure@AFgetglss@AFgetxme@AFequls@4jvxFswingF twenustem4AA{ ystemFoutFprintln@4yu 34AY if@eFgetoure@AaavertAdrwnelFsetointergolor@golorFgreenAY else if@eFgetoure@AaaleuAdrwnelFsetointergolor@golorFlueAY else drwnelFsetointergolor@golorFredAY } else{ if@eFgetoure@AaagreenAdrwnelFsetointergolor@golorFgreenAY else if@eFgetoure@AaalueAdrwnelFsetointergolor@golorFlueAY else drwnelFsetointergolor@golorFredAY } } } puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Amliorations possibles
Voici ce que vous pouvez faire an de rendre cette application plus attractive :  permettre de changer la taille du pinceau ;  proposer une plus grande palette de couleurs ;  proposer des pinceaux supplmentaires ;  crer une gomme ;  utiliser les numrations (ou encore le pattern strategy) pour grer les direntes fonctionnalits ;  etc.

448

Chapitre

29
Dicult :

Conteneurs, sliders et barres de progression

ans ce chapitre, nous allons voir de nouveaux conteneurs. Ils seront soit complmentaires au JPanel que vous connaissez bien maintenant, soit tout autre type de conteneur ayant ses propres spcicits. Il y a plusieurs objets qui peuvent vous aider mieux grer le contenu de vos IHM ; ceux qui seront abords ici vont, je pense, vous rendre un sacr service. . . Toutefois, laissez-moi vous mettre en garde : ici, nous n'aborderons pas les objets dans le dtail, nous ne ferons mme qu'en survoler certains. Le fait est que vous tes dornavant mme d'approfondir tel ou tel sujet en Java.

449

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION

Autres conteneurs
L'objet JSplitPane
Avant de vous faire un laus (un petit, je vous rassure), voici quoi ressemblent des fentres avec un JSplitPane (gure 29.1) :

Figure

29.1  Exemple de JSplitPane avec dplacement du splitter

Cette image reprsente l'intrieur d'un objet JFrame. La barre au milieu est un objet dplaable qui permet d'agrandir une zone tout en rtrcissant celle d' ct. Ici, dans la premire image, la barre est vers la gauche. La deuxime image est prise pendant que je dplace la barre centrale et enn, la troisime correspond au rsultat lorsque j'ai relch le bouton de ma souris ! Vous pouvez constater que le conteneur de gauche est devenu plus grand, au dtriment de celui de droite. . . Je vous rassure tout de suite, ce composant est trs simple d'utilisation. En fait, les composants abords dans ce chapitre n'ont rien de compliqu. Je ne vais pas vous faire mariner plus longtemps : l'objet utilis ici est un JSplitPane. Voici le code source que j'ai utilis pour avoir le rsultat ci-dessus :
import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvxFswingFtprmeY jvxFswingFtnelY jvxFswingFtplitneY

puli lss penetre extends tprme { GGyn dlre notre ojet tplitne privte tplitne splitY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsetitle@4qrer vos onteneur4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetize@PHHD PHHAY GGyn re deux onteneurs de ouleurs diffrentes tnel pn a new tnel@AY pnFsetfkground@golorFlueAY

450

AUTRES CONTENEURS
tnel pnP a new tnel@AY pnPFsetfkground@golorFredAY GGyn onstruit enfin notre sprteur split a new tplitne@tplitneFrysyxevvsD pnD pnPAY GGyn le psse ensuite u ontent pne de notre ojet penetre GGpl u entre pour qu9il utilise tout l9espe disponile thisFgetgontentne@AFdd@splitD fordervyoutFgixiAY thisFsetisile@trueAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Vous avez sans doute repr l'attribut JSplitPane.HORIZONTAL_SPLIT dans le constructeur de l'objet : il sert spcier le type de sparation utilis. Eh oui, il en existe d'autres ! Vous pouvez obtenir une sparation verticale en utilisant l'attribut JSplitPane.VERTICAL_SPLIT (gure 29.2).

Figure

29.2  Split vertical

Autre point, les deux autres paramtres ne sont pas ncessairement des JPanel. Ici, j'ai utilis des JPanel, mais vous pouvez en fait utiliser n'importe quelle classe drivant de JComponent (conteneur, bouton, case cocher. . .) : elle n'est pas belle, la vie ? Je ne vous avais donc pas menti : cet objet est vraiment trs simple d'utilisation, mais je ne vais pas vous laisser tout de suite. . . Vous ne l'avez peut-tre pas remarqu mais ces objets ne peuvent pas faire disparatre entirement les cts. Dans notre cas, la fentre est petite, mais vous aurez peut-tre l'occasion d'avoir une grande IHM et d'agrandir ou de rtrcir frquemment vos contenus. L'objet JSplitPane dispose d'une mthode qui permet de rendre la barre de sparation  intelligente , enn presque. . . Ladite mthode ajoute deux petits boutons sur votre barre et, lorsque vous cliquerez dessus, fera rtrcir le ct vers lequel pointe la che dans le bouton. L'illustration de mes propos se trouve la gure 29.3. Pour avoir ces deux boutons en plus sur votre barre, il vous sut d'invoquer la mthode split.setOneTouchExpandable(true); (mon objet s'appelle toujours split) et le tour est jou ! Amusez-vous cliquer sur ces boutons et vous verrez quoi ils servent. 451

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION

Figure

29.3  Flches de positionnement

Avant de vous laisser fouiner un peu propos de cet objet, vous devez savoir que vous pouvez dnir une taille de sparateur grce la mthode split.setDividerSize(int size) ; la gure 29.4 vous montre ce que j'ai obtenu avec une taille de 35 pixels.

Figure

29.4  Agrandissement du splitter

Vous pouvez galement dnir o doit s'acher la barre de sparation. Ceci se fait grce la mthode setDividerLocation(int location); ou setDividerLocation(double location);. Avant de vous montrer un exemple de code utilisant cette mthode, vous avez d comprendre que, vu que cet objet peut accepter en paramtres des sous-classes de JComponent, il pouvait aussi accepter des JSplitPane ! La gure 29.5 vous montre ce que j'ai pu obtenir.

Figure

29.5  Multiple splitter

Voici le code correspondant :


import import import import import jvFwtFfordervyoutY jvFwtFgolorY jvxFswingFtprmeY jvxFswingFtnelY jvxFswingFtplitneY

puli lss penetre extends tprme { privte tplitne splitD splitPD splitQY puli penetre@A{

452

AUTRES CONTENEURS
thisFsetvotioneltiveo@nullAY thisFsetitle@4qrer vos onteneur4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetize@PHHD PHHAY GGyn re deux onteneurs de ouleurs diffrentes tnel pn a new tnel@AY pnFsetfkground@golorFlueAY tnel pnP a new tnel@AY pnPFsetfkground@golorFredAY tnel pnQ a new tnel@AY pnQFsetfkground@golorForngeAY tnel pnR a new tnel@AY pnRFsetfkground@golorFivvyAY GGyn onstruit enfin notre sprteur split a new tplitne@tplitneFrysyxevvsD pnD pnRAY GGyn ple le premier sprteur splitFsethividervotion@VHAY splitP a new tplitne@tplitneFrysyxevvsD pnQD pnPAY GGyn ple le deuxime sprteur splitPFsethividervotion@IHHAY GGyn psse les deux prdents tplitne eluiEi splitQ a new tplitne@tplitneFisgevvsD splitD splitPAY GGyn ple le troisime sprteur splitQFsethividervotion@VHAY GGyn le psse ensuite u ontent pne de notre ojet penetre GGpl u entre pour qu9il utilise tout l9espe disponile thisFgetgontentne@AFdd@splitQD fordervyoutFgixiAY thisFsetisile@trueAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Je pense que vous en savez assez pour utiliser cet objet comme il convient. Nous allons prsent voir un autre objet bien pratique. Il permet d'ajouter un scroll (barre de dlement) ct de vos conteneurs an de pouvoir dpasser les limites de ceux-ci.

L'objet JScrollPane
An que vous puissiez mieux juger l'utilit de l'objet que nous allons utiliser ici, nous allons voir un nouvel objet de texte : le JTextArea. Cet objet est trs simple : c'est une forme de JTextField, mais en plus grand ! Nous pouvons directement crire dans ce composant, celui-ci ne retourne pas directement la ligne si vous atteignez le bord droit de la fentre. Pour vrier si les lettres tapes au clavier sont bien dans notre 453

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION objet, vous pouvez rcuprer le texte saisi grce la mthode getText(). Voici un code d'exemple :
import import import import import import jvFwtFfordervyoutY jvFwtFeventFetioniventY jvFwtFeventFetionvistenerY jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtextereY

puli lss penetre extends tprme { privte textere textne a new textere@AY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsetitle@4qrer vos onteneur4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetize@PHHD PHHAY tfutton outon a new tfutton@4fouton4AY outonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eA{ ystemFoutFprintln@4exte rit dns le textere X 4AY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY ystemFoutFprintln@textneFgetext@AAY } }AY GGyn joute l9ojet u ontent pne de notre fentre thisFgetgontentne@AFdd@textneD fordervyoutFgixiAY thisFgetgontentne@AFdd@outonD fordervyoutFyrAY thisFsetisile@trueAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Le code est simple et clair, je vous laisse le tester chez vous ! Cependant, les plus curieux d'entre vous l'auront remarqu : si vous crivez trop de lignes, vous dpassez la limite impose par le bas de votre fentre. . . Le texte est bien crit mais vous ne le voyez pas. . . Exactement comme pour le bord droit. Pour ce genre de problme, il existe ce qu'on appelle des scrolls. Ce sont de petit ascenseurs positionns sur le ct et / ou sur le bas de votre fentre et qui vous permettent de dpasser les limites imposes par ladite fentre (gure 29.6) ! Vous voyez le petit ascenseur droite et en bas de la fentre ? Avec a, nis les problmes de taille de vos conteneurs ! Voici le code que j'ai utilis pour obtenir ce rsultat : 454

AUTRES CONTENEURS

Figure

29.6  Exemple de JScrollPane

import jvFwtFfordervyoutY import jvFwtFeventFetioniventY import jvFwtFeventFetionvistenerY import import import import jvxFswingFtfuttonY jvxFswingFtprmeY jvxFswingFtrollneY jvxFswingFtextereY

puli lss penetre extends tprme { privte textere textne a new textere@AY privte trollne sroll a new trollne@textneAY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsetitle@4qrer vos onteneur4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetize@PHHD PHHAY tfutton outon a new tfutton@4fouton4AY outonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eA{ ystemFoutFprintln@4exte rit dns le textere X 4AY ystemFoutFprintln@4EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY ystemFoutFprintln@textneFgetext@AAY } }AY GGyn joute l9ojet u ontent pne de notre fentre thisFgetgontentne@AFdd@srollD fordervyoutFgixiAY GGyn urit pu ussi rire GGthisFgetgontentne@AFdd@new trollne@textneAD fordervyoutFgixiAY thisFgetgontentne@AFdd@outonD fordervyoutFyrAY thisFsetisile@trueAY

455

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

L'objet utilis an d'avoir un ascenseur s'appelle donc un JScrollPane. Dsormais, vous pourrez crire aussi loin que vous le voulez, vers le bas et vers la droite ! Les ascenseurs apparaissent automatiquement lorsque vous dpassez les limites autorises. De plus, vous pouvez rednir leurs comportements grce aux mthodes :  scroll.setHorizontalScrollBarPolicy(int policy) , qui permet de dnir le comportement du scroll en bas de votre fentre ;  scroll.setVerticalScrollBarPolicy(int policy) , qui permet de dnir le comportement du scroll droite de votre fentre. Le paramtre de ces mthodes est un entier dni dans la classe JScrollPane, il peut prendre les valeurs suivantes :  JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED : le scroll vertical n'est visible que s'il est ncessaire, donc s'il y a dpassement de la taille en hauteur ;  JScrollPane.VERTICAL_SCROLLBAR_NEVER : le scroll vertical n'est jamais visible, mme si vous dpassez ; en revanche, le conteneur s'allonge tout de mme ;  JScrollPane.VERTICAL_SCROLLBAR_ALWAYS : le scroll vertical est toujours visible, mme si vous ne dpassez pas. Les mmes entiers existent pour le scroll horizontal, mais vous devrez alors remplacer VERTICAL par HORIZONTAL ! Vous devez tout de mme savoir que cet objet en utilise un autre : un JScrollBar. Les deux barres de dlement sont deux instances de cet objet. . . Nous avons vu comment sparer un conteneur, comment agrandir un conteneur, nous allons maintenant voir comment ajouter dynamiquement des conteneurs !

L'objet JTabbedPane
Dans ce chapitre, vous allez apprendre crer plusieurs  pages  dans votre IHM. . . Jusqu' maintenant, vous ne pouviez pas avoir plusieurs contenus dans votre fentre, moins de leur faire partager l'espace disponible. Il existe une solution toute simple qui consiste crer des onglets et, croyez-moi, c'est aussi trs simple faire. L'objet utiliser est un JTabbedPane. An d'avoir un exemple plus ludique, j'ai constitu une classe hrite de JPanel an de crer des onglets ayant une couleur de fond dirente. . . Cette classe ne devrait plus vous poser de problmes :
import import import import jvFwtFgolorY jvFwtFpontY jvFwtFqrphisY jvxFswingFtnelY

puli lss nneu extends tnel{ privte golor olor a golorFwhiteY

456

AUTRES CONTENEURS
privte stti int gyx a HY privte tring messge a 44Y puli nneu@A{} puli nneu@golor olorA{ thisFolor a olorY thisFmessge a 4gontenu du pnneu x4 C @CCgyxAY } puli void pintgomponent@qrphis gA{ gFsetgolor@thisFolorAY gFfillet@HD HD thisFgetidth@AD thisFgetreight@AAY gFsetgolor@golorFwhiteAY gFsetpont@new pont@4eril4D pontFfyvhD ISAAY gFdrwtring@thisFmessgeD IHD PHAY }

J'ai utilis cet objet an de crer un tableau de Panneau. Chaque instance est ensuite ajoute mon objet grant les onglets via sa mthode add(String title, JComponent comp). Vous voudriez peut-tre disposer du code tout de suite, le voici donc :
import jvFwtFgolorY import jvxFswingFtprmeY import jvxFswingFtedneY puli lss penetre extends tprme { privte tedne ongletY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsetitle@4qrer vos onteneurs4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetize@RHHD PHHAY GGgrtion de plusieurs nneu nneu tn a { new nneu@golorFihAD new nneu@golorFqiixAD new nneu@golorFfviA}Y GGgrtion de notre onteneur d9onglets onglet a new tedne@AY int i a HY for@nneu pn X tnA{ GGwthode d9jout d9onglet ongletFdd@4ynglet n o 4C@CCiAD pnAY GGous pouvez ussi utiliser l mthode dd GGongletFdd@4ynglet n o 4C@CCiAD pnAY }

457

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION


GGyn psse ensuite les onglets u ontent pne thisFgetgontentne@AFdd@ongletAY thisFsetisile@trueAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Ce qui a donn le rsultat que l'on peut voir la gure 29.7.

Figure

29.7  Plusieurs onglets

Vous constatez que l'utilisation de cet objet est trs simple, l aussi. . . Je vais tout de mme vous prsenter quelques mthodes bien utiles. Par exemple, vous pouvez ajouter une image en guise d'icne ct du titre de l'onglet. Ce qui pourrait nous donner la gure 29.8.

Figure

29.8  Image en titre d'onglet

Le code est identique au prcdent, l'exception de ce qu'il y a dans la boucle :


for@nneu pn X tnA{ GGwthode d9jout d9onglet ongletFdd@4ynglet n o 4C@CCiAD pnAY GGyn joute l9imge l9onglet en ours GGves index d9onglets fontionnent omme les tleux X ils ommenent H ongletFsetsonet@@i E IAD new smgeson@4jvFjpg4AAY

458

AUTRES CONTENEURS
GGous pouvez ussi utiliser l mthode dd GGongletFdd@4ynglet n o 4C@CCiAD new smgeson@4jvFjpg4AD pnAY

Vous avez galement la possibilit de changer l'emplacement des en-ttes d'onglets en spciant cet emplacement dans le constructeur, comme ceci :
GGeffihe les onglets en s de l fentre tedne onglet a new tedne@tedneFfyywAY GGeffihe les onglets guhe de l fentre tedne onglet a new tedne@tedneFvipAY GGeffihe les onglets droite de l fentre tedne onglet a new tedne@tedneFsqrAY

La gure 29.9 vous montre ce que vous pouvez obtenir.

Figure

29.9  Emplacement des onglets

Vous pouvez aussi utiliser la mthode setTabPlacement(JTabbedPane.BOTTOM); qui a le mme eet : ici, la barre d'exploration des onglets sera situe en bas du conteneur. Vous avez aussi la possibilit d'ajouter ou de retirer des onglets. Pour ajouter, vous avez devin comment procder ! Pour retirer un onglet, nous allons utiliser la mthode remove(int index). Cette mthode parle d'elle-mme, elle va retirer l'onglet ayant pour index le paramtre pass.
GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme { privte tedne ongletY GGgompteur pour le nomre d9onglets privte int nre a HY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsetitle@4qrer vos onteneurs4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetize@RHHD PHHAY

459

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION

GGgrtion de plusieurs nneu nneu tn a { new nneu@golorFihAD new nneu@golorFqiixAD new nneu@golorFfviA}Y GGgrtion de notre onteneur d9onglets onglet a new tedne@AY for@nneu pn X tnA{ GGwthode d9jout d9onglets ongletFdd@4ynglet x4C@CCnreAD pnAY } GGyn psse ensuite les onglets u ontent pne thisFgetgontentne@AFdd@ongletD fordervyoutFgixiAY GGejout du outon pour jouter des onglets tfutton nouveu a new tfutton@4ejouter un onglet4AY nouveuFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eA{ ongletFdd@4ynglet x4C@CCnreAD new nneu@golorFheuqeAAY } }AY GGejout du outon pour retirer l9onglet sletionn tfutton delete a new tfutton@4iffer l9onglet4AY deleteFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eA{ GGyn rupre l9index de l9onglet sletionn int seleted a ongletFgeteletedsndex@AY GG9il n9y plus d9ongletD l mthode iEdessus retourne EI if@seleted b EIAongletFremove@seletedAY } }AY tnel pn a new tnel@AY pnFdd@nouveuAY pnFdd@deleteAY thisFgetgontentne@AFdd@pnD fordervyoutFyrAY thisFsetisile@trueAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Ce qui peut vous donner la mme chose que la gure 29.10. 460

AUTRES CONTENEURS

Figure

29.10  Beaucoup, beaucoup d'onglets. . .

L'objet JDesktopPane combin des

JInternalFrame

Ces deux objets sont trs souvent associs et permettent de raliser des applications multifentres (gure 29.11).

Figure

29.11  Exemple d'une application multifentre

GGgv C rsp C y pour gnrer les imports nessires puli lss fureu extends tprme{ privte stti int nrepenetre a HY privte thesktopne desktop a new thesktopne@AY privte stti int xy a IHY puli fureu@A{ thisFsetize@RHHD QHHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY tfutton jouter a new tfutton@4ejouter une fentre interne4AY jouterFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eventA{ CCnrepenetreY

461

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION


xy Ca PY desktopFdd@new winipenetre@nrepenetreAD nrepenetreAY

}AY

thisFgetgontentne@AFdd@desktopD fordervyoutFgixiAY thisFgetgontentne@AFdd@jouterD fordervyoutFyrAY

lss winipenetre extends tsnternlprme{ puli winipenetre@int nreA{ thisFsetitle@4penetre x4CnreAY thisFsetglosle@trueAY thisFsetesizle@trueAY thisFsetize@ISHD VHAY thisFsetvotion@xyD xyAY thisFsetisile@trueAY } } puli stti void min@tring rgsA{ fureu ureu a new fureu@AY ureuFsetisile@trueAY }

L'objet JWindow
Pour faire simple, c'est une JFrame, mais sans les contours permettant de rduire, fermer ou agrandir la fentre ! Il est souvent utilis pour faire des splash screens (ce qui s'ache au lancement d'Eclipse, par exemple. . .). La gure 29.12 vous donne un exemple de cet objet.

Figure

29.12  JWindow

GGgv C rsp C y pour gnrer les imports nessires puli lss indow extends tindow{

462

AUTRES CONTENEURS
puli stti void min@tring rgsA{ indow wind a new indow@AY windFsetisile@trueAY } puli indow@A{ setize@PPHD ITSAY setvotioneltiveo@nullAY tnel pn a new tnel@AY tvel img a new tvel@new smgeson@4plnteFjpeg4AAY imgFsetertilelignment@tvelFgixiAY imgFsetrorizontlelignment@tvelFgixiAY pnFsetforder@forderptoryFretevineforder@golorFlueAAY pnFdd@imgAY getgontentne@AFdd@pnAY }

Le JEditorPane
Voici un objet sympathique mais quelque peu limit par la faon dont il gre son contenu HTML (gure 29.13) ! Il permet de raliser des textes riches (avec une mise en page). Il y a aussi le JTextPane qui vous permet trs facilement de faire un mini-diteur de texte (enn, tout est relatif. . .).

Figure

29.13  Aperu de l'objet JEditorPane

GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme { privte tiditorne editorneD peruY privte tedne onglet a new tedne@AY

463

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION

puli penetre@A{ thisFsetize@THHD RHHAY thisFsetitle@4gonteneur ditle4AY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY editorne a new tiditorne@AY editorneFsetext@4 `rwvb`riehb`Griehb`fyhb`Gfyhb`Grwvb 4AY peru a new tiditorne@AY peruFsetiditle@flseAY ongletFdd@4iditeur rwv4D new trollne@editorneAAY ongletFdd@4eperu4D new trollne@peruAAY ongletFddghngevistener@new ghngevistener@A{ puli void stteghnged@ghngeivent eA { pileriter fw a nullY try { fw a new pileriter@new pile@4tmpGtmpFhtml4AAY fwFwrite@editorneFgetext@AAY fwFlose@AY } th @pilexotpoundixeption eIA { eIFprinttkre@AY } th @syixeption eIA { eIFprinttkre@AY } try { pile file a new pile@4tmpGtmpFhtml4AY peruFsetiditoruit@new rwviditoruit@AAY peruFsetge@fileFtov@AAY } th @syixeption eIA { eIFprinttkre@AY } }

}AY

thisFgetgontentne@AFdd@ongletD fordervyoutFgixiAY thisFsetisile@trueAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Dans cet exemple, on dite le code HTML dans l'onglet d'dition et, au changement d'onglet, on gnre un chier temporaire avec l'extension .html. Ce chier est stock dans un rpertoire nomm  tmp  la racine de notre projet. 464

AUTRES CONTENEURS

Le JSlider
Ce composant vous permet d'utiliser un systme de mesure pour une application : redimensionner une image, choisir le tempo d'un morceau de musique, l'opacit d'une couleur, etc. (gure 29.14).

Figure

29.14  Un JSlider

Le code source :
GGgv C rsp C y pour gnrer les imports nessires puli lss lide extends tprme{ privte tvel lel a new tvel@4leur tuelle X QH4AY puli lide@A{ thisFsetize@PSHD ISHAY thisFsetitle@4lider4AY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY tlider slide a new tlider@AY slideFsetwximum@IHHAY slideFsetwinimum@HAY slideFsetlue@QHAY slideFsetintiks@trueAY slideFsetintvels@trueAY slideFsetwinorikping@IHAY slideFsetwjorikping@PHAY slideFddghngevistener@new ghngevistener@A{ puli void stteghnged@ghngeivent eventA{ lelFsetext@4leur tuelle X 4 C @@tliderAeventFgetoure@AAFgetlue@AAY } }AY thisFgetgontentne@AFdd@slideD fordervyoutFgixiAY thisFgetgontentne@AFdd@lelD fordervyoutFyrAY

} puli stti void min@tring rgsA{ lide slide a new lide@AY slideFsetisile@trueAY }

465

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION

La JProgressBar
Elle vous permet de raliser une barre de progression pour des traitements longs (gure 29.15).

Figure

29.15  Une JProgressBar

Voici le code source :


GGgv C rsp C y pour gnrer les imports nessires puli lss rogress extends tprme{ privte hred tY privte trogressfr rY privte tfutton lunh Y puli rogress@A{ thisFsetize@QHHD VHAY thisFsetitle@4BBB trogressfr BBB4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY t a new hred@new ritement@AAY r a new trogressfr@AY rFsetwximum@SHHAY rFsetwinimum@HAY rFsettringinted@trueAY thisFgetgontentne@AFdd@rD fordervyoutFgixiAY lunh a new tfutton@4vner4AY lunhFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eventA{ t a new hred@new ritement@AAY tFstrt@AY } }AY thisFgetgontentne@AFdd@lunhD fordervyoutFyrAY

466

ENJOLIVER VOS IHM


tFstrt@AY thisFsetisile@trueAY

lss ritement implements unnle{ puli void run@A{ lunhFsetinled@flseAY for@int vl a HY vl `a SHHY vlCCA{ rFsetlue@vlAY try { tFsleep@IHAY } th @snterruptedixeption eA { GG yhy eutoEgenerted th lok eFprinttkre@AY } } lunhFsetinled@trueAY

puli stti void min@tring rgsA{ rogress p a new rogress@AY }

La modication des valeurs de cet objet doit se faire dans un thread, sinon vous aurez une barre vide, un temps d'attente puis la barre remplie, mais sans que les valeurs aient dl en temps rel !

Enjoliver vos IHM


Nous n'avons pas beaucoup abord ce point tout au long du livre, mais je vous laisse dcouvrir les joyeusets qu'ore Java en la matire. . . Voici comment ajouter des bordures (gure 29.16) vos composants :

Figure

29.16  Exemples de bordures 467

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION


GGgv C rsp C y pour gnrer les imports nessires puli lss forderhemo extends tprme{ privte tring list a { 4fevel forder4D 4ithed forder4D 4vine forder4D 4wtted forder4D 4ised fevel forder4D 4itle forder4D 4gompound forder4 }Y privte forder listforder a { forderptoryFretefevelforder@fevelforderFvyiihD golorFlkD golorFredAD forderptoryFreteithedforder@golorFfviD golorFqeAD forderptoryFretevineforder@golorFgreenAD forderptoryFretewtteforder@SD PD SD PD golorFweqixeAD forderptoryFreteisedfevelforder@AD forderptoryFreteitledforder@4itre4AD forderptoryFretegompoundforder@ forderptoryFretefevelforder@fevelforderFvyiihD golorFlkD golorFlueAD forderptoryFretewtteforder@SD PD SD PD golorFweqixeA A }Y puli forderhemo@A{ thisFsetitle@4ves ordures font l fte 34AY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetize@SSHD PHHAY tnel pn a new tnel@AY for@int i a HY i ` listFlengthY iCCA{ tvel li a new tvel@listiAY liFsetreferredize@new himension@ISHD SHAAY liFsetforder@listforderiAY liFsetelignment@tvelFgixiAY liFsetrorizontlelignment@tvelFgixiAY pnFdd@liAY } } thisFgetgontentne@AFdd@pnAY

puli stti void min@tring rgsA{ forderhemo demo a new forderhemo@AY demoFsetisile@trueAY

468

ENJOLIVER VOS IHM


}

En rsum
 L'objet JSplitPane vous permet de scinder un conteneur en deux parties via un splitter dplaable.  Vous pouvez spcier si le splitter doit tre horizontal ou vertical.  L'objet JScrollPane vous permet d'avoir un conteneur ou un objet contenant du texte de s'tirer selon son contenu, en hauteur comme en largeur.  L'objet JTabbedPane vous permet d'obtenir une interface compose d'autant d'onglets que vous le dsirez et grable de faon dynamique.  Vous pouvez donner un titre et mme une image chaque onglet.  Les onglets peuvent tre disposs aux quatre coins d'une fentre.  Les objets JDesktopPane combins des objets JInternalFrame vous permettent de crer une application multifentre.  L'objet JWindow est une JFrame sans les contrles d'usage. Elle sert acher une image de lancement de programme, comme Eclipse par exemple.  L'objet JEditorPane vous permet de crer un diteur HTML et d'acher le rendu du code crit.  Vous pouvez grer des mesures ou des taux via l'objet JSlider. En dplaant le curseur, vous pourrez faire crotre une valeur an de l'utiliser.  L'objet JProgressBar ache une barre de progression.  Vous pouvez enjoliver la plupart de vos composants avec des bordures en utilisant l'objet BorderFactory qui vous permettra de crer dirents types de traits.

469

CHAPITRE 29. CONTENEURS, SLIDERS ET BARRES DE PROGRESSION

470

Chapitre

30
Dicult :

Les arbres et leur structure

utant les objets vus dans le chapitre prcdent taient simples, autant celui que nous allons voir est assez compliqu. Cela ne l'empche pas d'tre trs pratique et trs utilis. Vous devez tous dj avoir vu un arbre. Non pas celui du monde vgtal, mais celui qui permet d'explorer des dossiers. Nous allons voir comment utiliser et exploiter un tel objet et interagir avec lui : ne vous inquitez pas, tout partira de zro. . . Le mieux, c'est encore de rentrer dans le vif du sujet !

471

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE

La composition des arbres


Tout d'abord, pour ceux qui ne verraient pas de quoi je parle, la gure 30.1 vous montre ce qu'on appelle un arbre ( JTree).

Figure

30.1  Exemple d'arbre

La chose bien pratique avec cet objet c'est que, mme s'il ne ressemble pas un chne ou un autre arbre, il est compos de la mme faon ! En fait, lorsque vous regardez bien un arbre, celui-ci est constitu de plusieurs sous-ensembles :  des racines ;  un tronc ;  des branches ;  des feuilles. L'objet JTree se base sur la mme architecture. Vous aurez donc :  une racine : le rpertoire le plus haut dans la hirarchie ; ici, seul  Racine  est considr comme une racine ;  une ou plusieurs branches : un ou plusieurs sous-rpertoires,  Fichier enfant n o 1-23-4  sont des branches (ou encore  Noeud n o 2-4-6 ) ;  une ou plusieurs feuilles : lments se trouvant en bas de la hirarchie, ici  Souschier enfant no 1-2-3-4  ou encore  Noeud n o 1-3-5-7  sont des feuilles. Voici le code que j'ai utilis :
GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme { privte tree rreY puli penetre@A{ thisFsetize@QHHD QHHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4ves rres4AY

472

LA COMPOSITION DES ARBRES


GGyn invoque l mthode de onstrution de notre rre uildree@AY } thisFsetisile@trueAY

privte void uildree@A{ GGgrtion d9une rine hefultwutlereexode rine a new hefultwutlereexode@4ine4AY GGxous llons jouter des rnhes et des feuilles notre rine for@int i a IY i ` IPY iCCA{ hefultwutlereexode rep a new hefultwutlereexode@4xoeud n

o4CiAY

} GGxous ronsD ve notre hirrhieD un rre rre a new tree@rineAY

GG9il s9git d9un nomre pirD on rjoute une rnhe if@@i7PA aa HA{ GGit une rnhe en plus 3 ne 3 for@int j a IY j ` SY jCCA{ hefultwutlereexode repP a new hefultwutlereexode@4pihier enfnt n o4 C jAY GGgette foisD on joute les feuilles for@int k a IY k ` SY kCCA repPFdd@new hefultwutlereexode @4ousEfihier enfnt n o4 C kAAY repFdd@repPAY } } GGyn joute l feuille ou l rnhe l rine rineFdd@repAY

GGue nous plons sur le gontentne de notre tprme l9ide d9un sroll thisFgetgontentne@AFdd@new trollne@rreAAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Si vous avez du mal vous y retrouver, essayez cette version de la mthode buildTree() :
privte void uildree@A{ GGgrtion d9une rine hefultwutlereexode rine a new hefultwutlereexode@4ine4AY GGxous llons jouter des rnhes et des feuilles notre rine for@int i a IY i ` TY iCCA{

473

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE


hefultwutlereexode rep a new hefultwutlereexode@4xoeud n GGyn rjoute R rnhes if@i ` RA{ hefultwutlereexode repP a new hefultwutlereexode @4pihier enfnt4AY repFdd@repPAY } GGyn joute l feuille ou l rnhe l rine rineFdd@repAY
o4CiAY

} GGxous ronsD ve notre hirrhieD un rre rre a new tree@rineAY

GGue nous plons sur le gontentne de notre tprme l9ide d9un sroll thisFgetgontentne@AFdd@new trollne@rreAAY

Cela devrait vous donner la gure 30.2.

Figure

30.2  Autre exemple de JTree

En ayant manipul ces deux objets, vous devez vous rendre compte que vous construisez une vritable hirarchie avant de crer et d'acher votre arbre ! Ce type d'objet est tout indiqu pour lister des chiers ou des rpertoires. D'ailleurs, nous avons vu comment faire lorsque nous avons abord les ux. C'est avec un arbre que nous allons acher notre arborescence de chiers :
GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme { privte tree rreY privte hefultwutlereexode rineY puli penetre@A{ thisFsetize@QHHD QHHAY thisFsetvotioneltiveo@nullAY

474

LA COMPOSITION DES ARBRES


thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4ves rres4AY GGyn invoque l mthode de onstrution de l9rre listoot@AY } thisFsetisile@trueAY

privte void listoot@A{ thisFrine a new hefultwutlereexode@AY int ount a HY for@pile file X pileFlistoots@AA { hefultwutlereexode leteur a new hefultwutlereexode@fileFgetesoluteth@AAY try { for@pile nom X fileFlistpiles@AA{ hefultwutlereexode node a new hefultwutlereexode@nomFgetxme@AC44AY leteurFdd@thisFlistpile@nomD nodeAAY } } th @xullointerixeption eA {} thisFrineFdd@leteurAY } GGxous ronsD ve notre hirrhieD un rre rre a new tree@thisFrineAY GGue nous plons sur le gontentne de notre tprme l9ide d9un sroll thisFgetgontentne@AFdd@new trollne@rreAAY

privte hefultwutlereexode listpile@pile fileD hefultwutlereexode nodeA{ int ount a HY if@fileFispile@AA return new hefultwutlereexode@fileFgetxme@AAY else{ pile list a fileFlistpiles@AY if@list aa nullA return new hefultwutlereexode@fileFgetxme@AAY for@pile nom X listA{ ountCCY GGs plus de S enfnts pr noeud if@ount ` SA{ hefultwutlereexode suxodeY if@nomFishiretory@AA{ suxode a new hefultwutlereexode@nomFgetxme@AC44AY

475

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE


nodeFdd@thisFlistpile@nomD suxodeAAY }else{ suxode a new hefultwutlereexode@nomFgetxme@AAY } nodeFdd@suxodeAY

} } return nodeY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Ce type de code ne devrait plus vous faire peur. Voici ce que a me donne, aprs quelques secondes (gure 30.3). . .

Figure

30.3  Arborescence de chiers

Pas mal, mais du coup, le dossier  Racine  ne correspond rien ! Heureusement, il existe une mthode dans l'objet JTree qui permet de ne pas acher la racine d'une arborescence : setRootVisible(Boolean ok); . Il sut donc de rajouter l'instruction setRootVisible(false); la n de la mthode listRoot() de l'objet JTree, juste avant d'ajouter notre arbre au ContentPane. Bon : vous arrivez crer et acher un arbre. Maintenant, voyons comment interagir avec !

Des arbres qui vous parlent


Vous connaissez la musique maintenant, nous allons encore implmenter une interface ! Celle-ci se nomme TreeSelectionListener . Elle ne contient qu'une mthode 476

DES ARBRES QUI VOUS PARLENT rednir : valueChanged(TreeSelectionEvent event) . Voici un code utilisant une implmentation de cette interface :
GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme { privte tree rreY privte hefultwutlereexode rineY puli penetre@A{ thisFsetize@QHHD PHHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4ves rres4AY GGyn invoque l mthode de onstrution de l9rre listoot@AY } thisFsetisile@trueAY

privte void listoot@A{ thisFrine a new hefultwutlereexode@AY int ount a HY for@pile file X pileFlistoots@AA{ hefultwutlereexode leteur a new hefultwutlereexode@fileFgetesoluteth@AAY try { for@pile nom X fileFlistpiles@AA{ hefultwutlereexode node a new hefultwutlereexode@nomFgetxme@AC44AY leteurFdd@thisFlistpile@nomD nodeAAY } } th @xullointerixeption eA {} thisFrineFdd@leteurAY } GGxous ronsD ve notre hirrhieD un rre rre a new tree@thisFrineAY rreFsetootisile@flseAY rreFddreeeletionvistener@new reeeletionvistener@A{ puli void vlueghnged@reeeletionivent eventA { if@rreFgetvsteletedthgomponent@A 3a nullA{ ystemFoutFprintln@rreFgetvsteletedthgomponent@A Ftotring@AAY } }

}AY GGue nous plons sur le gontentne de notre tprme GG l9ide d9un sroll

477

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE


thisFgetgontentne@AFdd@new trollne@rreAAY

privte hefultwutlereexode listpile@pile fileD hefultwutlereexode nodeA{ int ount a HY if@fileFispile@AA return new hefultwutlereexode@fileFgetxme@AAY else{ pile list a fileFlistpiles@AY if@list aa nullA return new hefultwutlereexode@fileFgetxme@AAY for@pile nom X listA{ ountCCY GGs plus de S enfnts pr noeud if@ount ` SA{ hefultwutlereexode suxodeY if@nomFishiretory@AA{ suxode a new hefultwutlereexode@nomFgetxme@AC44AY nodeFdd@thisFlistpile@nomD suxodeAAY }else{ suxode a new hefultwutlereexode@nomFgetxme@AAY } nodeFdd@suxodeAY } } return nodeY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

Cela donne la gure 30.4. Votre arbre est maintenant ractif ! Lorsque vous slectionnez un dossier ou un chier, le nom de ce dernier s'ache. Cela se fait grce la mthode getLastSelectedPathComponent() : elle retourne un Object correspondant au dernier point de l'arbre qui a t cliqu. Il ne reste plus qu' utiliser la mthode toString() an de retourner son libell. Nous avons russi acher le nom du dernier nud cliqu, mais nous n'allons pas nous arrter l. . . Il peut tre intressant de connatre le chemin d'accs du nud dans l'arbre ! Surtout dans notre cas, puisque nous listons le contenu de notre disque. Nous pouvons donc obtenir des informations supplmentaires sur une feuille ou une branche en recourant un objet File, par exemple. L'objet TreeEvent pass en paramtre de la mthode de l'interface vous apporte de prcieux renseignements, dont la mthode 478

DES ARBRES QUI VOUS PARLENT

Figure

30.4  Arborescence qui ragit

getPath() qui vous retourne un objet TreePath. Ce dernier contient les objets corres-

pondant aux nuds du chemin d'accs un point de l'arbre. Ne vous inquitez pas, vous n'avez pas changer beaucoup de choses pour obtenir ce rsultat. En fait, je n'ai modi que la classe anonyme qui gre l'vnement dclench sur l'arbre. Voici la nouvelle version de cette classe anonyme :
rreFddreeeletionvistener@new reeeletionvistener@A{ puli void vlueghnged@reeeletionivent eventA { if@rreFgetvsteletedthgomponent@A 3a nullA{ GGv mthode getth retourne un ojet reeth ystemFoutFprintln@getesoluteth@eventFgetth@AAAY } } privte tring getesoluteth@reeth treethA{ tring str a 44Y GGyn lie le ontenu de l9ojet reeth for@yjet nme X treethFgetth@AA{ GGi l9ojet un nomD on l9joute u hemin if@nmeFtotring@A 3a nullA str Ca nmeFtotring@AY } return strY }

}AY

La gure 30.5 vous montre ce que j'ai pu obtenir. Vous pouvez voir que nous avons maintenant le chemin complet dans notre arbre et, 479

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE

Figure

30.5  Achage du chemin complet des nuds

480

DCOREZ VOS ARBRES vu que nous interagissons avec les chiers de notre systme, nous pourrons en savoir plus. Nous allons donc ajouter un  coin information  droite de notre arbre, dans un conteneur part. Essayez de le faire vous-mmes dans un premier temps, sachant que j'ai obtenu quelque chose comme la gure 30.6.

Figure

30.6  Acher des informations sur les chiers

Copier la correction Code web : 623139  J'espre que vous n'avez pas eu trop de mal faire ce petit exercice. . . Vous devriez maintenant commencer savoir utiliser ce type d'objet, mais avant de passer autre chose, je vous propose d'apprendre personnaliser un peu l'achage de notre arbre.

Dcorez vos arbres


Vous avez la possibilit de changer les icnes des rpertoires et des chiers, tout comme celles d'ouverture et de fermeture. Cette opration est trs simple raliser : il vous sut d'utiliser un objet DefaultTreeCellRenderer (qui est une sorte de modle), de dnir les icnes pour tous ces cas, et ensuite de spcier votre arbre qu'il lui fait utiliser ce modle en utilisant la mthode setCellRenderer(DefaultTreeCellRenderer cellRenderer). La gure 30.7 vous montre un exemple de trois rendus distincts. Et voici le code qui m'a permis d'arriver ce rsultat :
GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme { privte tree rreD rrePD rreQY privte hefultwutlereexode rineY GGyn v rer deux modles d9ffihge privte hefultreegellenderer tgellenderer a new hefultreegellendererQY puli penetre@A{ thisFsetize@THHD QSHAY

481

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE

Figure

30.7  Icnes personnalises

thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4ves rres4AY GGyn invoque l mthode de onstrution de l9rre initenderer@AY listoot@AY } thisFsetisile@trueAY

privte void initenderer@A{ GGsnstnition thisFtgellendererH a new hefultreegellenderer@AY GGsnitilistion des imges pour les tions fermerD GGouvrir et pour les feuilles thisFtgellendererHFsetglosedson@new smgeson@4imgGfermeFjpg4AAY thisFtgellendererHFsetypenson@new smgeson@4imgGouvertFjpg4AAY thisFtgellendererHFsetvefson@new smgeson@4imgGfeuilleFjpg4AAY thisFtgellendererI a new hefultreegellenderer@AY thisFtgellendererIFsetglosedson@nullAY thisFtgellendererIFsetypenson@nullAY thisFtgellendererIFsetvefson@nullAY

privte void listoot@A{ thisFrine a new hefultwutlereexode@AY int ount a HY for@pile file X pileFlistoots@AA{ hefultwutlereexode leteur a new hefultwutlereexode@fileFgetesoluteth@AAY

482

DCOREZ VOS ARBRES


try { for@pile nom X fileFlistpiles@AA{ hefultwutlereexode node a new hefultwutlereexode@nomFgetxme@AC44AY leteurFdd@thisFlistpile@nomD nodeAAY } } th @xullointerixeption eA {} thisFrineFdd@leteurAY } GGxous ronsD ve notre hirrhieD un rre rre a new tree@thisFrineAY rreFsetootisile@flseAY GGyn dfinit le rendu pour et rre rreFsetgellenderer@thisFtgellendererHAY rreP a new tree@thisFrineAY rrePFsetootisile@flseAY rrePFsetgellenderer@thisFtgellendererIAY rreQ a new tree@thisFrineAY rreQFsetootisile@flseAY tplitne split a new tplitne@ new trollne@rrePAD new trollne@rreQAAY splitFsethividervotion@PHHAY tplitne splitP a new tplitne@ new trollne@rreAD splitAY splitPFsethividervotion@PHHAY thisFgetgontentne@AFdd@splitPAY tplitneFrysyxevvsD

tplitneFrysyxevvsD

privte hefultwutlereexode listpile@pile fileD hefultwutlereexode nodeA{ int ount a HY if@fileFispile@AA return new hefultwutlereexode@fileFgetxme@AAY else{ pile list a fileFlistpiles@AY if@list aa nullA return new hefultwutlereexode@fileFgetxme@AAY for@pile nom X listA{ ountCCY GGs plus de S enfnts pr noeud if@ount ` SA{

483

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE


hefultwutlereexode suxodeY if@nomFishiretory@AA{ suxode a new hefultwutlereexode@nomFgetxme@AC44AY nodeFdd@thisFlistpile@nomD suxodeAAY }else{ suxode a new hefultwutlereexode@nomFgetxme@AAY } nodeFdd@suxodeAY

} } return nodeY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY }

C'est simple, n'est-ce pas ? Vous dnissez les nouvelles images et indiquez l'arbre le modle utiliser ! Il existe une autre faon de changer l'achage (le design) de votre application. Chaque systme d'exploitation possde son propre  design , mais vous avez pu constater que vos applications Java ne ressemblent pas du tout ce que votre OS 1 vous propose d'habitude ! Les couleurs, mais aussi la faon dont sont dessins vos composants. . . Mais il y a un moyen de pallier ce problme : utiliser le  look and feel  de votre OS. J'ai rajout ces lignes de code dans le constructeur de mon objet, avant l'instruction setVisible(true) :
try { GGyn fore utiliser le look nd feel du systme swngerFsetvookendpeel@swngerFgetystemvookendpeelglssxme@AAY GGsi on fore tous les omposnts de notre fentre @thisA se redessiner GGve le look nd feel du systme wingtilitiesFupdtegomponentrees@thisAY } th @snstntitionixeption eA { } th @glssxotpoundixeption eA { } th @nsupportedvookendpeelixeption eA { } th @sllegleessixeption eA {}

Cela me donne, avec le code ci-dessus, la gure 30.8. Bien sr, vous pouvez utiliser d'autres  look and feel  que ceux de votre systme et de Java. Voici un code qui permet de lister ces types d'achage et d'instancier un objet Fenetre en lui spciant quel modle utiliser :
GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme {

1.

Operating System, ou systme d'exploitation.

484

DCOREZ VOS ARBRES

Figure

30.8  Design de l'OS forc

privte tree rreD rrePD rreQY privte hefultwutlereexode rineY puli penetre@tring lookendpeelA{ thisFsetize@PHHD QHHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY tring title a @lookendpeelFsplit@4F4AA@lookendpeelFsplit@4F4A Flength E IAY thisFsetitle@4xom du look nd feel X 4 C titleAY listoot@AY GGyn fore l9utilistion try { swngerFsetvookendpeel@lookendpeelAY wingtilitiesFupdtegomponentrees@thisAY } th @snstntitionixeption eA { } th @glssxotpoundixeption eA { } th @nsupportedvookendpeelixeption eA { } th @sllegleessixeption eA {} thisFsetisile@trueAY

GGFFF puli stti void min@tring rgsA{ GGxous llons rer des fentres ve des looks diffrents GGgette instrution permet de ruprer tous les looks du systme swngerFvookendpeelsnfo looks a swngerFgetsnstlledvookendpeels@AY penetre fenY

485

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE


GGyn prourt tout le tleu en pssnt le nom du look utiliser for@int i a HY i ` looksFlengthY iCCA fen a new penetre@looksiFgetglssxme@AAY

J'ai captur les fentres obtenues, voyez la gure 30.9.

Figure

30.9  Dirents  look and feel 

Modier le contenu de nos arbres


C'est maintenant que les choses se compliquent ! Il va falloir faire la lumire sur certaines choses. . . Vous commencez connatre les arbres : cependant, je vous ai cach quelques lments an de ne pas surcharger le dbut de ce chapitre. Votre JTree est en fait compos de plusieurs objets. Voici une liste des objets que vous serez susceptibles d'utiliser avec ce composant (il y a cinq interfaces et une classe concrte. . .) :  TreeModel : c'est lui qui contient les nuds de votre arbre ;  TreeNode : nuds et structure de votre arbre ;  TreeSelectionModel : modle de slection de tous vos nuds ;  TreePath : objet qui vous permet de connatre le chemin d'un nud dans l'arbre. La voil, notre classe concrte ;  TreeCellRenderer : interface permettant de modier l'apparence d'un nud ;  TreeCellEditor : diteur utilis lorsqu'un nud est ditable. Vous allez voir que, mme si ces objets sont nombreux, leur utilisation, avec un peu de pratique, n'est pas aussi complique que a. . . Nous allons commencer par quelque chose d'assez simple : modier le libell d'un nud ! Il faudra commencer par le rendre ditable, via la mthode setEnabled(Boolean bok) de notre JTree. Attention, vous serez peut-tre amens sauvegarder le nouveau nom de votre nud. . . Il faudra donc dclencher un traitement lors de la modication d'un nud. Pour faire cela, nous allons utiliser l'objet TreeModel et l'couter an de dterminer ce qui se passe avec notre arbre ! 486

MODIFIER LE CONTENU DE NOS ARBRES Voici un exemple de code utilisant un DefaultTreeModel (classe implmentant l'interface TreeModel) ainsi qu'une implmentation de l'interface TreeModelListener an d'couter cet objet :
GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme { privte tree rreY privte hefultwutlereexode rineY GGxotre ojet modle privte hefultreewodel modelY puli penetre@A{ thisFsetize@PHHD QHHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tree4AY listoot@AY thisFsetisile@trueAY } privte void listoot@A{ thisFrine a new hefultwutlereexode@AY int ount a HY for@pile file X pileFlistoots@AA { hefultwutlereexode leteur a new hefultwutlereexode@fileFgetesoluteth@AAY try { for@pile nom X fileFlistpiles@AA{ hefultwutlereexode node a new hefultwutlereexode@nomFgetxme@AC44AY leteurFdd@thisFlistpile@nomD nodeAAY } } th @xullointerixeption eA {} thisFrineFdd@leteurAY } GGxous rons notre modle thisFmodel a new hefultreewodel@thisFrineAY GGit nous llons outer e que notre modle nous dire 3 thisFmodelFddreewodelvistener@new reewodelvistener@A { GBB B wthode ppele lorsqu9un noeud hng BG puli void treexodesghnged@reewodelivent evtA { ystemFoutFprintln@4ghngement dns l9rre4AY yjet listxoeuds a evtFgetghildren@AY int listsndies a evtFgetghildsndies@AY for @int i a HY i ` listxoeudsFlengthY iCCA { ystemFoutFprintln@4sndex 4 C listsndiesi C 4D

487

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE


nouvelle vleur X4 C listxoeudsiAY

} } GBB B wthode ppele lorsqu9un noeud est insr BG puli void treexodessnserted@reewodelivent eventA { ystemFoutFprintln@4n noeud t insr 34AY

GBB B wthode ppele lorsqu9un noeud est supprim BG puli void treexodesemoved@reewodelivent eventA { ystemFoutFprintln@4n noeud t retir 34AY } GBB B wthode ppele lorsque l struture d9un noeud t modifie BG puli void treetrutureghnged@reewodelivent eventA { ystemFoutFprintln@4v struture d9un noeud hng 34AY } }AY GGxous ronsD ve notre hirrhieD un rre rre a new tree@AY GGxous pssons notre modle notre rre GGaab yn pouvit ussi psser l9ojet reewodel u onstruteur du tree rreFsetwodel@modelAY rreFsetootisile@flseAY GGyn rend notre rre ditle rreFsetiditle@trueAY thisFgetgontentne@AFdd@new trollne@rreAD fordervyoutFgixiAY

privte hefultwutlereexode listpile@pile fileD hefultwutlereexode nodeA{ int ount a HY if@fileFispile@AA return new hefultwutlereexode@fileFgetxme@AAY else{ pile list a fileFlistpiles@AY if@list aa nullA return new hefultwutlereexode@fileFgetxme@AAY for@pile nom X listA{ ountCCY GGs plus de S enfnts pr noeud if@ount ` QA{

488

MODIFIER LE CONTENU DE NOS ARBRES


hefultwutlereexode suxodeY if@nomFishiretory@AA{ suxode a new hefultwutlereexode@nomFgetxme@AC44AY nodeFdd@thisFlistpile@nomD suxodeAAY }else{ suxode a new hefultwutlereexode@nomFgetxme@AAY } nodeFdd@suxodeAY

} } return nodeY

puli stti void min@tring rgsA{ GGxous llons rer des fentres ve des looks diffrents GGgette instrution permet de ruprer tous les looks du systme try { swngerFsetvookendpeel@swngerFgetystemvookendpeelglssxme@AAY } th @snstntitionixeption eA { } th @glssxotpoundixeption eA { } th @nsupportedvookendpeelixeption eA { } th @sllegleessixeption eA {} penetre fen a new penetre@AY

An de pouvoir changer le nom d'un nud, vous devez double-cliquer dessus avec un intervalle d'environ une demi-seconde entre chaque clic. . . Si vous double-cliquez trop vite, vous dplierez le nud !
Ce code a donn chez moi la gure 30.10. Le dossier  toto  s'appelait  CNAM/  : vous pouvez voir que lorsque nous changeons le nom d'un nud, la mthode treeNodesChanged(TreeModelEvent evt) est invoque ! Vous voyez que, mis part le fait que plusieurs objets sont mis en jeu, ce n'est pas si compliqu que a. . . Maintenant, je vous propose d'xaminer la manire d'ajouter des nuds notre arbre. Pour ce faire, nous allons utiliser un bouton qui va nous demander de spcier le nom du nouveau nud, via un JOptionPane. Voici un code d'exemple :
GGgv C rsp C y pour gnrer les imports nessires puli lss penetre extends tprme { privte tree rreY privte hefultwutlereexode rineY privte hefultreewodel modelY privte tfutton outon a new tfutton@4ejouter4AY

489

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE

Figure

30.10  Changement de la valeur d'un nud

puli penetre@A{ thisFsetize@PHHD QHHAY thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tree4AY GGyn invoque l mthode de onstrution de l9rre listoot@AY outonFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent eventA { if@rreFgetvsteletedthgomponent@A 3a nullA{ typtionne jop a new typtionne@AY tring nodexme a jopFshowsnputhilog@4isir un nom de noeud4AY if@nodexme 3a null 88 3nodexmeFtrim@AFequls@44AA{ hefultwutlereexode prentxode a @hefultwutlereexodeArreFgetvsteletedthgomponent@AY hefultwutlereexode hildxode a new hefultwutlereexode@nodexmeAY prentxodeFdd@hildxodeAY modelFinsertxodesnto@hildxodeD prentxodeD prentxodeFgetghildgount@AEIAY modelFnodeghnged@prentxodeAY }

} }AY thisFgetgontentne@AFdd@outonD fordervyoutFyrAY

} else{ ystemFoutFprintln@4euune sletion 34AY }

490

MODIFIER LE CONTENU DE NOS ARBRES


thisFsetisile@trueAY

privte void listoot@A{ thisFrine a new hefultwutlereexode@AY int ount a HY for@pile file X pileFlistoots@AA { hefultwutlereexode leteur a new hefultwutlereexode@fileFgetesoluteth@AAY try { for@pile nom X fileFlistpiles@AA{ hefultwutlereexode node a new hefultwutlereexode@nomFgetxme@AC44AY leteurFdd@thisFlistpile@nomD nodeAAY } } th @xullointerixeption eA {} thisFrineFdd@leteurAY } GGxous ronsD ve notre hirrhieD un rre rre a new tree@AY thisFmodel a new hefultreewodel@thisFrineAY rreFsetwodel@modelAY rreFsetootisile@flseAY rreFsetiditle@trueAY rreFgetwodel@AFddreewodelvistener@new reewodelvistener@A { puli void treexodesghnged@reewodelivent evtA { ystemFoutFprintln@4ghngement dns l9rre4AY yjet listxoeuds a evtFgetghildren@AY int listsndies a evtFgetghildsndies@AY for @int i a HY i ` listxoeudsFlengthY iCCA { ystemFoutFprintln@4sndex 4 C listsndiesi C 4D noeud dlenheur X 4 C listxoeudsiAY } } puli void treexodessnserted@reewodelivent eventA { ystemFoutFprintln@4n noeud t insr 34AY } puli void treexodesemoved@reewodelivent eventA { ystemFoutFprintln@4n noeud t retir 34AY } puli void treetrutureghnged@reewodelivent eventA { ystemFoutFprintln@4v struture d9un noeud hng 34AY } }AY

491

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE


thisFgetgontentne@AFdd@new trollne@rreAD fordervyoutFgixiAY

privte hefultwutlereexode listpile@pile fileD hefultwutlereexode nodeA{ int ount a HY if@fileFispile@AA return new hefultwutlereexode@fileFgetxme@AAY else{ pile list a fileFlistpiles@AY if@list aa nullA return new hefultwutlereexode@fileFgetxme@AAY for@pile nom X listA{ ountCCY GGs plus de S enfnts pr noeud if@ount ` QA{ hefultwutlereexode suxodeY if@nomFishiretory@AA{ suxode a new hefultwutlereexode@nomFgetxme@AC44AY nodeFdd@thisFlistpile@nomD suxodeAAY }else{ suxode a new hefultwutlereexode@nomFgetxme@AAY } nodeFdd@suxodeAY } } return nodeY

puli stti void min@tring rgsA{ GGxous llons rer des fentres ve des look nd feel diffrents GGgette instrution permet de ruprer tous les look nd feel du systme try { swngerFsetvookendpeel@swngerFgetystemvookendpeelglssxme@AAY } th @snstntitionixeption eA { } th @glssxotpoundixeption eA { } th @nsupportedvookendpeelixeption eA { } th @sllegleessixeption eA {} penetre fen a new penetre@AY } }

Vous remarquerez que nous avons ajout des variables d'instances an d'y avoir accs dans toute notre classe !
492

MODIFIER LE CONTENU DE NOS ARBRES La gure 30.11 nous montre direntes tapes de cration de nuds.

Figure

30.11  Cration de nuds

L non plus, rien d'extraordinairement compliqu, mis part cette portion de code :
prentxode a @hefultwutlereexodeArreFgetvsteletedthgomponent@AY hefultwutlereexode hildxode a new hefultwutlereexode@nodexmeAY hefultwutlereexode prentxodeFdd@hildxodeAY modelFinsertxodesnto@hildxodeD prentxodeD prentxodeFgetghildgount@AEIAY modelFnodeghnged@prentxodeAY

Tout d'abord, nous rcuprons le dernier nud slectionn avec Ensuite, nous crons un nouveau nud avec

parentNode = (DefaultMutableTreeNode)arbre.getLastSelectedPathComponent() . DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(nodeName);

et l'ajoutons dans le nud parent avec l'instruction parentNode.add(childNode); . Cependant, nous devons spcier notre modle qu'il contient un nouveau nud et donc, qu'il a chang, au moyen des instructions :
modelFinsertxodesnto@hildxodeD prentxodeD prentxodeFgetghildgount@AEIAY modelFnodeghnged@prentxodeAY

Pour supprimer un nud, il surait d'appeler model.removeNodeFromParent(node) . Vous pouvez copier le code complet ralis au cours de ce chapitre : Systme complet Code web : 818956 


493

CHAPITRE 30. LES ARBRES ET LEUR STRUCTURE Voil : je pense que vous en savez assez pour utiliser les arbres dans vos futures applications !

En rsum
 Les arbres constituent une combinaison d'objets DefaultMutableTreeNode et d'objets JTree.  Vous pouvez masquer le rpertoire  racine  en invoquant la mthode setRootVisible(Boolean ok) .  An d'intercepter les vnements sur tel ou tel composant, vous devez implmenter l'interface TreeSelectionListener .  Cette interface n'a qu'une mthode rednir : public void valueChanged(TreeSelectionEvent event) .  L'achage des dirents lments constituant un arbre peut tre modi l'aide d'un DefaultTreeCellRenderer . Dnissez et aectez cet objet votre arbre pour en personnaliser l'achage.  Vous pouvez aussi changer le  look and feel  et utiliser celui de votre OS.

494

Chapitre

31
Dicult :

Les interfaces de tableaux

ous continuons notre progression avec un autre composant assez complexe : le tableau. Celui-ci fonctionne un peu comme le JTree vu prcdemment. Les choses se compliquent ds que l'on doit manipuler les donnes l'intrieur du tableau, car Java impose de sparer strictement l'achage et les donnes dans le code.

495

CHAPITRE 31. LES INTERFACES DE TABLEAUX

Premiers pas
Les tableaux sont des composants qui permettent d'acher des donnes de faon structure. Pour ceux qui ne savent pas ce que c'est, en voici un la gure 31.1.

Figure

31.1  Exemple de tableau

Le code source de ce programme est le suivant :


GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme { puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tle4AY thisFsetize@QHHD IPHAY GGves donnes du tleu yjet dt a { {4gysoy4D 4PV ns4D 4IFVH m4}D {4frrydde4D 4PV ns4D 4IFVH m4}D {4smfow4D 4PR ns4D 4IFWH m4}D {4punwn4D 4QP ns4D 4IFVS m4} }Y GGves titres des olonnes tring title a {4seudo4D 4ege4D 4ille4}Y tle tleu a new tle@dtD titleAY GGxous joutons notre tleu notre ontentne dns un sroll GGinon les titres des olonnes ne s9ffiheront ps 3 thisFgetgontentne@AFdd@new trollne@tleuAAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY fenFsetisile@trueAY }

Vous instanciez un objet JTable en lui passant en paramtres les donnes qu'il doit utiliser.

Les titres des colonnes de votre tableau peuvent tre de type String ou de type Object, tandis que les donnes sont obligatoirement de type Object.
496

GESTION DE L'AFFICHAGE

Vous verrez un peu plus loin qu'il est possible de mettre plusieurs types d'lments dans un tableau. Mais nous n'en sommes pas l : il nous faut d'abord comprendre comment fonctionne cet objet. Les plus observateurs auront remarqu que j'ai mis le tableau dans un scroll. . . En fait, si vous avez essay d'ajouter le tableau dans le contentPane sans scroll, vous avez d constater que les titres des colonnes n'apparaissent pas. En eet, le scroll indique automatiquement au tableau l'endroit o il doit acher ses titres ! Sans lui, vous seriez obligs de prciser o acher l'en-tte du tableau, comme ceci :
GGyn indique que l9enEtte doit tre u nordD don uEdessus thisFgetgontentne@AFdd@tleuFgetlereder@AD fordervyoutFxyrAY GGit le orps u entre 3 thisFgetgontentne@AFdd@tleuD fordervyoutFgixiAY

Je pense que nous avons fait le tour des prliminaires. . . Entrons dans le vif du sujet !

Gestion de l'achage
Les cellules
Vos tableaux sont composs de cellules. Vous pouvez les voir facilement, elles sont encadres de bordures noires et contiennent les donnes que vous avez mises dans le tableau d'Object et de String. Celles-ci peuvent tre retrouves par leurs coordonnes (x, y) o x correspond au numro de la ligne et y au numro de la colonne ! Une cellule est donc l'intersection d'une ligne et d'une colonne. An de modier une cellule, il faut rcuprer la ligne et la colonne auxquelles elle appartient. Ne vous inquitez pas, nous allons prendre tout cela point par point. Tout d'abord, commenons par changer la taille d'une colonne et d'une ligne. Le rsultat nal ressemble ce qu'on voit sur la gure 31.2.

Figure

31.2  Changement de taille 497

CHAPITRE 31. LES INTERFACES DE TABLEAUX Vous allez voir que le code utilis est simple comme tout, encore fallait-il que vous sachiez quelles mthodes et quels objets utiliser. . . Voici le code permettant d'obtenir ce rsultat :
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme { privte tle tleuY privte tfutton hnge a new tfutton@4ghnger l tille4AY privte tfutton retlir a new tfutton@4tlir4AY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tle4AY thisFsetize@QHHD PRHAY yjet dt a { {4gysoy4D 4PV ns4D 4IFVH m4}D {4frrydde4D 4PV ns4D 4IFVH m4}D {4smfow4D 4PR ns4D 4IFWH m4}D {4punwn4D 4QP ns4D 4IFVS m4} }Y tring title a {4seudo4D 4ege4D 4ille4}Y thisFtleu a new tle@dtD titleAY tnel pn a new tnel@AY hngeFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { hngeize@PHHD VHAY hngeFsetinled@flseAY retlirFsetinled@trueAY } }AY retlirFddetionvistener@new etionvistener@A{ puli void tionerformed@etionivent rgHA { hngeize@USD ITAY hngeFsetinled@trueAY retlirFsetinled@flseAY

}AY

retlirFsetinled@flseAY pnFdd@hngeAY pnFdd@retlirAY thisFgetgontentne@AFdd@new trollne@tleuAD fordervyoutFgixiAY

498

GESTION DE L'AFFICHAGE
thisFgetgontentne@AFdd@pnD fordervyoutFyrAY

GBB B ghnge l tille d9une ligne et d9une olonne B t9i mis deux oules fin que vous puissiez voir B omment prourir les olonnes et les lignes BG puli void hngeize@int widthD int heightA{ GGxous rons un ojet legolumn fin de trviller sur notre olonne legolumn olY for@int i a HY i ` tleuFgetgolumngount@AY iCCA{ if@i aa IA{ GGyn rupre le modle de l olonne ol a tleuFgetgolumnwodel@AFgetgolumn@iAY GGyn lui ffete l nouvelle vleur olFsetreferredidth@widthAY } } for@int i a HY i ` tleuFgetowgount@AY iCCA{ GGyn ffete l tille de l ligne l9indie spifi 3 if@i aa IA tleuFsetowreight@iD heightAY } } puli stti void min@tring rgsA{ penetre fen a new penetre@AY fenFsetisile@trueAY }

Tout comme pour les tableaux vus dans la premire partie de cet ouvrage, les indices des lignes et des colonnes d'un objet JTable commencent 0 ! Vous constatez que la ligne et la colonne concernes changent bien de taille lors du clic sur les boutons. Vous venez donc de voir comment changer la taille des cellules de faon dynamique. Je dis a parce que, au cas o vous ne l'auriez pas remarqu, vous pouvez changer la taille des colonnes manuellement. Il vous sut de cliquer sur un sparateur de colonne, de maintenir le clic et de dplacer le sparateur (gure 31.3).

Figure

31.3  Sparateurs

Par contre, cette instruction a d vous sembler trange : tableau.getColumnModel().getColumn(i); . En fait, vous devez savoir que c'est un 499

CHAPITRE 31. LES INTERFACES DE TABLEAUX objet qui fait le lien entre votre tableau et vos donnes. Celui-ci est ce qu'on appelle un modle de tableau (a vous rappelle les modles d'arbres, non ?). L'objet en question s'appelle JTableModel et vous allez voir qu'il permet de faire des choses trs intressantes ! C'est lui qui stocke vos donnes. . . Toutes vos donnes ! Tous les types hritant de la classe Object sont accepts. Essayez ce morceau de code :
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme { privte tle tleuY privte tfutton hnge a new tfutton@4ghnger l tille4AY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tle4AY thisFsetize@THHD IRHAY yjet dt a { {4gysoy4D new tfutton@4Toy4AD new houle@IFVHAD new foolen@trueA}D {4frrydde4D new tfutton@4fr4AD new houle@IFUVAD new foolen@flseA}D {4smfow4D new tfutton@4fo4AD new houle@IFWHAD new foolen@flseA}D {4punwn4D new tfutton@4er4AD new houle@IFVSAD new foolen@trueA} }Y tring title a {4seudo4D 4ege4D 4ille4D 4yu c4}Y thisFtleu a new tle@dtD titleAY thisFgetgontentne@AFdd@new trollne@tleuAD fordervyoutFgixiAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY fenFsetisile@trueAY }

Vous devriez obtenir un rsultat similaire celui prsent la gure 31.4.

Figure

31.4  Dirents objets dans un tableau

Pour tre le plus exible possible, on doit crer son propre modle qui va stocker les 500

GESTION DE L'AFFICHAGE donnes du tableau. Il vous sut de crer une classe hritant de AbstractTableModel qui  vous l'avez srement devin  est une classe abstraite. . . Voici donc un code pour tayer mes dires :
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme { privte tle tleuY privte tfutton hnge a new tfutton@4ghnger l tille4AY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tle4AY thisFsetize@THHD IRHAY yjet dt a { {4gysoy4D new tfutton@4Toy4AD new houle@IFVHAD new foolen@trueA}D {4frrydde4D new tfutton@4fr4AD new houle@IFUVAD new foolen@flseA}D {4smfow4D new tfutton@4fo4AD new houle@IFWHAD new foolen@flseA}D {4punwn4D new tfutton@4er4AD new houle@IFVSAD new foolen@trueA} }Y tring title a {4seudo4D 4ege4D 4ille4D 4yu c4}Y

wodel model a new wodel@dtD titleAY ystemFoutFprintln@4xomre de olonne X 4 C modelFgetgolumngount@AAY ystemFoutFprintln@4xomre de ligne X 4 C modelFgetowgount@AAY thisFtleu a new tle@modelAY thisFgetgontentne@AFdd@new trollne@tleuAD fordervyoutFgixiAY

GGglsse modle personnlise lss wodel extends estrtlewodel{ privte yjet dtY privte tring titleY GGgonstruteur puli wodel@yjet dtD tring titleA{ thisFdt a dtY thisFtitle a titleY } GGetourne le nomre de olonnes puli int getgolumngount@A { return thisFtitleFlengthY } GGetourne le nomre de lignes

501

CHAPITRE 31. LES INTERFACES DE TABLEAUX


puli int getowgount@A { return thisFdtFlengthY } GGetourne l vleur l9emplement spifi puli yjet getlueet@int rowD int olA { return thisFdtrowolY }

puli stti void min@tring rgsA{ penetre fen a new penetre@AY fenFsetisile@trueAY }

Le rsultat en gure 31.5.

Figure

31.5  Utilisation d'un modle de tableau

Bon. . . Vous ne voyez plus les titres des colonnes. Ceci est d au fait que vous n'avez redni que les mthodes abstraites de la classe AbstractTableModel. Si nous voulons voir nos titres de colonnes apparatre, il faut rednir la mthode getColumnName(int col). Elle devrait ressembler ceci :
GBB B etourne le titre de l olonne l9indie spif BG puli tring getgolumnxme@int olA { return thisFtitleolY }

Excutez nouveau votre code, aprs avoir rajout cette mthode dans votre objet ZModel : vous devriez avoir le mme rendu que la gure 31.6. Regardez la gure 31.7 pour comprendre l'intrt de grer sa propre classe de modle. Vous avez vu ? Les boolens se sont transforms en cases cocher ! Les boolens valant vrai sont devenus des cases coches et les boolens valant faux sont maintenant des cases non coches ! Pour obtenir a, j'ai redni une mthode dans mon modle et le reste est automatique. Cette mthode permet de retourner la classe du type de valeur d'un modle et de transformer vos boolens en cases cocher. . . Au moment o notre 502

GESTION DE L'AFFICHAGE

Figure

31.6  Achage des titres de colonnes

Figure

31.7  Achage de checkbox

objet cre le rendu des cellules, il invoque cette mthode et s'en sert pour crer certaines choses, comme ce que vous venez de voir. Pour obtenir ce rendu, il vous sut de rednir la mthode getColumnClass(int col) . Cette mthode retourne un objet Class. Je vous laisse rchir un peu. . . Pour savoir comment faire, c'est juste en dessous :
GGetourne l lsse de l donne de l olonne puli glss getgolumnglss@int olA{ GGyn retourne le type de l ellule l olonne demnde GGyn se moque de l ligne puisque les types de donnes GGsont les mmes quelle que soit l ligne GGyn hoisit don l premire ligne return thisFdtHolFgetglss@AY }

Je ne sais pas si vous avez remarqu, mais vos cellules ne sont plus ditables ! Je vous avais prvenus que ce composant tait pnible. . . En fait, vous devez aussi informer votre modle qu'il faut avertir l'objet JTable que certaines cellules peuvent tre dites et d'autres pas (le bouton, par exemple). Pour ce faire, il faut rednir la mthode isCellEditable(int row, int col) qui, dans la classe mre, retourne systmatiquement false. . . Ajoutez donc ce morceau de code dans votre modle pour renvoyer true :
GGetourne vri si l ellule est ditle X elleEi ser don ditle puli oolen isgelliditle@int rowD int olA{ return trueY }

Vos cellules sont nouveau ditables. Cependant, vous n'avez pas prcis au modle que la cellule contenant le bouton n'est pas cense tre ditable. . . Comment rgler ce 503

CHAPITRE 31. LES INTERFACES DE TABLEAUX problme ? Grce la mthode getClass() de tout objet Java ! Vous pouvez dterminer de quelle classe est issu votre objet grce au mot-cl instanceof. Regardez comment on procde :
GGetourne vri si l ellule est ditle X elleEi ser don ditle puli oolen isgelliditle@int rowD int olA{ GGyn ppelle l mthode getlueet qui retourne l vleur d9une ellule GGet on effetue un tritement spifique si 9est un tfutton if@getlueet@HD olA instneof tfuttonA return flseY return trueY }

Victoire ! Les cellules sont nouveau ditables, sauf le JButton. D'ailleurs, je suppose que certains d'entre vous attendent toujours de le voir apparatre, bouton. . . Pour cela, nous n'allons pas utiliser un modle de tableau, mais un objet qui s'occupe de grer le contenu et la faon dont celui-ci est ach. Les modles font un pont entre ce qu'ache JTable et les actions de l'utilisateur. Pour modier l'achage des cellules, nous devrons utiliser DefaultCellRenderer.

Contrlez l'achage
Vous devez bien distinguer un TableModel d'un DefaultTableCellRenderer . Le premier fait le lien entre les donnes et le tableau tandis que le second s'occupe de grer l'achage dans les cellules ! Le but du jeu est de dnir une nouvelle faon de dessiner les composants dans les cellules. En dnitive, nous n'allons pas vraiment faire cela, mais dire notre tableau que la valeur contenue dans une cellule donne est un composant (bouton ou autre). Il sut de crer une classe hritant de DefaultTableCellRenderer et de rednir la mthode
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) .

Il y en a, des paramtres ! Mais, dans le cas qui nous intresse, nous n'avons besoin que d'un seul d'entre eux : value. Remarquez que cette mthode retourne un objet Component. Nous allons seulement spcier le type d'objet dont il s'agit suivant le cas. Regardez notre classe hrite :
GGgv C rsp C y pour gnrer les imports puli lss legomponent extends hefultlegellenderer { puli gomponent getlegellenderergomponent@tle tleD yjet vlueD oolen iseletedD oolen hspousD int rowD int olumnA { GGi l vleur de l ellule est un tfuttonD on trnstype ette vleur if @vlue instneof tfuttonA{

504

GESTION DE L'AFFICHAGE
return @tfuttonA vlueY } else return thisY

Une fois cette classe cre, il sut de signaler notre tableau qu'il doit utiliser ce rendu de cellules grce l'instruction this.tableau.setDefaultRenderer(JButton.class, new TableComponent()); . Le premier paramtre permet de dire notre tableau de faire attention ce type d'objet et enn, le second lui dit d'utiliser ce modle de cellules. Cela nous donne la gure 31.8.

Figure

31.8  Achage des boutons

Voil notre bouton en chair et en os ! Je me doute bien que les plus taquins d'entre vous ont d essayer de mettre plus d'un type de composant dans le tableau. . . Et ils se retrouvent le bec dans l'eau car il ne prend en compte que les boutons pour le moment. En fait, une fois que vous avez dni une classe hrite an de grer le rendu de vos cellules, vous avez fait le plus gros du travail. . . Tenez, si, par exemple, nous voulons mettre ce genre de donnes dans notre tableau :
yjet dt a { {4gysoy4D new tfutton@4Toy4AD new tgomofox@new tring{4toto4D {4frrydde4D new tfutton@4fr4AD new tgomofox@new tring{4toto4D {4smfow4D new tfutton@4fo4AD new tgomofox@new tring{4toto4D {4punwn4D new tfutton@4er4AD new tgomofox@new tring{4toto4D }Y

4titi4D 4tt4}AD new foolen@trueA}D 4titi4D 4tt4}AD new foolen@flseA}D 4titi4D 4tt4}AD new foolen@flseA}D 4titi4D 4tt4}AD new foolen@trueA}

. . . et si nous conservons l'objet de rendu de cellules tel qu'il est actuellement, nous obtiendrons la gure 31.9. Les boutons s'achent toujours, mais pas les combos ! Je sais que certains d'entre vous ont presque trouv la solution. Vous n'auriez pas ajout ce qui suit dans votre objet de rendu de cellule ?
GGgv C rsp C y pour gnrer les imports puli lss legomponent extends hefultlegellenderer {

505

CHAPITRE 31. LES INTERFACES DE TABLEAUX

Figure

31.9  Problme d'achage d'une combo

puli gomponent getlegellenderergomponent@tle tleD yjet vlueD oolen iseletedD oolen hspousD int rowD int olumnA { if @vlue instneof tfuttonA{ return @tfuttonA vlueY } GGvignes joutes else if@vlue instneof tgomofoxA{ return @tgomofoxA vlueY } else return thisY

Ceux qui ont fait cela ont trouv la premire partie de la solution ! Vous avez bien spci votre objet de retourner une valeur caste en cas de rencontre avec une combo. Seulement, et j'en suis quasiment sr, vous avez d oublier de dire votre tableau de faire attention aux boutons et aux combos ! Rappelez-vous cette instruction : this.tableau.setDefaultRenderer(JButton.class, new TableComponent()); . Votre tableau ne fait attention qu'aux boutons ! Pour corriger le tir, il faut simplement changer JButton.class en JComponent.class. Aprs avoir fait ces deux modications, vous devriez parvenir la gure 31.10.

Figure

31.10  Combos et boutons dans un tableau

Maintenant, vous devriez avoir saisi la manire d'utiliser les modles de tableaux et les rendus de cellules. . . Cependant, vous aurez constat que vos composants sont inertes ! C'est d au fait que vous allez devoir grer vous-mmes la faon dont ragissent les 506

GESTION DE L'AFFICHAGE cellules. Cependant, avant d'aborder ce point, nous allons nous pencher sur une autre faon d'acher correctement des composants dans un JTable. Nous pouvons laisser de ct notre classe servant de modle et nous concentrer sur les composants. Commenons par revenir un code plus sobre :
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme { privte tle tleuY privte tfutton hnge a new tfutton@4ghnger l tille4AY puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tle4AY thisFsetize@THHD IVHAY yjet dt a { {4gysoy4D 4Toy4D 4gomo4D new foolen@trueA}D {4frrydde4D 4fr4D 4gomo4D new foolen@flseA}D {4smfow4D 4fo4D 4gomo4D new foolen@flseA}D {4punwn4D 4er4D 4gomo4D new foolen@trueA} }Y tring title a {4seudo4D 4ege4D 4ille4D 4yu c4}Y

thisFtleu a new tle@dtD titleAY thisFtleuFsetowreight@QHAY thisFgetgontentne@AFdd@new trollne@tleuAD fordervyoutFgixiAY } puli stti void min@tring rgsA{ penetre fen a new penetre@AY fenFsetisile@trueAY

De l, nous allons crer une classe qui achera un bouton dans les cellules de la seconde colonne et une combo dans les cellules de la troisime colonne. . . Le principe est simple : crer une classe qui hritera de la classe JButton et qui implmentera l'interface TableCellRenderer. Nous allons ensuite dire notre tableau qu'il doit utiliser utiliser ce type de rendu pour la seconde colonne. Voici notre classe ButtonRenderer :
GGgv C rsp C y pour gnrer les imports puli lss futtonenderer extends tfutton implements legellenderer{ puli gomponent getlegellenderergomponent@tle tleD yjet vlueD

507

CHAPITRE 31. LES INTERFACES DE TABLEAUX


oolen iseletedD oolen ispousD int rowD int olA { GGyn rit dns le outon e que ontient l ellule setext@@vlue 3a nullA c vlueFtotring@A X 44AY GGyn retourne notre outon return thisY

Il nous sut maintenant de mettre jour le tableau grce l'instruction

this.tableau.getColumn("Age").setCellRenderer(newButtonRenderer()); : on

rcupre la colonne grce son titre, puis on applique le rendu ! Rsultat en gure 31.11.

Figure

31.11  Objet de rendu de bouton

Votre bouton est de nouveau ditable, mais ce problme sera rgl par la suite. . . Pour le rendu de la cellule numro 3, je vous laisse un peu chercher, ce n'est pas trs dicile maintenant que vous avez appris cette mthode. Voici le code ; la gure 31.12 vous montre le rsultat.
GGgv C rsp C y pour gnrer les imports puli lss gomoenderer extends tgomofox implements legellenderer { puli gomponent getlegellenderergomponent@tle tleD yjet vlueD oolen iseletedD oolen ispousD int rowD int olA { thisFddstem@4rs ien4AY thisFddstem@4fien4AY thisFddstem@4wl4AY return thisY }

Interaction avec l'objet JTable


Dernire ligne droite avant la n du chapitre. . . Nous commencerons par le plus dicile et terminerons par le plus simple ! Je vous le donne en mille : le composant le plus dicile utiliser dans un tableau, entre un bouton et une combo c'est. . . le bouton ! 508

INTERACTION AVEC L'OBJET JTABLE

Figure

31.12  Rendu d'une combo

Eh oui, vous verrez que la combo est gre presque automatiquement, alors qu'il vous faudra dire aux boutons ce qu'ils devront faire. . . Pour arriver cela, nous allons crer une classe qui permettra notre tableau d'eectuer des actions spciques grce aux boutons.
GGgv C rsp C y pour gnrer les imports puli lss futtoniditor extends hefultgelliditor { proteted tfutton uttonY privte oolen isushedY privte futtonvistener vistener a new futtonvistener@AY GGgonstruteur ve une ghekfox puli futtoniditor@tghekfox hekfoxA { GGr dfutD e type d9ojet trville ve un tghekfox super@hekfoxAY GGyn re nouveu un outon utton a new tfutton@AY uttonFsetypque@trueAY GGyn lui ttriue un listener uttonFddetionvistener@vistenerAY } puli gomponent getlegelliditorgomponent@tle tleD yjet vlueD oolen iseletedD int rowD int olumnA { GGyn prise le numro de ligne notre listener vistenerFsetow@rowAY GGsdem pour le numro de olonne vistenerFsetgolumn@olumnAY GGyn psse ussi le tleu en prmtre pour des tions potentielles vistenerFsetle@tleAY GGyn rffete le liell u outon uttonFsetext@ @vlue aa nullA c 44 X vlueFtotring@A AY GGyn renvoie le outon return uttonY

GGxotre listener pour le outon lss futtonvistener implements etionvistener{

509

CHAPITRE 31. LES INTERFACES DE TABLEAUX


privte int olumnD rowY privte tle tleY privte int nre a HY puli void setgolumn@int olA{thisFolumn a olY} puli void setow@int rowA{thisFrow a rowY} puli void setle@tle tleA{thisFtle a tleY} puli void tionerformed@etionivent eventA { GGyn ffihe un messgeD mis vous pourriez GGeffetuer les tritements que vous voulez ystemFoutFprintln@4ouou du outon X 4 C @@tfuttonAeventFgetoure@AAFgetext@AAY GGyn ffete un nouveu liell une utre ellule de l ligne tleFsetlueet@4xew lue 4 C @CCnreAD thisFrowD @thisFolumn EIAAY }

Ce code n'est pas trs dicile comprendre. . . Vous commencez avoir l'habitude de manipuler ce genre d'objet. Maintenant, an d'utiliser cet objet avec notre tableau, nous allons lui indiquer l'existence de cet diteur dans la colonne correspondante avec cette instruction : this.tableau.getColumn("Age").setCellEditor(new ButtonEditor(new JCheckBox())); . Le rendu (gure 31.13) est trs probant.

Figure

31.13  Bouton actif

Vous pouvez voir que lorsque vous cliquez sur un bouton, la valeur dans la cellule situe juste gauche est modie. L'utilisation est donc trs simple. Imaginez par consquent que la gestion des combos est encore plus aise ! Un peu plus tt, je vous ai fait dvelopper une classe permettant d'acher la combo normalement. Cependant, il y a beaucoup plus facile. . . Vous avez pu voir que la classe DefaultCellEditor pouvait prendre un objet en paramtre : dans l'exemple du JButton, il utilisait un JCheckBox. Vous devez savoir que cet objet accepte d'autres types de paramtres :  un JComboBox ;  un JTextField. Nous pouvons donc utiliser l'objet DefaultCellEditor directement en lui passant une combo en paramtre. . . Nous allons aussi enlever l'objet permettant d'acher 510

INTERACTION AVEC L'OBJET JTABLE correctement la combo an que vous puissiez juger de l'ecacit de cette mthode. Voici le nouveau code du constructeur de notre fentre :
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme { privte tle tleuY privte tfutton hnge a new tfutton@4ghnger l tille4AY GGgontenu de notre omo privte tring omoht a {4rs ien4D 4fien4D 4wl4}Y puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tle4AY thisFsetize@THHD IVHAY GGhonnes de notre tleu yjet dt a { {4gysoy4D 4Toy4D omohtHD new foolen@trueA}D {4frrydde4D 4fr4D omohtHD new foolen@flseA}D {4smfow4D 4fo4D omohtHD new foolen@flseA}D {4punwn4D 4er4D omohtHD new foolen@trueA} }Y GGitre du tleu tring title a {4seudo4D 4ege4D 4ille4D 4yu c4}Y GGgomo utiliser tgomofox omo a new tgomofox@omohtAY thisFtleu a new tle@dtD titleAY thisFtleuFsetowreight@QHAY thisFtleuFgetgolumn@4ege4AFsetgellenderer@new futtonenderer@AAY thisFtleuFgetgolumn@4ege4AFsetgelliditor@new futtoniditor@new tghekfox@AAAY GGyn dfinit l9diteur pr dfut pour l ellule GGen lui spifint quel type d9ffihge prendre en ompte thisFtleuFgetgolumn@4ille4AFsetgelliditor@new hefultgelliditor@omoAAY thisFgetgontentne@AFdd@new trollne@tleuAD fordervyoutFgixiAY

puli stti void min@tring rgsA{ penetre fen a new penetre@AY fenFsetisile@trueAY }

C'est d'une simplicit enfantine ! Le rsultat est, en plus, trs convaincant (gure 31.14). Votre cellule se  transforme  en combo lorsque vous cliquez dessus ! En fait, lorsque le tableau sent une action sur cette cellule, il utilise l'diteur que vous avez spci 511

CHAPITRE 31. LES INTERFACES DE TABLEAUX

Figure

31.14  DefaultCellEditor et combo

pour celle-ci. Si vous prfrez que la combo soit ache directement mme sans clic de souris, il vous sut de laisser l'objet grant l'achage et le tour est jou. De mme, pour le bouton, si vous enlevez l'objet de rendu du tableau, celui-ci s'ache comme un bouton lors du clic sur la cellule ! Il ne nous reste plus qu' voir comment rajouter des informations dans notre tableau, et le tour est jou.

Certains d'entre vous l'auront remarqu, les boutons ont un drle de comportement. Cela est d au fait que vous avez aect des comportements spciaux votre tableau. . . Il faut donc dnir un modle utiliser an de bien dnir tous les points comme l'achage, la mise jour, etc.
Nous allons donc utiliser un modle de tableau personnalis o les actions seront dnies par nos soins. Voici la classe Fenetre modie en consquence :
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme { privte tle tleuY privte tfutton hnge a new tfutton@4ghnger l tille4AY GGgontenu de notre omo privte tring omoht a {4rs ien4D 4fien4D 4wl4}Y puli penetre@A{ thisFsetvotioneltiveo@nullAY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetitle@4tle4AY thisFsetize@THHD IVHAY GGhonnes de notre tleu yjet dt a { {4gysoy4D 4Toy4D omohtHD new foolen@trueA}D {4frrydde4D 4fr4D omohtHD new foolen@flseA}D {4smfow4D 4fo4D omohtHD new foolen@flseA}D {4punwn4D 4er4D omohtHD new foolen@trueA} }Y tring title a {4seudo4D 4ege4D 4ille4D 4yu c4}Y tgomofox omo a new tgomofox@omohtAY

512

INTERACTION AVEC L'OBJET JTABLE

GGxous devons utiliser un modle d9ffihge spifique pour pllier GGles ugs d9ffihge 3 wodel zwodel a new wodel@dtD titleAY thisFtleu a new tle@zwodelAY thisFtleuFsetowreight@QHAY thisFtleuFgetgolumn@4ege4AFsetgellenderer@new futtonenderer@AAY thisFtleuFgetgolumn@4ege4AFsetgelliditor@new futtoniditor@new tghekfox@AAAY GGyn dfinit l9diteur pr dfut pour l ellule GGen lui spifint quel type d9ffihge prendre en ompte thisFtleuFgetgolumn@4ille4AFsetgelliditor@new hefultgelliditor@omoAAY thisFgetgontentne@AFdd@new trollne@tleuAD fordervyoutFgixiAY

lss wodel extends estrtlewodel{ privte yjet dtY privte tring titleY GGgonstruteur puli wodel@yjet dtD tring titleA{ thisFdt a dtY thisFtitle a titleY } GGetourne le titre de l olonne l9indie spifi puli tring getgolumnxme@int olA { return thisFtitleolY } GGetourne le nomre de olonnes puli int getgolumngount@A { return thisFtitleFlengthY } GGetourne le nomre de lignes puli int getowgount@A { return thisFdtFlengthY } GGetourne l vleur l9emplement spifi puli yjet getlueet@int rowD int olA { return thisFdtrowolY } GGhfinit l vleur l9emplement spifi puli void setlueet@yjet vlueD int rowD int olA {

513

CHAPITRE 31. LES INTERFACES DE TABLEAUX


GGyn interdit l modifition sur ertines olonnes 3 if@3thisFgetgolumnxme@olAFequls@4ege4A 88 3thisFgetgolumnxme@olAFequls@4uppression4AA thisFdtrowol a vlueY

GGetourne l lsse de l donne de l olonne puli glss getgolumnglss@int olA{ GGyn retourne le type de l ellule l olonne demnde GGyn se moque de l ligne puisque les types de donnes GGsont les mmes quelle que soit l ligne GGyn hoisit don l premire ligne return thisFdtHolFgetglss@AY } puli oolen isgelliditle@int rowD int olA{ return trueY }

puli stti void min@tring rgsA{ penetre fen a new penetre@AY fenFsetisile@trueAY }

Vous aurez remarqu que nous construisons notre tableau par le biais de notre modle, ce qui implique que nous devrons galement passer par le modle pour modier le tableau ! Consquence directe : il va falloir modier un peu notre classe ButtonEditor. Voici la classe ButtonEditor utilisant le modle de tableau pour grer la modication des valeurs :
GGgv C rsp C y pour gnrer les imports puli lss futtoniditor extends hefultgelliditor { proteted tfutton uttonY privte oolen isushedY privte futtonvistener vistener a new futtonvistener@AY puli futtoniditor@tghekfox hekfoxA { super@hekfoxAY utton a new tfutton@AY uttonFsetypque@trueAY uttonFddetionvistener@vistenerAY } puli gomponent getlegelliditorgomponent@tle tleD yjet vlueD oolen iseletedD int rowD int olumnA { GGyn ffete le numro de ligne u listener

514

AJOUTER DES LIGNES ET DES COLONNES


vistenerFsetow@rowAY GGsdem pour le numro de olonne vistenerFsetgolumn@olumnAY GGyn psse ussi le tleu en prmtre pour des tions potentielles vistenerFsetle@tleAY GGyn rffete le liell u outon uttonFsetext@ @vlue aa nullA c 44 X vlueFtotring@A AY GGyn renvoie le outon return uttonY

GGxotre listener pour le outon lss futtonvistener implements etionvistener{ privte privte privte privte int olumnD rowY tle tleY int nre a HY tfutton uttonY

puli void setgolumn@int olA{thisFolumn a olY} puli void setow@int rowA{thisFrow a rowY} puli void setle@tle tleA{thisFtle a tleY} puli tfutton getfutton@A{return thisFuttonY} puli void tionerformed@etionivent eventA { ystemFoutFprintln@4ouou du outon X 4 C @@tfuttonAeventFgetoure@AAFgetext@AAY GGyn ffete un nouveu liell une elulle de l ligne @@estrtlewodelAtleFgetwodel@AA Fsetlueet@4xew lue 4 C @CCnreAD thisFrowD @thisFolumn EIAAY GGermet de dire notre tleu qu9une vleur hng GG l9emplement dtermin pr les vleurs psses en prmtres @@estrtlewodelAtleFgetwodel@AA Ffirelegellpdted@thisFrowD thisFolumn E IAY thisFutton a @@tfuttonAeventFgetoure@AAY }

Voil : dsormais, le bug d'achage devrait avoir disparu ! Je vous propose donc de continuer sur notre lance.

Ajouter des lignes et des colonnes


Je vais proter de ce point pour vous montrer une autre faon d'initialiser un tableau : 515

CHAPITRE 31. LES INTERFACES DE TABLEAUX


GGdt et title sont toujours nos tleux d9ojets 3 tle tleu a new tle@new hefultlewodel@dtD titleAAY

L'intrt ? C'est trs simple : l'ajout et la suppression dynamiques d'entres dans un tableau se font via un modle de rendu, vous vous en doutiez. Cependant, avec cette notation, vous conomisez une ligne de code et vous avez la possibilit d'aecter diverses tches votre modle de rendu, comme, par exemple, formater les donnes. . . Dans un premier temps, ajoutons et retirons des lignes notre tableau. Nous garderons le mme code que prcdemment avec deux ou trois ajouts :  le bouton pour ajouter une ligne ;  le bouton pour eacer une ligne. Le modle par dfaut dni lors de la cration du tableau nous donne accs deux mthodes fort utiles :  addRow(Object[] lineData) : ajoute une ligne au modle et met automatiquement jour le tableau ;  removeRow(int row) : eace une ligne du modle et met automatiquement jour le tableau. Avant de pouvoir utiliser ce modle, nous allons devoir le rcuprer. En fait, c'est notre tableau qui va nous le fournir en invoquant la mthode getModel() qui retourne un objet TableModel. Attention, un cast sera ncessaire an de pouvoir utiliser l'objet rcupr ! Par exemple : ((ZModel)table.getModel()).removeRow() . Au nal, la gure 31.15 nous montre ce que nous obtiendrons. Vous constatez que j'ai ajout un bouton  Ajouter une ligne  ainsi qu'un bouton  Supprimer la ligne  ; mis part a, l'IHM n'a pas chang. Essayez de dvelopper ces nouvelles fonctionnalits. Pour tlcharger le code complet du chapitre, utilisez le code web suivant : Copier le code Code web : 433848 


En rsum
 Pour utiliser le composant  tableau , vous devrez utiliser l'objet JTable.  Celui-ci prend en paramtres un tableau d'objets deux dimensions (un tableau de donnes) correspondant aux donnes acher, et un tableau de chanes de caractres qui, lui, achera les titres des colonnes.  An de grer vous-mmes le contenu du tableau, vous pouvez utiliser un modle de donnes (TableModel).  Pour ajouter ou retirer des lignes un tableau, il faut passer par un modle de donnes. Ainsi, l'achage est mis jour automatiquement.  Il en va de mme pour l'ajout et la suppression de colonnes.  La gestion de l'achage brut (hors dition) des cellules peut se grer colonne par colonne l'aide d'une classe drivant de TableCellRenderer. 516

AJOUTER DES LIGNES ET DES COLONNES

Figure

31.15  Ajout et suppression de lignes

517

CHAPITRE 31. LES INTERFACES DE TABLEAUX  La gestion de l'achage brut lors de l'dition d'une cellule se gre colonne par colonne avec une classe drivant de DefaultCellEditor.

518

Chapitre

32
Dicult :

TP : le pendu

e TP est srement le plus dicile que vous aurez raliser ! Il fait appel beaucoup d'lments vus prcdemment. Nous allons devoir raliser un jeu de pendu. Le principe est classique : vous devez trouver un mot secret lettre par lettre en faisant un minimum d'erreurs. Nous en proterons pour utiliser des design patterns, ces fameuses bonnes pratiques de programmation.

519

CHAPITRE 32. TP : LE PENDU

Cahier des charges


Vous devez raliser un jeu du pendu en Java grant la sauvegarde des dix meilleurs scores. Toutefois, j'ai des exigences prcises :  l'application doit contenir les menus  Nouveau ,  Scores ,  Rgles  et  propos  ;  une page d'accueil doit tre mise en place ;  les points doivent tre cumuls en tenant compte des mots trouvs et des erreurs commises ;  il faut vrier si le joueur est dans le top dix, auquel cas on lui demande son pseudo, on enregistre les donnes et on le redirige vers la page des scores ;  si le joueur n'a pas assez de points, on le redirige vers la page d'accueil ;  il faut essayer d'utiliser le pattern observer. Les rgles du jeu sont reprsentes en gure 32.1.

Figure

32.1  cran principal

Vous pouvez voir les crans que j'ai obtenus en gure 32.2. Je vous fournis galement les images que j'ai utilises pour raliser ce pendu.


Tlcharger les images Code web : 259119 

520

CAHIER DES CHARGES

Figure

32.2  Captures d'cran du TP

521

CHAPITRE 32. TP : LE PENDU Vous aurez besoin d'un chier - dictionnaire contenant de nombreux mots pour votre jeu : Tlcharger le chier Code web : 588152  Il me reste encore quelques recommandations vous prodiguer. . .


Prrequis
Vous devrez utiliser les ux an de parcourir le chier texte qui contient plus de 336 000 lignes : il faudra donc choisir un nombre alatoire entre 0 et 336 529, puis rcuprer le mot dsign. Pour obtenir un nombre alatoire entre 0 et 336 529, j'ai cod ceci :
int nre a @intA@wthFrndom@ABQQTSPWAY

An de rcuprer les mots ligne par ligne, j'ai utilis un LineNumberReader : puisque cet objet retourne le numro de la ligne en invoquant la mthode getLineNumber(), il tait tout indiqu ! Il y a aussi un point qui peut vous poser problme : la mise jour du JPanel. Pour ma part, j'ai choisi la technique suivante : tout retirer du conteneur grce la mthode removeAll(), replacer des composants puis invoquer la mthode revalidate() an de modier l'achage. Il faudra galement que vous pensiez grer les caractres accentus, lorsque vous cliquerez sur le bouton  E  par exemple. Vous devrez donc aussi acher les lettres  E  accentues. Je ne vais pas tout vous dvoiler, il serait dommage de gcher le plaisir. En revanche, j'insiste sur le fait que c'est un TP dicile, et qu'il vous faudra certainement plusieurs heures avant d'en venir bout. Prenez donc le temps de dterminer les problmes, rchissez bien et codez proprement ! Je vous conseille vivement d'aller relire les chapitres traitant des design patterns, car j'en ai utilis ici ; de plus, j'ai rang mes classes en packages. Allez, en avant les Zros !

Correction
Une fois n'est pas coutume, je ne vais pas inscrire ici tous les codes source, mais vais plutt vous fournir tout mon projet Eclipse contenant un .jar excutable ; et pour cause, il contient beaucoup de classes (gure 32.3). Rcuprer le projet Code web : 528713  Voici donc une astuce d'Eclipse permettant de rapatrier un projet. Une fois Eclipse ouvert, eectuez un clic droit dans la zone o se trouvent vos projets, puis cliquez sur Import et choisissez Existing project dans General (gure 32.4). 522


CORRECTION

Figure

32.3  Classes du TP

Figure

32.4  Importer un projet existant dans Eclipse 523

CHAPITRE 32. TP : LE PENDU Il ne vous reste plus qu' spcier l'endroit o vous avez dcompress l'archive .jar que je vous ai fournie, et le tour est jou.

Une fois dcompresse, vous devriez pouvoir lancer le chier .jar par un double-clic. Si rien ne se produit, mettez jour vos variables d'environnement 1 .
Prenez bien le temps de lire et comprendre le code. Si vous n'arrivez pas tout faire maintenant, essayez de commencer par raliser les choses les plus simples, vous pourrez toujours amliorer votre travail plus tard lorsque vous vous sentirez plus l'aise ! Vous pourrez constater que j'ai rang mon code d'une faon assez trange, avec un package com.sdz.model et un com.sdz.vue. . . Cette faon de procder correspond un autre pattern de conception permettant de sparer le code en couches capables d'interagir entre elles : c'est le sujet du chapitre suivant.

1. Voir le premier chapitre.

524

Chapitre

33
Dicult :

Mieux structurer son code : le pattern MVC

e chapitre va vous prsenter un des design patterns les plus connus : MVC. Il va vous apprendre dcouper vos codes en trois parties : modle, vue et contrleur. C'est un pattern compos, ce qui signie qu'il est constitu d'au moins deux patterns (mais rien n'empche qu'il y en ait plus). Nous allons voir cela tout de suite, inutile de tergiverser plus longtemps !

525

CHAPITRE 33. MIEUX STRUCTURER SON CODE : LE PATTERN MVC

Premiers pas
Dans les chapitres prcdents, nous avons agi de la manire suivante :  mise en place d'une situation ;  examen de ce que nous pouvions faire ;  dcouverte du pattern. Ici, nous procderons autrement : puisque le pattern MVC est plus complexe aborder, nous allons entrer directement dans le vif du sujet. Le schma de la gure 33.1 en dcrit le principe ; il ne devrait pas tre tranger ceux d'entre vous qui auraient dj fait quelques recherches concernant ce pattern.

Figure

33.1  Schma du pattern MVC

Avant d'expliquer ce schma, nous devons faire le point sur ce que sont rellement ces trois entits.

La vue
Ce que l'on nomme  la vue  est en fait une IHM. Elle reprsente ce que l'utilisateur a sous les yeux. La vue peut donc tre :  une application graphique Swing, AWT, SWT pour Java (Form pour C#. . .) ;  une page web ;  un terminal Linux ou une console Windows ;  etc. 526

PREMIERS PAS

Le modle
Le modle peut tre divers et vari. C'est l que se trouvent les donnes. Il s'agit en gnral d'un ou plusieurs objets Java. Ces objets s'apparentent gnralement ce qu'on appelle souvent  la couche mtier  de l'application et eectuent des traitements absolument transparents pour l'utilisateur. Par exemple, on peut citer des objets dont le rle est de grer une ou plusieurs tables d'une base de donnes. En trois mots, il s'agit du cur du programme ! Dans le chapitre prcdent, nous avons confectionn un jeu du pendu. Dans cette application, notre fentre Swing correspond la vue et l'objet Model correspond au modle.

Le contrleur
Cet objet - car il s'agit aussi d'un objet - permet de faire le lien entre la vue et le modle lorsqu'une action utilisateur est intervenue sur la vue. C'est cet objet qui aura pour rle de contrler les donnes. Maintenant que toute la lumire est faite sur les trois composants de ce pattern, je vais expliquer plus prcisment la faon dont il travaille.

An de travailler sur un exemple concret, nous allons reprendre notre calculatrice issue d'un TP prcdent.
Dans une application structure en MVC, voici ce qu'il peut se passer :  l'utilisateur eectue une action sur votre calculatrice (un clic sur un bouton) ;  l'action est capte par le contrleur, qui va vrier la cohrence des donnes et ventuellement les transformer an que le modle les comprenne. Le contrleur peut aussi demander la vue de changer ;  le modle reoit les donnes et change d'tat (une variable qui change, par exemple) ;  le modle notie la vue (ou les vues) qu'il faut se mettre jour ;  l'achage dans la vue (ou les vues) est modi en consquence en allant chercher l'tat du modle. Je vous disais plus haut que le pattern MVC tait un pattern compos : ce stade de votre apprentissage, vous pouvez isoler deux patterns dans cette architecture. Le pattern observer se trouve au niveau du modle. Ainsi, lorsque celui-ci va changer d'tat, tous les objets qui l'observeront seront mis au courant automatiquement, et ce, avec un couplage faible ! Le deuxime est plus dicile voir mais il s'agit du pattern strategy ! Ce pattern est situ au niveau du contrleur. On dit aussi que le contrleur est la stratgie (en rfrence au pattern du mme nom) de la vue. En fait, le contrleur va transfrer les donnes de l'utilisateur au modle et il a tout fait le droit de modier le contenu. Ceux qui se demandent pourquoi utiliser le pattern strategy pourront se souvenir de la 527

CHAPITRE 33. MIEUX STRUCTURER SON CODE : LE PATTERN MVC raison d'tre de ce pattern : encapsuler les morceaux de code qui changent ! En utilisant ce pattern, vous prvenez les risques potentiels de changement dans votre logique de contrle. Il vous sura d'utiliser une autre implmentation de votre contrleur an d'avoir des contrles dirents. Ceci dit, vous devez tout de mme savoir que le modle et le contrleur sont intimement lis : un objet contrleur pour notre calculatrice ne servira que pour notre calculatrice ! Nous pouvons donc autoriser un couplage fort entre ces deux objets. Je pense qu'il est temps de se mettre coder !

Le modle
Le modle est l'objet qui sera charg de stocker les donnes ncessaires un calcul (nombre et oprateur) et d'avoir le rsultat. An de prvoir un changement ventuel de modle, nous crerons le notre partir d'un supertype de modle : de cette manire, si un changement s'opre, nous pourrons utiliser les direntes classes lles de faon polymorphe. Avant de foncer tte baisse, rchissons ce que notre modle doit tre capable d'eectuer. Pour raliser des calculs simples, il devra :  rcuprer et stocker au moins un nombre ;  stocker l'oprateur de calcul ;  calculer le rsultat ;  renvoyer le rsultat ;  tout remettre zro. Trs bien : voila donc la liste des mthodes que nous trouverons dans notre classe abstraite. Comme vous le savez, nous allons utiliser le pattern observer an de faire communiquer notre modle avec d'autres objets. Il nous faudra donc une implmentation de ce pattern ; la voici, dans un package com.sdz.observer.

Observable.java
pkge omFsdzFoserverY puli interfe yservle { puli void ddyserver@yserver osAY puli void removeyserver@AY puli void notifyyserver@tring strAY }

Observer.java
pkge omFsdzFoserverY puli interfe yserver {

528

LE MODLE
puli void updte@tring strAY

Notre classe abstraite devra donc implmenter ce pattern an de centraliser les implmentations. Puisque notre supertype implmente le pattern observer, les classes hritant de cette dernire hriteront aussi des mthodes de ce pattern ! Voici donc le code de notre classe abstraite que nous placerons dans le package com.sdz.model.

AbstractModel.java
pkge omFsdzFmodelY import jvFutilFerryvistY import omFsdzFoserverFyservleY import omFsdzFoserverFyserverY puli strt lss estrtwodel implements yservle{ proteted doule result a HY proteted tring operteur a 44D opernde a 44Y privte erryvist`yserverb listyserver a new erryvist`yserverb@AY GGiffe puli strt void reset@AY GGiffetue le lul puli strt void lul@AY GGeffihge for du rsultt puli strt void getesultt@AY GGhfinit l9oprteur de l9oprtion puli strt void setyperteur@tring operteurAY GGhfinit le nomre utiliser pour l9oprtion puli strt void setxomre@tring nreA Y GGsmplmenttion du pttern oserver puli void ddyserver@yserver osA { thisFlistyserverFdd@osAY } puli void notifyyserver@tring strA { if@strFmthes@4HHEWC4AA str a strFsustring@ID strFlength@AAY for@yserver os X listyserverA osFupdte@strAY

529

CHAPITRE 33. MIEUX STRUCTURER SON CODE : LE PATTERN MVC

puli void removeyserver@A { listyserver a new erryvist`yserverb@AY }

Ce code est clair et simple comprendre. Maintenant, nous allons crer une classe concrte hritant de AbstractModel. Voici la classe concrte que j'ai cre.

Calculator.java
pkge omFsdzFmodelY import omFsdzFoserverFyservleY puli lss glultor extends estrtwodel{ GGhfinit l9oprteur puli void setyperteur@tring opeA{ GGyn lne le lul lul@AY GGyn stoke l9oprteur thisFoperteur a opeY GGi l9oprteur n9est ps a if@3opeFequls@4a4AA{ GGyn rinitilise l9oprnde thisFopernde a 44Y }

GGhfinit le nomre puli void setxomre@tring resultA{ GGyn ontne le nomre thisFopernde Ca resultY GGyn met jour notifyyserver@thisFoperndeAY } GGpore le lul puli void getesultt@A { lul@AY } GGinitilise tout puli void reset@A{ thisFresult a HY thisFopernde a 4H4Y thisFoperteur a 44Y

530

LE CONTRLEUR
GGwise jour 3 notifyyserver@tringFvlueyf@thisFresultAAY

GGglul puli void lul@A{ GG9il n9y ps d9oprteurD le rsultt est le nomre sisi if@thisFoperteurFequls@44AA{ thisFresult a houleFprsehoule@thisFoperndeAY } else{ GGi l9oprnde n9est ps videD on lule ve l9oprteur de lul if@3thisFoperndeFequls@44AA{ if@thisFoperteurFequls@4C4AA{ thisFresult Ca houleFprsehoule@thisFoperndeAY } if@thisFoperteurFequls@4E4AA{ thisFresult Ea houleFprsehoule@thisFoperndeAY } if@thisFoperteurFequls@4B4AA{ thisFresult Ba houleFprsehoule@thisFoperndeAY } if@thisFoperteurFequls@4G4AA{ try{ thisFresult Ga houleFprsehoule@thisFoperndeAY }th@erithmetiixeption eA{ thisFresult a HY } }

} } thisFopernde a 44Y GGyn lne ussi l mise jour 3 notifyyserver@tringFvlueyf@thisFresultAAY

Voil, notre modle est prt l'emploi ! Nous allons donc continuer crer les composants de ce pattern.

Le contrleur
Celui-ci sera charg de faire le lien entre notre vue et notre modle. Nous crerons aussi une classe abstraite an de dnir un supertype de variable pour utiliser, le cas chant, des contrleurs de faon polymorphe. 531

CHAPITRE 33. MIEUX STRUCTURER SON CODE : LE PATTERN MVC Que doit faire notre contrleur ? C'est lui qui va intercepter les actions de l'utilisateur, qui va modeler les donnes et les envoyer au modle. Il devra donc :  agir lors d'un clic sur un chire ;  agir lors d'un clic sur un oprateur ;  avertir le modle pour qu'il se rinitialise dans le cas d'un clic sur le bouton  reset  ;  contrler les donnes. Voil donc notre liste de mthodes pour cet objet. Cependant, puisque notre contrleur doit interagir avec le modle, il faudra qu'il possde une instance de notre modle. Voici donc le code source de notre superclasse de contrle.

AbstractControler.java
pkge omFsdzFontrolerY import jvFutilFerryvistY import omFsdzFmodelFestrtwodelY puli strt lss estrtgontroler { proteted estrtwodel lY proteted tring operteur a 44D nre a 44Y proteted erryvist`tringb listyperteur a new erryvist`tringb@AY puli estrtgontroler@estrtwodel lA{ thisFl a lY GGyn dfinit l liste des oprteurs GGfin de s9ssurer qu9ils sont orrets thisFlistyperteurFdd@4C4AY thisFlistyperteurFdd@4E4AY thisFlistyperteurFdd@4B4AY thisFlistyperteurFdd@4G4AY thisFlistyperteurFdd@4a4AY } GGhfinit l9oprteur puli void setyperteur@tring opeA{ thisFoperteur a opeY ontrol@AY } GGhfinit le nomre puli void setxomre@tring nomreA{ thisFnre a nomreY ontrol@AY } GGiffe puli void reset@A{

532

LE CONTRLEUR
thisFlFreset@AY

GGwthode de ontrle strt void ontrol@AY

Nous avons dni les actions globales de notre objet de contrle et vous constatez aussi qu' chaque action dans notre contrleur, celui-ci invoque la mthode control(). Celleci va vrier les donnes et informer le modle en consquence. Nous allons voir maintenant ce que doit eectuer notre instance concrte. Voici donc, sans plus tarder, notre classe.

CalculetteControler.java
pkge omFsdzFontrolerY import omFsdzFmodelFestrtwodelY puli lss glulettegontroler extends estrtgontroler { puli glulettegontroler@estrtwodel lA { super@lAY } puli void ontrol@A { GGyn notifie le modle d9une tion si le ontrle est on GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGi l9oprteur est dns l liste if@thisFlistyperteurFontins@thisFoperteurAA{ GGi l9oprteur est a GGon ordonne u modle d9ffiher le rsultt if@thisFoperteurFequls@4a4AA thisFlFgetesultt@AY GGinonD on psse l9oprteur u modle else thisFlFsetyperteur@thisFoperteurAY } GGi le nomre est onforme if@thisFnreFmthes@4HEWFC64AA{ thisFlFsetxomre@thisFnreAY } thisFoperteur a 44Y thisFnre a 44Y

533

CHAPITRE 33. MIEUX STRUCTURER SON CODE : LE PATTERN MVC Vous pouvez voir que cette classe rednit la mthode control() et qu'elle permet d'indiquer les informations envoyer notre modle. Celui-ci mis jour, les donnes acher dans la vue seront envoyes via l'implmentation du pattern observer entre notre modle et notre vue. D'ailleurs, il ne nous manque plus qu'elle. Alors allons-y !

La vue
Voici le plus facile dvelopper et ce que vous devriez matriser le mieux. . . La vue sera cre avec le package javax.swing. Je vous donne donc le code source de notre classe que j'ai mis dans le package com.sdz.vue.

Calculette.java
pkge omFsdzFvueY GGgv C rsp C y pour gnrer les imports puli lss glulette extends tprme implements yserver{ privte tnel ontiner a new tnel@AY tring tstring a {4I4D 4P4D 4Q4D 4R4D 4S4D 4T4D 4U4D 4V4D 4W4D 4H4D 4F4D 4a4D 4g4D 4C4D 4E4D 4B4D 4G4}Y tfutton tutton a new tfuttontstringFlengthY privte privte privte privte privte privte tvel ern a new tvel@AY himension dim a new himension@SHD RHAY himension dimP a new himension@SHD QIAY doule hiffreIY oolen liyperteur a flseD updte a flseY tring operteur a 44Y

GGv9instne de notre ojet ontrleur privte estrtgontroler ontrolerY puli glulette@estrtgontroler ontrolerA{ thisFsetize@PRHD PTHAY thisFsetitle@4glulette4AY thisFsethefultgloseypertion@tprmeFisyxgvyiAY thisFsetvotioneltiveo@nullAY thisFsetesizle@flseAY initgomposnt@AY thisFontroler a ontrolerY thisFsetgontentne@ontinerAY thisFsetisile@trueAY } privte void initgomposnt@A{ pont polie a new pont@4eril4D pontFfyvhD PHAY

534

LA VUE
ern a new tvel@4H4AY ernFsetpont@polieAY ernFsetrorizontlelignment@tvelFsqrAY ernFsetreferredize@new himension@PPHD PHAAY tnel operteur a new tnel@AY operteurFsetreferredize@new himension@SSD PPSAAY tnel hiffre a new tnel@AY hiffreFsetreferredize@new himension@ITSD PPSAAY tnel pnirn a new tnel@AY pnirnFsetreferredize@new himension@PPHD QHAAY GGxous utiliserons le mme listener pour tous les oprteurs yperteurvistener opevistener a new yperteurvistener@AY for@int i a HY i ` tstringFlengthY iCCA { tuttoni a new tfutton@tstringiAY tuttoniFsetreferredize@dimAY swith@iA{ se II X tuttoniFddetionvistener@opevistenerAY hiffreFdd@tuttoniAY rekY se IP X tuttoniFsetporeground@golorFredAY tuttoniFddetionvistener@new esetvistener@AAY tuttoniFsetreferredize@dimPAY operteurFdd@tuttoniAY rekY se IQ X se IR X se IS X se IT X tuttoniFsetporeground@golorFredAY tuttoniFddetionvistener@opevistenerAY tuttoniFsetreferredize@dimPAY operteurFdd@tuttoniAY rekY defult X hiffreFdd@tuttoniAY tuttoniFddetionvistener@new ghiffrevistener@AAY rekY

} } pnirnFdd@ernAY pnirnFsetforder@forderptoryFretevineforder@golorFlkAAY

535

CHAPITRE 33. MIEUX STRUCTURER SON CODE : LE PATTERN MVC


ontinerFdd@pnirnD fordervyoutFxyrAY ontinerFdd@hiffreD fordervyoutFgixiAY ontinerFdd@operteurD fordervyoutFieAY

GGves listeners pour nos outons lss ghiffrevistener implements etionvistener{ puli void tionerformed@etionivent eA { GGyn ffihe le hiffre en plus dns le lel tring str a @@tfuttonAeFgetoure@AAFgetext@AY if@3ernFgetext@AFequls@4H4AA str a ernFgetext@A C strY } ontrolerFsetxomre@@@tfuttonAeFgetoure@AAFgetext@AAY

lss yperteurvistener implements etionvistener{ puli void tionerformed@etionivent eA { ontrolerFsetyperteur@@@tfuttonAeFgetoure@AAFgetext@AAY } } lss esetvistener implements etionvistener{ puli void tionerformed@etionivent rgHA { ontrolerFreset@AY } } GGsmplmenttion du pttern oserver puli void updte@tring strA { ernFsetext@strAY

Vous devez tre mme de comprendre ce code, puisqu'il ressemble beaucoup notre calculette ralise dans le TP du chapitre correspondant. Vous constaterez que la vue contient le contrleur (juste avant le constructeur de la classe). Toutes nos classes sont prsent oprationnelles. Copier ces codes Code web : 763482  Il ne nous manque plus qu'une classe de test an d'observer le rsultat. Elle cre les trois composants qui vont dialoguer entre eux : le modle (donnes), la vue (fentre) et le contrleur qui lie les deux. La voici :
import omFsdzFontrolerFBY import omFsdzFmodelFBY import omFsdzFvueFgluletteY

536

LA VUE

puli lss win { puli stti void min@tring rgsA { GGsnstnition de notre modle estrtwodel l a new glultor@AY GGgrtion du ontrleur estrtgontroler ontroler a new glulettegontroler@lAY GGgrtion de notre fentre ve le ontrleur en prmtre glulette lulette a new glulette@ontrolerAY GGejout de l fentre omme oserver de notre modle lFddyserver@luletteAY }

Testez ce code : le tout fonctionne trs bien ! Tous nos objets sont interconnects et dialoguent facilement (gure 33.2).

Figure

33.2  Notre calculatrice MVC

Comme vous connaissez la faon de travailler de ce pattern, nous allons dcortiquer ce qui se passe.

Lorsque nous cliquons sur un chire


     L'action est envoye au contrleur. Celui-ci vrie si le chire est conforme. Il informe le modle. Ce dernier est mis jour et informe la vue de ses changements. La vue rafrachit son achage.

Lorsque nous cliquons sur un oprateur


 L'action est toujours envoye au contrleur.  Celui-ci vrie si l'oprateur envoy est dans sa liste.  Le cas chant, il informe le modle. 537

CHAPITRE 33. MIEUX STRUCTURER SON CODE : LE PATTERN MVC  Ce dernier agit en consquence et informe la vue de son changement.  La vue est mise jour. Il se passera la mme chose lorsque nous cliquerons sur le bouton  reset .

Nous aurions trs bien pu faire la mme chose sans le contrleur !


Oui, bien sr. Mme sans modle ! Rappelez-vous de la raison d'exister du design pattern : prvenir des modications de codes ! Avec une telle architecture, vous pourrez travailler trois en mme temps sur le code : une personne sur la vue, une sur le modle, une sur le contrleur.

J'mets toutefois quelques rserves concernant ce pattern. Bien qu'il soit trs utile grce ses avantages long terme, celui-ci complique grandement votre code et peut le rendre trs dicile comprendre pour une personne extrieure l'quipe de dveloppement. Mme si le design pattern permet de rsoudre beaucoup de problmes, attention la patternite : son usage trop frquent peut rendre le code incomprhensible et son entretien impossible raliser.

En rsum
 Le pattern MVC est un pattern compos du pattern observer et du pattern strategy.  Avec ce pattern, le code est dcoup en trois parties logiques qui communiquent entre elles :  Le modle (donnes)  La vue (fentre)  Le contrleur qui lie les deux.  L'implmentation du pattern observer permet au modle de tenir informs ses observateurs.  L'implmentation du pattern strategy permet la vue d'avoir des contrles dirents.  Utiliser ce pattern permet de dcoupler trois acteurs d'une application, ce qui permet plus de souplesse et une maintenance plus aise du code.

538

Chapitre

34
Dicult :

Le Drag'n Drop

ette notion est somme toute assez importante l'heure actuelle : beaucoup de gens l'utilisent, ne serait-ce que pour dplacer des chiers dans leur systme d'exploitation ou encore faire des copies sur une cl USB. Pour rappel, le Drag'n Drop - traduit par  Glisser-Dposer  - revient slectionner un lment graphique d'un clic gauche, le dplacer grce la souris tout en maintenant le bouton enfonc et le dposer l'endroit voulu en relchant le bouton. En Java, cette notion est arrive avec JDK 1.2, dans le systme graphique awt. Nous verrons comment ceci tait gr car, mme si ce systme est fondu et simpli avec swing, vous devrez utiliser l'ancienne gestion de ce comportement, version awt. Je vous propose de commencer par un exemple simple, en utilisant swing, puis ensuite de dcouvrir un cas plus complet en utilisant tous les rouages de ces vnements, car il s'agit encore et toujours d'vnements.

539

CHAPITRE 34. LE DRAG'N DROP

Prsentation
La premire chose faire en swing pour activer le drag'n drop, c'est d'activer cette fonctionnalit dans les composants concerns. Voici un petit code de test :
GGgv C rsp C y pour gnrer les imports puli lss estI extends tprme{ puli estI@A{ super@4est de hrg9n hrop4AY setize@QHHD PHHAY tnel pn a new tnel@AY pnFsetfkground@golorFwhiteAY pnFsetvyout@new fordervyout@AAY GGxotre textere ve son ontenu dplle textere lel a new textere@4exte dplle 34AY lelFsetreferredize@new himension@QHHD IQHAAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGg9est ette instrution qui permet le dplement GGde son ontenu lelFsethrginled@trueAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE pnFdd@new trollne@lelAD fordervyoutFxyrAY tnel pnP a new tnel@AY pnPFsetfkground@golorFwhiteAY pnPFsetvyout@new fordervyout@AAY GGyn re le premier textfield ve ontenu dplle textpield text a new textpield@AY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE textFsethrginled@trueAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGit le seondD snsF textpield textP a new textpield@AY pnPFdd@textPD fordervyoutFyrAY pnPFdd@textD fordervyoutFxyrAY pnFdd@pnPD fordervyoutFyrAY dd@pnD fordervyoutFgixiAY } setisile@trueAY

puli stti void min@tring rgsA{

540

PRSENTATION
new estI@AY

Vous avez pu constater que le drag'n drop tait vraiment trs simple activer. . . Rcapitulons. Nous avons une fentre contenant trois composants : un JTextArea avec le drag'n drop activ et deux JTextField dont seul celui du dessus a l'option active. La gure 34.1 vous montre ce que donne ce code.

Figure

34.1  Lancement du programme

La gure 34.2 donne le rsultat aprs avoir slectionn une portion de texte et l'avoir glisse dans le JTextField no 1.

Figure

34.2  Texte cliqu-gliss

Vous trouverez sur la gure 34.3 le rsultat d'un dplacement du contenu du JTextField no 1 vers le JTextField no 2. tant donn que ce dernier JTextField est dpourvu de l'option dsire, vous ne pouvez plus dplacer le texte.

J'ai essay de faire la mme chose avec un JLabel et a n'a pas fonctionn !
C'est tout fait normal. Par dfaut, le drag'n drop n'est disponible que pour certains composants. D'abord, il ne faut pas confondre l'action  drag  et l'option  drop . 541

CHAPITRE 34. LE DRAG'N DROP

Figure

34.3  Changement de JTextField

Certains composants autorisent les deux alors que d'autres n'autorisent que le drag. Voici un tableau rcapitulatif des actions autorises par composant : Composant
JEditorPane JColorChooser JFileChooser JTextPane JTextField JTextArea JFormattedTextField JPasswordTextField JLabel JTable JTree JList

Drag X X X X X X X X X X

Drop X X X X X X X

Certains composants de ce tableau autorisent soit l'export de donnes, soit l'import de donnes, soit les deux, soit aucun des deux. Certains composants n'ont aucun comportement lorsque nous y dposons des donnes. . . Ceci est d leur complexit et leurs modes de fonctionnement. Par exemple, donner un comportement par dfaut un JTree n'est pas une mince aaire. Lors d'un drop, doit-il :  ajouter l'lment ?  ajouter l'lment en supprimant celui sur lequel nous le dposons ?  ajouter un nud mre ?  ajouter un nud lle ?  ... De ce fait, le comportement est laiss aux bons soins du dveloppeur, en l'occurrence, vous. Par contre, il faut que vous gardiez en mmoire que lorsqu'on parle de  drag , il y a deux notions implicites prendre en compte : le  drag dplacement  et le  drag copie . 542

FONCTIONNEMENT En fait, le drag'n drop peut avoir plusieurs eets :  la copie ;  le dplacement. Par exemple, sous Windows, lorsque vous dplacez un chier avec un drag'n drop dans un dossier, ce chier est entirement dplac : cela revient faire un couper - coller. En revanche, si vous eectuez la mme opration en maintenant la touche  Ctrl , l'action du drag'n drop devient l'quivalent d'un copier - coller. L'action  drag dplacement  indique donc les composants autorisant, par dfaut, l'action de type couper - coller, l'action  drag copie  indique que les composants autorisent les actions de type copier coller. La nalit, bien sr, tant de dposer des donnes l'endroit souhait. Gardez bien en tte que ce sont les fonctionnalits actives par dfaut sur ces composants.

Tu veux dire que nous pourrions ajouter cette fonctionnalit notre JLabel ?
Pour rpondre cette question, nous allons devoir mettre le nez dans le fonctionnement cach de cette fonctionnalit. . .

Fonctionnement
Comme beaucoup d'entre vous ont d le deviner, le transfert des informations entre deux composants se fait grce trois composantes essentielles :  un composant d'origine ;  des donnes transfres ;  un composant cible. Cette vision, bien qu'exacte dans la thorie, se simplie dans la pratique, pas de panique. Pour schmatiser ce que je viens de vous dire, voici un petit diagramme en gure 34.4.

Figure

34.4  Fonctionnement du drag'n drop 543

CHAPITRE 34. LE DRAG'N DROP Ce dernier est assez simple comprendre : pendant l'opration de drag'n drop, les donnes transitent d'un composant l'autre via un objet. Dans l'API Swing, le mcanisme de drag'n drop est encapsul dans l'objet JComponent dont tous les objets graphiques hritent, ce qui signie que tous les objets graphiques peuvent implmenter cette fonctionnalit. An d'activer le drag'n drop sur un composant graphique qui ne le permet pas par dfaut, nous devons utiliser la mthode setTransferHandler(TransferHandler newHandler) de l'objet JComponent. Cette mthode prend un objet TransferHandler en paramtre : c'est celui-ci qui lance le mcanisme de drag'n drop. Les composants du tableau rcapitulatif (hormis le JLabel) ont tous un objet TransferHandler par dfaut. Le drag'n drop s'active par la mthode setDragEnabled(true) sur la plupart des composants, mais comme vous avez pu le constater, pas sur le JLabel. . . An de contourner cela, nous devons lui spcier un objet TransferHandler ralis par nos soins. Attention, toutefois ! Vous pouvez dnir un TransferHandler pour un objet possdant dj un comportement par dfaut, mais cette action supplantera le mcanisme par dfaut du composant : rednissez donc les comportements avec prudence ! Retournons notre JLabel. An de lui ajouter les fonctionnalits voulues, nous devons lui aecter un nouveau TransferHandler. Une fois que ce nouvel objet lui sera assign, nous lui ajouterons un vnement souris an de lancer l'action de drag'n drop : je vous rappelle que l'objet TransferHandler ne permet que le transit des donnes, il ne gre pas les vnements ! Dans notre vnement, nous avons juste rcuprer le composant initiateur du drag, rcuprer son objet TransferHandler et invoquer sa mthode exportAsDrag(JComponent comp, InputEvent event, int action) . Voici un code permettant de dplacer le texte d'un JLabel dans un JTextField :
GGgv C rsp C y pour gnrer les imports puli lss velgontenthemo extends tprme{ puli velgontenthemo@A{ setitle@4hrg9n hrop ve un tvel 34AY setize@QHHD IHHAY setvotioneltiveo@nullAY sethefultgloseypertion@tprmeFisyxgvyiAY tnel pn a new tnel@AY pnFsetvyout@new qridvyout@PDPAAY pnFsetfkground@golorFwhiteAY tvel srvi a new tvel@4oure de drg X 4D tvelFsqrAY tvel sr a new tvel@4exte dpler 34AY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGyn re le nouvel ojet pour tiver le drg9n drop srFsetrnsferrndler@new rnsferrndler@4text4AAY

544

FONCTIONNEMENT
GGyn spifie u omposnt qu9il doit envoyer ses donnes GGvi son ojet rnsferrndler srFddwousevistener@new wouseedpter@A{ GGyn utilise et vnement pour que les tions soient GGvisiles ds le li de sourisFFF GGxous urions pu utiliser mouseelesedD GGmisD niveu srwD nous n9urions rien vu puli void mouseressed@wouseivent eA{ GGyn rupre le tgomponent tgomponent l a @tgomponentAeFgetoure@AY GGhu omposntD on rupre l9ojet de trnsfert X le ntre rnsferrndler hndle a lFgetrnsferrndler@AY GGyn lui ordonne d9morer l produre de drg9n drop hndleFexporteshrg@lD eD rnsferrndlerFgyAY } }AY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE tvel destvi a new tvel@4hestintion de drg X 4D tvelFsqrAY textpield dest a new textpield@AY GGyn tive le omportement pr dfut de e omposnt destFsethrginled@trueAY pnFdd@srviAY pnFdd@srAY pnFdd@destviAY pnFdd@destAY setgontentne@pnAY setisile@trueAY

puli stti void min@tring rgsA{ new velgontenthemo@AY }

Sur la gure 34.5, on dplace le contenu de notre source vers le champ texte.

Figure

34.5  Avant le drag

Sur la gure 34.6, on voit que le contenu est dplac. Enn, sur la gure 34.7, on dplace un fragment du contenu de notre champ texte vers notre JLabel. 545

CHAPITRE 34. LE DRAG'N DROP

Figure

34.6  Texte dplac

Figure

34.7  Aprs le dplacement de la chane  dplacer  vers le JLabel

Vous devez avoir plusieurs questions. Dj, pour ceux qui ne l'auraient pas remarqu (ou essay), l'objet de transfert n'a pas de constructeur sans argument ! Cette instruction ne compilera pas : TransferHandler trans = new TransferHandler(); . Par contre, le constructeur utilis fonctionne parfaitement pour un JLabel TransferHandler trans = new TransferHandler("text"); . Pourquoi ? Tout simplement parce que la chane de caractres passe en paramtre correspond une proprit JavaBean utilisable par l'objet. Un JavaBean est un objet Java rpondant certains critres de construction :  la classe doit tre Serializable pour pouvoir sauvegarder et restaurer l'tat des instances de cette classe ;  la classe doit possder un constructeur sans arguments (constructeur par dfaut) ;  les proprits prives de la classe (variables d'instance) doivent tre accessibles publiquement via des mthodes accesseurs ( get ou set) suivies du nom de la proprit avec la premire lettre transforme en majuscule ;  la classe doit contenir les mthodes d'interception d'vnements ncessaires. En fait, notre objet de transfert va utiliser la proprit  text  de notre objet JLabel, ceci an de rcuprer son contenu et de le faire transiter. Nous verrons plus tard comment faire pour les cas o nous ne connaissons pas le nom de la proprit. . . Ensuite, nous avons rcupr l'objet TransferHandler depuis notre composant : nous le lui avions aect avec un setter, nous pouvons le rcuprer avec un getter. L o les choses deviennent intressantes, c'est lorsque nous invoquons la mthode handle.exportAsDrag(lab, e, TransferHandler.COPY); . C'est cette instruction qui amorce rellement le drag'n drop. Les trois paramtres servent initialiser les actions eectuer et dterminer quand et sur qui les faire :  le premier paramtre indique le composant qui contient les donnes dplacer ;  le second paramtre indique notre objet l'vnement sur lequel il doit dclencher le transfert ;  le dernier indique l'action qui doit tre eectue : copie, dplacement, rien. . . Comme je vous l'avais dit, il existe plusieurs types d'actions qui peuvent tre eectues lors du drop, celles-ci sont paramtrables via l'objet TransferHandle : 546

CRER SON PROPRE TRANSFERHANDLER  TransferHandler.COPY : n'autorise que la copie des donnes vers le composant cible ;  TransferHandler.MOVE : n'autorise que le dplacement des donnes vers le composant cible ;  TransferHandler.LINK : n'autorise que l'action lien sur les donnes du composant cible ; cela revient crer un raccourci ;  TransferHandler.COPY_OR_MOVE : autorise la copie ou le dplacement ;  TransferHandler.NONE : n'autorise rien. Attention, l'objet TransferHandler n'accepte que les actions COPY lorsqu'il est instanci avec le paramtre  text  : si vous modiez la valeur ici, votre drag'n drop ne fonctionnera plus.

Alors, mme si nous avons russi faire un JLabel avec l'option drag'n drop, celui-ci sera restreint ?
Non, mais si nous sommes parvenus crer un nouveau TranferHandler, pour arriver dbrider notre composant, nous allons devoir encore approfondir. . .

Crer son propre TransferHandler


An de personnaliser le drag'n drop pour notre composant, nous allons devoir mettre les mains dans le cambouis. La classe TransferHandler fait pas mal de choses dans votre dos et, tout comme les modles de composants (cf. JTree, JTable), ds lors que vous y mettez les mains, tout sera votre charge ! Voici une reprsentation simplie de la classe en question en gure 34.8.

Figure

34.8  La classe TransferHandler

Nous y retrouvons nos types de transferts, la mthode exportAsDrag(...) et tout plein de nouveauts. . . C'est aussi dans cette classe que se trouvent les mthodes pour la gestion du copier - coller traditionnel. 547

CHAPITRE 34. LE DRAG'N DROP Le but est maintenant de dplacer les donnes du JLabel vers notre zone de texte faon  couper - coller . Vous vous en doutez, nous allons devoir rednir le comportement de certaines des mthodes de notre objet de transfert. Ne vous inquitez pas, nous allons y aller en douceur. Voici la liste des mthodes que nous allons utiliser pour arriver faire ce que nous cherchons :
import jvxFswingFrnsferrndlerY puli lss wyrnsferrndler extends rnsferrndler{ GBB B wthode permettnt l9ojet de svoir si les donnes reues B vi un drop sont utorises tre importes B dprm info B dreturn oolen BG puli oolen nsmport@rnsferrndlerFrnsferupport infoA {} GBB B g9est ii que l9insertion des donnes dns notre omposnt est rlise B dprm support B dreturn oolen BG puli oolen importht@rnsferrndlerFrnsferupport supportA{} GBB B gette mthode est invoque l fin de l9tion hy B i des tions sont fire ensuiteD 9est ii qu9il fudr oder B le omportement dsir B dprm B dprm t B dprm tion BG proteted void exporthone@tgomponent D rnsferle tD int tionA{} GBB B hns ette mthodeD nous llons rer l9ojet utilis pr B le systme de drg9n drop fin de fire iruler B les donnes entre les omposntsF B ous pouvez voir qu9il s9git d9un ojet de type rnsferle B dprm B dreturn BG proteted rnsferle reternsferle@tgomponent A {} GBB B gette mthode est utilise fin de dterminer le omportement B du omposnt visEEvis du drg9n drop X nous retrouverons B nos vriles sttiques gyD wyiD gyywyiD vsxu ou xyxi B dprm

548

CRER SON PROPRE TRANSFERHANDLER


B dreturn int BG puli int getoureetions@tgomponent A {} }

Commenons par dnir le comportement souhait pour notre composant : le dplacement. Cela se fait via la mthode public int getSourceActions(JComponent c) . Nous allons utiliser les variables statiques de la classe mre pour dnir l'action autorise :
puli int getoureetions@tgomponent A { GGxous n9utorisons don que le dplement ii return wyiY }

Maintenant, assurons-nous qu'il sera toujours possible d'importer des donnes d'un autre composant en les dposant dessus. Pour cela, nous allons rednir les mthodes d'import de donnes public boolean canImport(TransferHandler. TransferSupport info) et public boolean importData(TransferHandler. TransferSupport support) . Remarquez ce paramtre bizarre : TransferHandler.TransferSupport . Rappelez-vous les classes internes : la classe TransferSupport est l'intrieur de la classe TransferHandler. Cet objet a un rle trs important : la communication entre les composants. C'est lui qui vhicule l'objet encapsulant nos donnes. C'est aussi lui, pour des composants plus complexes tels qu'un tableau, un arbre ou une liste, qui fournit l'emplacement o a eu lieu l'action drop. Voici ce que vont contenir nos mthodes :
puli oolen nsmport@rnsferrndlerFrnsferupport infoA { GGxous ontrlons si les donnes reues GGsont d9un type utorisD ii le type tring if @3infoFishtplvorupported@htplvorFstringplvorAA { return flseY } return trueY }

L'objet TransferSupport nous ore une mthode permettant de contrler le type de donnes supportes par notre drag'n drop. Une liste de  type MIME 1  est disponible dans l'objet DataFlavor. Ici, nous avons utilis DataFlavor.stringFlavor , qui signie  chane de caractres , comme vous avez pu le deviner. Voici la liste des types d'lments disponibles via l'objet DataFlavor :
1. Signie Multipurpose Internet Mail Extensions . C'est une faon de typer certains chiers comme les images, les PDF, etc.

549

CHAPITRE 34. LE DRAG'N DROP  DataFlavor.javaSerializedObjectMimeType : autorise un objet Java srialis correspondant au type MIME  application/x-java-serialized-object  ;  DataFlavor.imageFlavor : autorise une image, soit la classe java.awt.Image correspondant au type MIME  image/x-java-image  ;  DataFlavor.javaFileListFlavor : autorise un objet java.util.List contenant des objets java.io.File ;  DataFlavor.javaJVMLocalObjectMimeType : autorise n'importe quel objet Java ;  DataFlavor.javaRemoteObjectMimeType : autorise un objet distant utilisant l'interface Remote ;  DataFlavor.stringFlavor : autorise soit une chane de caractres, soit la classe java.lang.String correspondant au type MIME  application/x-java-serializedobject . La seconde tape de notre dmarche consiste autoriser l'import de donnes vers notre composant grce la mthode public boolean importData(TransferHandler. TransferSupport support) :
puli oolen importht@rnsferrndlerFrnsferupport supportA{ GGxous ontrlons si les donnes reues GGsont d9un type utoris if@3nsmport@supportAA return flseY GGyn rupre notre ojet rnsferleD GGelui qui ontient les donnes en trnsit rnsferle dt a supportFgetrnsferle@AY tring str a 44Y try { GGxous ruprons nos donnes en spifint e que nous ttendons str a @tringAdtFgetrnsferht@htplvorFstringplvorAY } th @nsupportedplvorixeption eA{ eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY } GGi le nsferupportD nous pouvons ruprer notre omposnt tvel l a @tvelAsupportFgetgomponent@AY GGefin de lui ffeter s nouvelle vleur lFsetext@strAY } return trueY

Voil : ce stade, nous avons redni la copie du champ de texte vers notre JLabel. Voici notre objet en l'tat :
GGgv C rsp C y pour gnrer les imports puli lss velgontenthemo extends tprme{

550

CRER SON PROPRE TRANSFERHANDLER

puli velgontenthemo@A{ setitle@4hrg9n hrop ve un tvel 34AY setize@QHHD IHHAY setvotioneltiveo@nullAY sethefultgloseypertion@tprmeFisyxgvyiAY tnel pn a new tnel@AY pnFsetvyout@new qridvyout@PDPAAY pnFsetfkground@golorFwhiteAY tvel srvi a new tvel@4oure de drg X 4D tvelFsqrAY tvel sr a new tvel@4exte dpler 34AY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGyn utilise notre nouvel ojet wyrnsferrndle srFsetrnsferrndler@new wyrnsferrndler@AAY srFddwousevistener@new wouseedpter@A{ puli void mouseressed@wouseivent eA{ ystemFoutFprintln@4iix 34AY tgomponent l a @tgomponentAeFgetoure@AY rnsferrndler hndle a lFgetrnsferrndler@AY hndleFexporteshrg@lD eD rnsferrndlerFgyAY }

}AY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE tvel destvi a new tvel@4hestintion de drg X 4D tvelFsqrAY textpield dest a new textpield@AY destFsethrginled@trueAY pnFdd@srviAY pnFdd@srAY pnFdd@destviAY pnFdd@destAY setgontentne@pnAY setisile@trueAY

puli stti void min@tring rgsA{ new velgontenthemo@AY }

Et maintenant, le plus dur : eacer le contenu de notre objet une fois la copie des donnes eectue. 551

CHAPITRE 34. LE DRAG'N DROP


GGgv C rsp C y pour gnrer les imports puli lss wyrnsferrndler extends rnsferrndler{ puli oolen nsmport@rnsferrndlerFrnsferupport infoA { if @3infoFishtplvorupported@htplvorFstringplvorAA { return flseY } return trueY } puli oolen importht@rnsferrndlerFrnsferupport supportA{ if@3nsmport@supportAA return flseY rnsferle dt a supportFgetrnsferle@AY tring str a 44Y try { str a @tringAdtFgetrnsferht@htplvorFstringplvorAY } th @nsupportedplvorixeption eA{ eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY } tvel l a @tvelAsupportFgetgomponent@AY lFsetext@strAY } return flseY

proteted void exporthone@tgomponent D rnsferle tD int tionA{ GGne fois le drop effetu GGnous effons le ontenu de notre tvel if@tion aa wyiA @@tvelAAFsetext@44AY } proteted rnsferle reternsferle@tgomponent A { GGyn retourne un nouvel ojet implmentnt l9interfe rnsferle GGtringeletion implmente ette interfeD nous l9utilisons don return new tringeletion@@@tvelAAFgetext@AAY } puli int getoureetions@tgomponent A { return wyiY }

Vous pouvez tester nouveau votre code, cette fois le rendu est conforme nos attentes. 552

ACTIVER LE DROP SUR UN JTREE Vous venez de recrer la fonction drag'n drop pour un composant : bravo !

Activer le drop sur un JTree


Vous vous doutez de la marche suivre : cependant, comme je vous l'avais dit au dbut de ce chapitre, vous allez tre confronts au problme du positionnement du drop sur votre composant. Cependant, votre bote outils dispose d'un nouvel objet dont le rle est d'informer sur la position du drop : l'objet TransferSupport. Avant de poursuivre dans cette voie, rappelez-vous qu'il faut dnir l'action que doit eectuer notre composant lors du dpt de nos donnes. C'est possible grce l'objet DropMode que nous pouvons utiliser via la mthode setDropMode(DropMode dropMode) . Voici la liste des modes disponibles :  USE_SELECTION  ON  INSERT  ON_OR_INSERT  INSERT_COLS  INSERT_ROWS  ON_OR_INSERT_COLS  ON_OR_INSERT_ROWS Vous l'aurez compris : certains modes sont utilisables par des tableaux et d'autres non. . . An que vous puissiez vous faire votre propre ide sur le sujet, je vous invite les essayer dans l'exemple qui va suivre. C'est grce cela que nous allons spcier le mode de fonctionnement de notre arbre. Maintenant que nous savons comment spcier le mode de fonctionnement, il ne nous reste plus qu' trouver comment, et surtout o insrer le nouvel lment. C'est l que notre ami le TransfertSupport entre en jeu. Cet objet permet de rcuprer un objet DropLocation contenant toutes les informations ncessaires au bon positionnement des donnes dans le composant cible. En fait, par l'objet TransfertSupport, vous pourrez dduire un objet DropLocation propre votre composant, par exemple :
GGour ruprer les infos importntes sur un tree treeFhropvotion dl a @treeFhropvotionAmyrnsfertupportF gethropvotion@AY GGour ruprer les infos importntes sur un tle tleFhropvotion dl a @tleFhropvotionAmyrnsfertupportF gethropvotion@AY GGour ruprer les infos importntes sur un tvist tvistFhropvotion dl a @tvistFhropvotionAmyrnsfertupportF gethropvotion@AY

L'avantage de ces spcications, c'est qu'elles permettent d'avoir accs des informations fort utiles : 553

CHAPITRE 34. LE DRAG'N DROP


JList.DropLocation isInsert getIndex JTree.DropLocation getChildIndex getPath JTable.DropLocation isInsertRow isInsertColumn getRow getColumn

Maintenant que je vous ai prsent la marche suivre et les objets utiliser, je vous propose un exemple qui, je pense, parle de lui-mme et est assez comment pour que vous puissiez vous y retrouver. Voici les classes utilises.


Copier ce code Code web : 508422 

MyTransferHandler.java
GGgv C rsp C y pour gnrer les imports puli lss wyrnsferrndler extends rnsferrndler{ puli oolen nsmport@rnsferrndlerFrnsferupport infoA { if @3infoFishtplvorupported@htplvorFstringplvorAA { return flseY } return trueY } puli oolen importht@rnsferrndlerFrnsferupport supportA{ if@3nsmport@supportAA return flseY rnsferle dt a supportFgetrnsferle@AY tring str a 44Y try { str a @tringAdtFgetrnsferht@htplvorFstringplvorAY } th @nsupportedplvorixeption eA{ eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY } tvel l a @tvelAsupportFgetgomponent@AY lFsetext@strAY } return flseY

proteted void exporthone@tgomponent D rnsferle tD int tionA{ if@tion aa wyiA{

554

ACTIVER LE DROP SUR UN JTREE


tvel l a @tvelAY tring text a lFgetext@AY int indie a sntegerFprsesnt@textFsustring@textFlength@AEID textFlength@AAAY lFsetext@textFsustring@HD textFlength@AEIA C @CCindieAAY

proteted rnsferle reternsferle@tgomponent A { return new tringeletion@@@tvelAAFgetext@AAY } puli int getoureetions@tgomponent A { return wyiY }

TreeTransferHandler.java
GGgv C rsp C y pour gnrer les imports puli lss reernsferrndler extends rnsferrndler{ tree treeY puli reernsferrndler@tree treeA{ thisFtree a treeY } puli oolen nsmport@rnsferrndlerFrnsferupport infoA { if @3infoFishtplvorupported@htplvorFstringplvorAA { return flseY } return trueY

puli oolen importht@rnsferrndlerFrnsferupport supportA{ if@3nsmport@supportAA return flseY GGyn rupre l9endroit du drop vi un ojet ppropri treeFhropvotion dl a @treeFhropvotionAsupportFgethropvotion@AY GGves informtions fin de pouvoir rer un nouvel lment reeth pth a dlFgetth@AY int index a dlFgetghildsndex@AY GGgomme pour le tvelD on rupre les donnes rnsferle dt a supportFgetrnsferle@AY tring str a 44Y

555

CHAPITRE 34. LE DRAG'N DROP

try { str a @tringAdtFgetrnsferht@htplvorFstringplvorAY } th @nsupportedplvorixeption eA{ eFprinttkre@AY } th @syixeption eA { eFprinttkre@AY } GGyn peut mintennt jouter le nud hefultwutlereexode nouveu a new hefultwutlereexode@strAY GGyn dduit le nud prent vi le hemin hefultwutlereexode prent a @hefultwutlereexodeApthFgetvstthgomponent@AY hefultreewodel model a @hefultreewodelAthisFtreeFgetwodel@AY index a @index aa EIA c modelFgetghildgount@pthFgetvstthgomponent@AA X index Y modelFinsertxodesnto@nouveuD prentD indexAY treeFmkeisile@pthFpthfyeddingghild@nouveuAAY treeFsrollthoisile@pthAY } return trueY

puli int getoureetions@tgomponent A { return gyywyiY }

TreeDragDemo.java
GGgv C rsp C y pour gnrer les imports puli lss reehrghemo extends tprme{ tree treeY puli reehrghemo@A{ setitle@4hrg9n hrop ve un tvel 34AY setize@RHHD PHHAY setvotioneltiveo@nullAY sethefultgloseypertion@tprmeFisyxgvyiAY tnel pn a new tnel@AY pnFsetvyout@new qridvyout@ID IAAY pnFsetfkground@golorFwhiteAY tvel srvi a new tvel@4oure de drg X 4D tvelFsqrAY tvel sr a new tvel@4xoeud I4AY

556

ACTIVER LE DROP SUR UN JTREE


GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGyn utilise notre nouvel ojet wyrnsferrndle srFsetrnsferrndler@new wyrnsferrndler@AAY srFddwousevistener@new wouseedpter@A{ puli void mouseressed@wouseivent eA{ tgomponent l a @tgomponentAeFgetoure@AY rnsferrndler hndle a lFgetrnsferrndler@AY hndleFexporteshrg@lD eD rnsferrndlerFwyiAY }

}AY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

tvel destvi a new tvel@4hestintion de drg X 4D tvelFsqrAY textpield dest a new textpield@AY destFsethrginled@trueAY tree a new tree@getwodel@AAY treeFsethrginled@trueAY treeFsetrnsferrndler@new reernsferrndler@treeAAY pnFdd@srAY pnFdd@new trollne@treeAAY GGour le hoix des tions tgomofox omo a new tgomofox@AY omoFddstem@4iivigsyx4AY omoFddstem@4yx4AY omoFddstem@4sxi4AY omoFddstem@4yxysxi4AY omoFddstemvistener@new stemvistener@A{ puli void itemtteghnged@stemivent eventA { tring vlue a eventFgetstem@AFtotring@AY if@vlueFequls@4iivigsyx4AA{ treeFsethropwode@hropwodeFiivigsyxAY } if@vlueFequls@4yx4AA{ treeFsethropwode@hropwodeFyxAY } if@vlueFequls@4sxi4AA{ treeFsethropwode@hropwodeFsxiAY } if@vlueFequls@4yxysxi4AA{ treeFsethropwode@hropwodeFyxysxiAY }

557

CHAPITRE 34. LE DRAG'N DROP


}AY dd@pnD fordervyoutFgixiAY dd@omoD fordervyoutFyrAY setisile@trueAY

privte reewodel getwodel@A{ hefultwutlereexode root a new hefultwutlereexode@4h4AY hefultwutlereexode forum a new hefultwutlereexode@4porum4AY forumFdd@new hefultwutlereexode@4gCC4AAY forumFdd@new hefultwutlereexode@4tv4AAY forumFdd@new hefultwutlereexode@4r4AAY hefultwutlereexode tuto a new hefultwutlereexode@4utoriel4AY tutoFdd@new hefultwutlereexode@4utoriel4AAY tutoFdd@new hefultwutlereexode@4rogrmmtion4AAY tutoFdd@new hefultwutlereexode@4wpping4AAY rootFdd@tutoAY rootFdd@forumAY } return new hefultreewodel@rootAY

puli stti void min@tring rgsA{ new reehrghemo@AY }

La gure 34.9 vous montre ce que j'ai obtenu aprs quelques manipulations.

Eet de dplacement
la lecture de tous ces chapitres, vous devriez tre mme de comprendre et d'assimiler le fonctionnement du code qui suit. Son objectif est de simuler le dplacement de vos composants sur votre IHM, un peu comme dans les gures 34.10, 34.11 et 34.12. En fait, le principe revient dnir un GlassPane votre fentre, composant personnalis que nous avons fait hriter de JPanel. C'est lui qui va se charger de dessiner les images des composants sur sa surface, dont nous aurons au pralable dni la transparence. Sur chaque composant, nous allons devoir dnir les actions eectuer chaque vnement souris : deux classes sont codes cet eet. . . Ensuite, il ne reste plus qu' faire notre test. Voil les codes sources promis. 558

EFFET DE DPLACEMENT

Figure

34.9  Ajout de nud via drag'n drop

Figure

34.10  Dplacement d'un bouton sur un autre composant

Figure

34.11  Aprs avoir relch le bouton sur un autre composant

Figure

34.12  Dplacement d'un JLabel 559

CHAPITRE 34. LE DRAG'N DROP




Eet de dplacement Code web : 886736 

MyGlassPane.java
GGgv C rsp C y pour gnrer les imports puli lss wyqlssne extends tnel{ GGv9imge qui ser dessine privte fufferedsmge imgY GGves oordonnes de l9imge privte oint lotionY GGv trnsprene de notre gle privte gomposite trnspreneY puli wyqlssne@A{ GGefin de ne peindre que e qui nous intresse setypque@flseAY GGyn dfinit l trnsprene trnsprene a elphgompositeFgetsnstne@elphgompositeFgyiD HFSSfAY } puli void setvotion@oint lotionA{ thisFlotion a lotionY } puli void setsmge@fufferedsmge imgeA{ img a imgeY } puli void pintgomponent@qrphis gA{ GGi on n9 ps d9imge dessinerD on ne fit rienFFF if@img aa nullAreturnY GGhns le s ontrireD on dessine l9imge souhite qrphisPh gPd a @qrphisPhAgY gPdFsetgomposite@trnspreneAY gPdFdrwsmge@imgD @intA @lotionFget@A E @imgFgetidth@thisA G PAAD @intA @lotionFget@A E @imgFgetreight@thisA G PAAD nullAY

MouseGlassListener.java
GGgv C rsp C y pour gnrer les imports puli lss wouseqlssvistener extends wouseedpter{

560

EFFET DE DPLACEMENT

privte wyqlssne myqlssY privte fufferedsmge imgeY puli wouseqlssvistener@wyqlssne glssA{ myqlss a glssY } puli void mouseressed@wouseivent eventA { GGyn rupre le omposnt pour en dduire s position gomponent omposnt a eventFgetgomponent@AY oint lotion a @ointAeventFgetoint@AFlone@AY GGves mthodes iEdessous permettentD dns l9ordreD GGde onvertir un point en oordonnes d9rn GGet de reonvertir e point en oordonnes fentres wingtilitiesFonvertointoreen@lotionD omposntAY wingtilitiesFonvertointpromreen@lotionD myqlssAY GGves instrutions iEdessous permettent de redessiner le omposnt imge a new fufferedsmge@omposntFgetidth@AD omposntFgetreight@AD fufferedsmgeFisxeqfAY qrphis g a imgeFgetqrphis@AY omposntFpint@gAY GGyn psse les donnes qui vont ien notre qlssne myqlssFsetvotion@lotionAY myqlssFsetsmge@imgeAY GGyn n9oulie ps de dire notre qlssne de s9ffiher myqlssFsetisile@trueAY

puli void mouseelesed@wouseivent eventA { GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGyn implmente le trnsfert lorsqu9on relhe le outon de souris GGei fin de ne ps supplnter le fontionnement du dplement tgomponent l a @tgomponentAeventFgetoure@AY rnsferrndler hndle a lFgetrnsferrndler@AY hndleFexporteshrg@lD eventD rnsferrndlerFgyAY GGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GGyn rupre le omposnt pour en dduire s position gomponent omposnt a eventFgetgomponent@AY oint lotion a @ointAeventFgetoint@AFlone@AY GGves mthodes iEdessous permettentD dns l9ordreD GGde onvertir un point en oordonnes d9rn

561

CHAPITRE 34. LE DRAG'N DROP


GGet de reonvertir e point en oordonnes fentre wingtilitiesFonvertointoreen@lotionD omposntAY wingtilitiesFonvertointpromreen@lotionD myqlssAY GGyn psse les donnes qui vont ien notre qlssne myqlssFsetvotion@lotionAY myqlssFsetsmge@nullAY GGyn n9oulie ps de ne plus l9ffiher myqlssFsetisile@flseAY } }

MouseGlassMotionListener.java
GGgv C rsp C y pour gnrer les imports puli lss wouseqlsswotionvistener extends wouseedpter{ privte wyqlssne myqlssY puli wouseqlsswotionvistener@wyqlssne glssA{ myqlss a glssY } GBB B wthode fontionnnt sur le mme prinipe que l lsse prdente B mis ette fois sur l9tion de dplement BG puli void mousehrgged@wouseivent eventA { GGous onnissez mintenntFFF gomponent a eventFgetgomponent@AY oint p a @ointA eventFgetoint@AFlone@AY wingtilitiesFonvertointoreen@pD AY wingtilitiesFonvertointpromreen@pD myqlssAY myqlssFsetvotion@pAY myqlssFrepint@AY

Fenetre.java
GGgv C rsp C y pour gnrer les imports puli lss penetre extends tprme{ privte wyqlssne glss a new wyqlssne@AY puli penetre@A{

562

EFFET DE DPLACEMENT
super@4est de qlssne4AY setize@RHHD PHHAY setvotioneltiveo@nullAY sethefultgloseypertion@tprmeFisyxgvyiAY tnel pn a new tnel@AY tnel pnP a new tnel@AY GGyn re un omposnt tfutton outonI a new tfutton@4fouton x I4AY GGyn y tthe les outeurs qui uront pour rle GGd9initiliser notre gle et d9y ffeter les donnes GGqui permettront de simuler le dplement outonIFddwousevistener@new wouseqlssvistener@glssAAY outonIFddwousewotionvistener@new wouseqlsswotionvistener@glssAAY GGyn ffete mintennt un rnferrndler spifique GGinitilis ve l proprit tvfen 4text4 outonIFsetrnsferrndler@new rnsferrndler@4text4AAY tfutton outonP a new tfutton@4fouton x P4AY outonPFddwousevistener@new wouseqlssvistener@glssAAY outonPFddwousewotionvistener@new wouseqlsswotionvistener@glssAAY outonPFsetrnsferrndler@new rnsferrndler@4text4AAY tvel text a new tvel@4heuxime texte sttique4AY textFddwousevistener@new wouseqlssvistener@glssAAY textFddwousewotionvistener@new wouseqlsswotionvistener@glssAAY textFsetrnsferrndler@new rnsferrndler@4text4AAY tvel lel a new tvel@4exte sttique 34AY lelFddwousevistener@new wouseqlssvistener@glssAAY lelFddwousewotionvistener@new wouseqlsswotionvistener@glssAAY lelFsetrnsferrndler@new rnsferrndler@4text4AAY pnFdd@outonIAY pnFdd@lelAY dd@pnD fordervyoutFxyrAY pnPFdd@textAY pnPFdd@outonPAY dd@pnPD fordervyoutFyrAY setqlssne@glssAY setvotioneltiveo@nullAY sethefultgloseypertion@tprmeFisyxgvyiAY } setisile@trueAY

563

CHAPITRE 34. LE DRAG'N DROP


puli stti void min@tring rgsA{ new penetre@AY }

Pour des composants comme les JTree, JTable ou autres, vous aurez certainement faire des modications pour que a fonctionne !
Et voil : j'espre que a vous a plu ! Vous devriez dsormais aborder le drag'n drop avec plus de srnit. Il vous reste encore des choses explorer, mais rien qui devrait vous bloquer : vous n'tes plus des Zros !

En rsum
 Le drag'n drop n'est disponible via la mthode setDragEnabled(true); que pour certains composants.  Plusieurs comportements sont possibles pour les dplacements de donnes : la copie ou le dplacement.  Le drag'n drop permet de rcuprer des donnes d'un composant source pour les transmettre un composant cible, le tout via un objet : l'objet TransferHandler.  Vous pouvez activer le drag'n drop sur un composant en utilisant la mthode setTransferHandler(TransferHandler newHandler) hrite de JComponent.  La procdure de drag'n drop est rellement lance lors de l'appel la mthode handle.exportAsDrag(lab, e, TransferHandler.COPY); , qui permet de dterminer qui lance l'action, sur quel vnement, ainsi que l'action qui doit tre eectue.  An d'avoir le contrle du mcanisme de drag'n drop, vous pouvez raliser votre propre TransferHandler.  Ce dernier dispose d'une classe interne permettant de grer la communication entre les composants (l'objet TransferHandler.TransferSupport ) et permet aussi de s'assurer que les donnes reues sont bien du type attendu.

564

Chapitre

35
Dicult :

Mieux grer les interactions avec les composants

n d'amliorer la performance et la ractivit de vos programmes Java, nous allons parler de l'EDT, pour Event Dispatch Thread. Comme son nom l'indique, il s'agit d'un thread, d'une pile d'appel. Cependant celui-ci a une particularit, il s'occupe de grer toutes les modications portant sur un composant graphique :  le redimensionnement ;  le changement de couleur ;  le changement de valeur ;  ... Vos applications graphiques seront plus performantes et plus sres lorsque vous utiliserez ce thread pour eectuer tous les changements qui pourraient intervenir sur votre IHM.

565

CHAPITRE 35. MIEUX GRER LES INTERACTIONS AVEC LES COMPOSANTS

Prsentation des protagonistes

Vous savez dj que, lorsque vous lancez un programme Java en mode console, un thread principal est dmarr pour empiler les instructions de votre programme jusqu' la n. Ce que vous ignorez peut-tre, c'est qu'un autre thread est lanc : celui qui s'occupe de toutes les tches de fond (lancement de nouveaux threads. . .). Or depuis un certain temps, nous ne travaillons plus en mode console mais en mode graphique. Et, je vous le donne en mille, un troisime thread est lanc qui se nomme l'EDT (Event Dispatch Thread ). Comme je vous le disais, c'est dans celui-ci que tous les changements portant sur des composants sont excuts. Voici un petit schma illustrant mes dires (gure 35.1).

Figure

35.1  Threads lancs au dmarrage de tout programme Java

La philosophie de Java est que toute modication apporte un composant se fait obligatoirement dans l'EDT : lorsque vous utilisez une mthode actionPerformed, celle-ci, son contenu compris, est excute dans l'EDT (c'est aussi le cas pour les autres intercepteurs d'vnements). La politique de Java est simple : toute action modiant l'tat d'un composant graphique doit se faire dans un seul et unique thread, l'EDT. Vous vous demandez srement pourquoi. C'est simple, les composants graphiques ne sont pas  thread-safe  : ils ne peuvent pas tre utiliss par plusieurs threads simultanment et assurer un fonctionnement sans erreurs ! Alors, pour s'assurer que les composants sont utiliss au bon endroit, on doit placer toutes les interactions dans l'EDT. Par contre, cela signie que si dans une mthode actionPerformed nous avons un traitement assez long, c'est toute notre interface graphique qui sera ge ! Vous vous souvenez de la premire fois que nous avons tent de contrler notre animation ? Lorsque nous cliquions sur le bouton pour la lancer, notre interface tait bloque tant donn que la mthode contenant une boucle innie n'tait pas dpile du thread dans lequel elle tait lance. D'ailleurs, si vous vous souvenez bien, le bouton s'achait comme si on n'avait pas relch le clic ; c'tait d au fait que l'excution de notre mthode se faisait dans l'EDT, bloquant ainsi toutes les actions sur nos composants. Voici un schma, en gure 35.2, rsumant la situation. Imaginez la ligne comme une tte de lecture. Il y a dj quelques vnements faire dans l'EDT :  la cration de la fentre ;  la cration et mise jour de composants ;  ... 566

UTILISER L'EDT

Figure

35.2  Pourquoi les IHM Java se gent lors de traitements longs

Seulement voil, nous cliquons sur un bouton engendrant un long, un trs long traitement dans l'EDT (dernier bloc) : du coup, toute notre IHM est ge ! Non pas parce que Java est lent, mais parce que nous avons excut un traitement au mauvais endroit. Il existe toutefois quelques mthodes thread-safe :  paint() et repaint() ;  validate(), invalidate() et revalidate(). Celles-ci peuvent tre appeles depuis n'importe quel thread. ce stade, une question se pose : comment excuter une action dans l'EDT ? C'est exactement ce que nous allons voir.

Utiliser l'EDT
Java vous fournit la classe SwingUtilities qui ore plusieurs mthodes statiques permettant d'insrer du code dans l'EDT :  invokeLater(Runnable doRun) : excute le thread en paramtre dans l'EDT et rend immdiatement la main au thread principal ;  invokeAndWait(Runnable doRun) : excute le thread en paramtre dans l'EDT et attend la n de celui-ci pour rendre la main au thread principal ;  isEventDispatchThread() : retourne vrai si le thread dans lequel se trouve l'instruction est dans l'EDT. Maintenant que vous savez comment excuter des instructions dans l'EDT, il nous faut un cas concret :
GGgv C rsp C y pour gnrer les imports puli lss estI { stti int ount a HD ountP a HY stti tfutton outon a new tfutton@4use4AY puli stti void min@tring rgsA{ tprme fen a new tprme@4ih4AY fenFgetgontentne@AFdd@outonAY fenFsetize@PHHD IHHAY fenFsethefultgloseypertion@tprmeFisyxgvyiAY fenFsetvotioneltiveo@nullAY fenFsetisile@trueAY

567

CHAPITRE 35. MIEUX GRER LES INTERACTIONS AVEC LES COMPOSANTS


updtefouton@AY ystemFoutFprintln@4eprise du thred prinipl4AY

puli stti void updtefouton@A{ for@int i a HY i ` SY iCCA{ try { hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY } outonFsetext@4use 4 C CCountAY } }

Au lancement de ce test, vous constatez que le thread principal ne reprend la main qu'aprs la n de la mthode updateBouton(), comme le montre la gure 35.3.

Figure

35.3  Thread principal bloqu durant un traitement

La solution pour rendre la main au thread principal avant la n de la mthode, vous la connaissez : crez un nouveau thread, mais cette fois vous allez galement excuter la mise jour du bouton dans l'EDT. Voil donc ce que nous obtenons :
GGgv C rsp C y pour gnrer les imports puli lss estI { stti int ount a HY stti tfutton outon a new tfutton@4use4AY puli stti void min@tring rgsA{ tprme fen a new tprme@4ih4AY fenFgetgontentne@AFdd@outonAY fenFsetize@PHHD IHHAY fenFsethefultgloseypertion@tprmeFisyxgvyiAY fenFsetvotioneltiveo@nullAY fenFsetisile@trueAY updtefouton@AY } ystemFoutFprintln@4eprise du thred prinipl4AY

puli stti void updtefouton@A{

568

UTILISER L'EDT
GGve seond thred new hred@new unnle@A{ puli void run@A{ for@int i a HY i ` SY iCCA{ try { hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY } GGwodifition de notre omposnt dns l9ih hred t a new hred@new unnle@A{ puli void run@A{ outonFsetext@4use 4 C CCountAY } }AY if@wingtilitiesFisiventhispthhred@AA tFstrt@AY else{ ystemFoutFprintln@4vnement dns l9 ih4AY wingtilitiesFinvokevter@tAY } } } }AFstrt@AY

Le rendu correspond la gure 35.4.

Figure

35.4  Lancement d'un traitement dans l'EDT

Ce code est rudimentaire, mais il a l'avantage de vous montrer comment utiliser les mthodes prsentes. Cependant, pour bien faire, j'aurais aussi d inclure la cration de la fentre dans l'EDT, car tout ce qui touche aux composants graphiques doit tre mis dans celui-ci. Pour nir notre tour du sujet, il manque encore la mthode invokeAndWait(). Celle-ci fait la mme chose que sa cousine, mais comme je vous le disais, elle bloque le thread courant jusqu' la n de son excution. De plus, elle peut lever deux exceptions : InterruptedException et InvocationTargetException . Depuis la version 6 de Java, une classe est mise disposition pour eectuer des traitements lourds et interagir avec l'EDT. 569

CHAPITRE 35. MIEUX GRER LES INTERACTIONS AVEC LES COMPOSANTS

La classe SwingWorker<T, V>

Cette dernire est une classe abstraite permettant de raliser des traitements en tche de fond tout en dialoguant avec les composants graphiques via l'EDT, aussi bien en cours de traitement qu'en n de traitement. Ds que vous aurez un traitement prenant pas mal de temps et devant interagir avec votre IHM, pensez aux SwingWorker. Vu que cette classe est abstraite, vous allez devoir rednir une mthode : doInBackground(). Elle permet de rednir ce que doit faire l'objet en tche de fond. Une fois cette tche eectue, la mthode doInBackground() prend n. Vous avez la possibilit de rednir la mthode done(), qui a pour rle d'interagir avec votre IHM tout en s'assurant que ce sera fait dans l'EDT. Implmenter la mthode done() est optionnel, vous n'tes nullement tenus de le faire. Voici un exemple d'utilisation :
GGgv C rsp C y pour gnrer les imports puli lss estI { stti int ount a HY stti tfutton outon a new tfutton@4use4AY puli stti void min@tring rgsA{ tprme fen a new tprme@4ih4AY fenFgetgontentne@AFdd@outonAY fenFsetize@PHHD IHHAY fenFsethefultgloseypertion@tprmeFisyxgvyiAY fenFsetvotioneltiveo@nullAY fenFsetisile@trueAY updtefouton@AY } ystemFoutFprintln@4eprise du thred prinipl4AY

puli stti void updtefouton@A{ GGyn re le wingorker wingorker sw a new wingorker@A{ proteted yjet dosnfkground@A throws ixeption { for@int i a HY i ` SY iCCA{ try { hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY } } return nullY } puli void done@A{ if@wingtilitiesFisiventhispthhred@AA ystemFoutFprintln@4hns l9ih 3 4AY

570

LA CLASSE SWINGWORKER<T, V>


outonFsetext@4ritement termin4AY

}Y GGyn lne le wingorker swFexeute@AY

Vous constatez que le traitement se fait bien en tche de fond, et que votre composant est mis jour dans l'EDT. La preuve sur la gure 35.5.

Figure

35.5  Utilisation d'un objet SwingWorker

Je vous disais plus haut que vous pouviez interagir avec l'EDT pendant le traitement. Pour ce faire, il sut d'utiliser la mthode setProgress(int progress) combine avec l'vnement PropertyChangeListener , qui sera inform du changement d'tat de la proprit progress. Voici un code d'exemple :
GGgv C rsp C y pour gnrer les imports puli lss estI { stti int ount a HY stti tfutton outon a new tfutton@4use4AY puli stti void min@tring rgsA{ tprme fen a new tprme@4ih4AY fenFgetgontentne@AFdd@outonAY fenFsetize@PHHD IHHAY fenFsethefultgloseypertion@tprmeFisyxgvyiAY fenFsetvotioneltiveo@nullAY fenFsetisile@trueAY updtefouton@AY } ystemFoutFprintln@4eprise du thred prinipl4AY

puli stti void updtefouton@A{ wingorker sw a new wingorker@A{ proteted yjet dosnfkground@A throws ixeption { for@int i a HY i ` SY iCCA{

571

CHAPITRE 35. MIEUX GRER LES INTERACTIONS AVEC LES COMPOSANTS


try { GGyn hnge l proprit d9tt setrogress@iAY hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY }

} return nullY

}Y GGyn oute le hngement de vleur pour l proprit swFddropertyghngevistener@new ropertyghngevistener@A{ GGwthode de l9interfe puli void propertyghnge@ropertyghngeivent eventA { GGyn vrifie tout de mme le nom de l proprit if@4progress4Fequls@eventFgetropertyxme@AAA{ if@wingtilitiesFisiventhispthhred@AA ystemFoutFprintln@4hns le listener don dns l9ih 3 4AY GGyn rupre s nouvelle vleur outonFsetext@4use 4 C @sntegerA eventFgetxewlue@AAY } } }AY GGyn lne le wingorker swFexeute@AY

puli void done@A{ if@wingtilitiesFisiventhispthhred@AA ystemFoutFprintln@4hns l9ih 3 4AY outonFsetext@4ritement termin4AY }

La gure 35.6 prsente le rsultat de celui-ci.

Figure

35.6  Utilisation de setProgress(int i)

Les mthodes que vous avez vues jusqu'ici sont issues de la classe SwingWorker, qui implmente l'interface java.util.concurrent.Future , orant les mthodes suivantes :  get() : permet la mthode doInBackground() de renvoyer son rsultat d'autres threads ; 572

LA CLASSE SWINGWORKER<T, V>  cancel() : essaie d'interrompre la tche de doInBackground() en cours ;  isCancelled() : retourne vrai si l'action a t interrompue ;  isDone() : retourne vrai si l'action est termine. Nous pouvons donc utiliser ces mthodes dans notre objet SwingWorker an de rcuprer le rsultat d'un traitement. Pour le moment, nous n'avons pas utilis la gnricit de cette classe. Or, comme l'indique le titre de cette section, SwingWorker peut prendre deux types gnriques. Le premier correspond au type de renvoi de la mthode doInBackground() et, par extension, au type de renvoi de la mthode get(). Le deuxime est utilis comme type de retour intermdiaire pendant l'excution de la mthode doInBackground(). An de grer les rsultats intermdiaires, vous pouvez utiliser les mthodes suivantes :  publish(V value) : publie le rsultat intermdiaire pour la mthode progress(List<V> list) ;  progress(List<V> list) : permet d'utiliser le rsultat intermdiaire pour un traitement spcique. Voici l'exemple utilis jusqu'ici avec les complments :
GGgv C rsp C y pour gnrer les imports puli lss estI { stti int ount a HY stti tfutton outon a new tfutton@4use4AY puli stti void min@tring rgsA{ tprme fen a new tprme@4ih4AY fenFgetgontentne@AFdd@outonAY fenFsetize@PHHD IHHAY fenFsethefultgloseypertion@tprmeFisyxgvyiAY fenFsetvotioneltiveo@nullAY fenFsetisile@trueAY updtefouton@AY } ystemFoutFprintln@4eprise du thred prinipl4AY

puli stti void updtefouton@A{ GGyn re un orker gnriqueD ette fois wingorker sw a new wingorker`sntegerD tringb@A{ proteted snteger dosnfkground@A throws ixeption { int iY for@i a HY i ` SY iCCA{ try { GGyn hnge l proprit d9tt setrogress@iAY GGyn pulie un rsultt intermdiire pulish@4our de oule x 4 C @iCIAAY

573

CHAPITRE 35. MIEUX GRER LES INTERACTIONS AVEC LES COMPOSANTS


hredFsleep@IHHHAY } th @snterruptedixeption eA { eFprinttkre@AY }

} return iY

}Y GGyn oute le hngement de vleur pour l proprit swFddropertyghngevistener@new ropertyghngevistener@A{ GGwthode de l9interfe puli void propertyghnge@ropertyghngeivent eventA { GGyn vrifie tout de mme le nom de l proprit if@4progress4Fequls@eventFgetropertyxme@AAA{ if@wingtilitiesFisiventhispthhred@AA ystemFoutFprintln@4hns le listener don dns l9ih 3 4AY GGyn rupre s nouvelle vleur outonFsetext@4use 4 C @sntegerA eventFgetxewlue@AAY } } }AY GGyn lne le wingorker swFexeute@AY

puli void done@A{ if@wingtilitiesFisiventhispthhred@AA ystemFoutFprintln@4hns l9ih 3 4AY try { GGyn utilise l mthode get@A pour ruprer le rsultt GGde l mthode dosnfkground@A outonFsetext@4ritement termin u out de 4Cget@AC4 fois 34AY } th @snterruptedixeption eA { eFprinttkre@AY } th @ixeutionixeption eA { eFprinttkre@AY } } GGv mthode grnt les rsultts intermdiires puli void proess@vist`tringb listA{ for@tring str X listA ystemFoutFprintln@strAY }

Et le rsultat, en gure 35.7, parle de lui-mme. Voil : vous savez maintenant comment utiliser l'EDT et les SwingWorker. Vos applications n'en seront que plus ractives ! 574

LA CLASSE SWINGWORKER<T, V>

Figure

35.7  Utilisation de types gnriques avec un objet SwingWorker

En rsum
 Au lancement d'un programme Java, trois threads se lancent : le thread principal, celui grant les tches de fond et l'EDT.  Java prconise que toute modication des composants graphiques se fasse dans l'EDT.  Si vos IHM se gent, c'est peut-tre parce que vous avez lanc un traitement long dans l'EDT.  An d'amliorer la ractivit de vos applications, vous devez choisir au mieux dans quel thread vous allez traiter vos donnes.  Java ore la classe SwingUtilities, qui permet de lancer des actions dans l'EDT depuis n'importe quel thread.  Depuis Java 6, la classe SwingWorker(<T, V>) vous ore la possibilit de lancer des traitements dans un thread en vous assurant que les mises jour des composants se feront dans l'EDT.

575

CHAPITRE 35. MIEUX GRER LES INTERACTIONS AVEC LES COMPOSANTS

576

Quatrime partie
Interactions avec les bases de donnes

577

Chapitre

36
Dicult :

JDBC : la porte d'accs aux bases de donnes

ans ce chapitre, nous ferons nos premiers pas avec Java DataBase Connectivity , communment appel JDBC. Il s'agit en fait de classes Java permettant de se connecter et d'interagir avec des bases de donnes. Mais avant toute chose, il nous faut une base de donnes ! Nous allons donc nous pencher sur l'utilit d'une base de donnes et verrons comment en installer une que nous utiliserons an d'illustrer la suite de cette partie. Pour commencer, je pense qu'un petit rappel sur le fonctionnement des bases de donnes s'impose.

579

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES

Rappels sur les bases de donnes


Lorsque vous ralisez un logiciel, un site web ou quelque chose d'autre, vous tes confronts tt ou tard cette question :  Comment vais-je procder pour sauvegarder mes donnes ? Pourquoi ne pas tout stocker dans des chiers ?  Les bases de donnes (BDD) permettent de stocker des donnes. Mais concrtement, comment cela fonctionne-t-il ? En quelques mots, il s'agit d'un systme de chiers contenant les donnes de votre application. Cependant, ces chiers sont totalement transparents pour l'utilisateur d'une base de donnes, donc totalement transparents pour vous ! La dirence avec les chiers classiques se trouve dans le fait que ce n'est pas vous qui les grez : c'est votre BDD qui les organise, les range et, le cas chant, vous retourne les informations qui y sont stockes. De plus, plusieurs utilisateurs peuvent accder simultanment aux donnes dont ils ont besoin, sans compter que de nos jours, les applications sont amenes traiter une grande quantit de donnes, le tout en rseau. Imaginez-vous grer tout cela manuellement alors que les BDD le font automatiquement. . . Les donnes sont ordonnes par  tables , c'est--dire par regroupements de plusieurs valeurs. C'est vous qui crerez vos propres tables, en spciant quelles donnes vous souhaiterez y intgrer. Une base de donnes peut tre vue comme une gigantesque armoire tiroirs dont vous spciez les noms et qui contiennent une multitude de ches dont vous spciez aussi le contenu. Je sais, un schma est toujours le bienvenu, je vous invite donc jeter un il la gure 36.1.

Figure

36.1  Une BDD contenant deux tables

Dans cette base de donnes, nous trouvons deux tables : une dont le rle est de stocker des informations relatives des personnes (noms, prnoms et ges) ainsi qu'une autre qui s'occupe de stocker des pays, avec leur nom et leur capitale. Si je reprends ma comparaison ci-dessus, la BDD symbolise l'armoire, chaque table reprsente un tiroir et chaque ligne de la table correspond une che de ce tiroir ! 580

RAPPELS SUR LES BASES DE DONNES De plus, ce qui est formidable avec les BDD, c'est que vous pouvez les interroger en leur posant des questions via un langage prcis. Vous pouvez interroger votre base de donnes en lui donnant les instructions suivantes :   Donne-moi la che de la table Personne pour le nom HERBY  ;   Donne-moi la che de la table Pays pour le pays France  ;  etc. Le langage permettant d'interroger des bases de donnes est le langage SQL 1 . Grce aux BDD, vos donnes sont stockes, classes par vos soins et identiables facilement sans avoir grer votre propre systme de chiers. Pour utiliser une BDD, vous avez besoin de deux lments : la base de donnes et ce qu'on appelle le SGBD 2 .

Cette partie ne s'intresse pas au langage SQL. Vous pouvez cependant trouver une introduction ce langage sur le Site du Zro ; elle fait partie d'un tutoriel traitant du PHP, mais il sut de ne vous attarder que sur le SQL. Je vous conseille de lire galement le chapitre suivant.
Introduction au SQL Code web : 555604 


Quelle base de donnes utiliser


Il existe plusieurs bases de donnes et toutes sont utilises par beaucoup de dveloppeurs. Voici une liste non exhaustive recensant les principales bases :  PostgreSQL ;  MySQL ;  SQL Server ;  Oracle ;  Access. Toutes ces bases de donnes permettent d'eectuer les actions que je vous ai expliques plus haut. Chacune possde des spcicits : certaines sont payantes (Oracle), d'autres sont plutt permissives avec les donnes qu'elles contiennent (MySQL), d'autres encore sont dotes d'un systme de gestion trs simple utiliser (MySQL). . . C'est vous de faire votre choix en regardant par exemple sur Internet ce qu'en disent les utilisateurs. Pour cette partie traitant des bases de donnes, mon choix s'est port sur PostgreSQL qui est gratuit et complet. Alors, continuons !

Installation de PostgreSQL
Tlchargez une version de PostgreSQL pour Windows, Linux ou Mac OS X.
1. Structured Query Language ou, en franais,  langage de requte structure . 2. Systme de Gestion de Base de Donnes.

581

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES Tlcharger PostgreSQL Code web : 339582  Je vous invite dcompresser l'archive tlcharge et excuter le chier. partir de maintenant, si je ne mentionne pas une fentre de l'assistant d'installation particulire, vous pouvez laisser les rglages par dfaut. L'installation commence et il vous est demand votre langue : choisissez et validez. Vous serez invits, par la suite, saisir un mot de passe pour l'utilisateur (gure 36.2).


Figure

36.2  Choix du mot de passe

Un mot de passe vous sera galement demand pour le superadministrateur (gure 36.3). la n de la prinstallation, vous aurez le choix d'excuter ou non le  Stack Builder  ; ce n'est pas ncessaire, il permet juste d'installer d'autres logiciels en rapport avec PostgreSQL. Le serveur est prsent install : il doit en tre de mme pour le SGBD ! Pour vrier que l'installation s'est bien droule, ouvrez le menu  Dmarrer  et rendezvous dans Tous les programmes (sous Windows) : l'encart  PostgreSQL 8.3  3 doit ressembler la gure 36.4. Dans ce dossier, deux excutables permettent respectivement de lancer et d'arrter le serveur. Le dernier excutable, pgAdmin III, correspond notre SGBD : lancez-le, nous allons congurer notre serveur. Dans le menu  Fichier , choisissez  Ajouter un serveur...  (gure 36.5). Cela vous amne la gure 36.6.   Nom  correspond au nom de votre base de donnes.   Hte  correspond l'adresse du serveur sur le rseau ; ici, le serveur est situ sur votre ordinateur, inscrivez donc localhost.
3. Le numro de version peut tre plus rcent.

582

RAPPELS SUR LES BASES DE DONNES

Figure

36.3  Choix du mot de passe pour le superutilisateur

Figure

36.4  Menu  Dmarrer  avec PostgreSQL

Figure

36.5  Ajout d'un serveur

583

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES

Figure

36.6  Conguration du serveur

 Vous n'avez normalement pas besoin de modier le port ; dans le cas contraire, insrez la valeur qui gure sur l'image.  Entrez enn le nom de l'utilisateur et le mot de passe. Voil : vous devriez maintenant avoir la gure 36.7 devant les yeux. Nous reviendrons sur tout cela, mais vous pouvez observer que votre serveur, nomm  SDZ , possde une base de donnes appele postgres ne contenant aucune table. Simple, mais ecace ! Nous avons install notre serveur, nous allons donc apprendre crer une base, des tables et surtout faire un bref rappel sur ce fameux langage SQL.

Prparer la base de donnes


Vous tes prsent connects votre BDD prfre. Premirement, les bases de donnes servent stocker des informations ; a, vous le savez. Mais ce que vous ignorez peut-tre, c'est que pour ranger correctement nos informations, nous devrons les analyser. . . Ce chapitre n'a pas pour objectif de traiter de l'analyse combine avec des diagrammes entits  associations 4 . . . Nous nous contenterons de poser un thme et d'agir comme si nous connaissions tout cela ! Pour notre base de donnes, nous allons donc grer une cole dont voici les caractristiques :  cette cole est compose de classes ;  chaque classe est compose d'lves ;
4. Dans le jargon, cela dsigne ce dont on se sert pour crer des BDD, c'est--dire pour organiser les informations des tables et de leur contenu.

584

PRPARER LA BASE DE DONNES

Figure

36.7  Votre premire base de donnes

585

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES  chaque classe est attribu un professeur pour chacune des matires dispenses ;  un professeur peut enseigner plusieurs matires et exercer ses fonctions dans plusieurs classes. Vous vous rendez compte qu'il y a beaucoup d'informations grer. En thorie, nous devrions tablir un dictionnaire des donnes, vrier qui appartient quelle donne, poursuivre avec une modlisation la faon MCD 5 et simplier le tout selon certaines rgles, pour terminer avec un MPD 6 . Nous raccourcirons le processus : je vous fournis un modle tout prt (gure 36.8) que je vous expliquerai tout de mme.

Figure

36.8  Modle de notre BDD

Tous ces lments correspondent nos futures tables ; les attributs qui s'y trouvent se nomment des  champs . Tous les acteurs mentionns gurent dans ce schma (classe, professeur, lve. . .). Vous constatez que chaque acteur possde un attribut nomm  id  correspondant son identiant : c'est un champ de type entier qui s'incrmentera chaque nouvelle entre ; c'est galement grce ce champ que nous pouvons crer des liens entre les acteurs. Vous devez savoir que les ches du schma signient  a un  ; de ce fait, un lve  a une  classe.
5. Modle Conceptuel de Donnes. 6. Modle Physique de Donnes.

586

PRPARER LA BASE DE DONNES Certaines tables contiennent un champ ayant une spcicit : un champ dont le nom se termine par  _k . Quelques-unes de ces tables possdent deux champs de cette nature, pour une raison trs simple : parce que nous avons dcid qu'un professeur pouvait enseigner plusieurs matires, nous avons alors besoin de ce qu'on appelle une  table de jointure . Ainsi, nous pouvons spcier que tel professeur enseigne telle ou telle matire et qu'une association professeur  matire est assigne une classe. Ces liens se feront par les identiants ( id). De plus  il est dicile de ne pas avoir remarqu cela  chaque champ possde un type (int, double, date, boolean. . .). Nous savons maintenant tout ce qui est ncessaire pour construire notre BDD !

Crer la base de donnes


Pour cette opration, rien de plus simple : pgAdmin met notre disposition un outil qui facilite la cration de bases de donnes et de tables (excuter tout cela la main avec SQL, c'est un peu fastidieux). Pour crer une nouvelle base de donnes, eectuez un clic droit sur  Bases de donnes  (gure 36.9).

Figure

36.9  Ajouter une BDD

Le pop-up correspondant la gure 36.10 s'ache alors.

Figure

36.10  Crer les caractristiques

Renseignez le nom de la base de donnes ( Ecole dans notre cas) et choisissez l'encodage UTF-8. Cet encodage correspond un jeu de caractres tendu qui autorise les caractres spciaux. Une fois cela fait, vous devriez obtenir quelque chose de similaire la gure 36.11. Vous pouvez dsormais voir la nouvelle base de donnes ainsi que le script SQL permettant de la crer. Il ne nous reste plus qu' crer les tables l'aide du bon type de donnes. . . 587

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES

Figure

36.11  Premire BDD

Crer les tables


Nous allons maintenant nous attaquer la cration de nos tables an de pouvoir travailler correctement. Je vous expliquerai comment crer une table simple pour vous donner une ide du principe ; je fournirai aux plus fainants le script SQL qui nira la cration des tables. Commenons par la table classe, tant donn que c'est l'une des tables qui n'a aucun lien avec une autre. La procdure est la mme que prcdemment : il vous sut d'eectuer un clic droit sur  Tables  cette fois, comme le montre la gure 36.12.

Figure

36.12  Ajouter une table

Ensuite, PostgreSQL vous demande des informations sur la future table :  son nom ;  le nom de ses champs ;  le type de ses champs ;  ainsi que d'autres lments. La gure 36.13 dsigne l'endroit o vous devez renseigner le nom de la table. Ajoutez ensuite les champs, comme le montrent les gures 36.14 et 36.15 (j'ai ajout des prxes aux champs pour qu'il n'y ait pas d'ambigut dans les requtes SQL).

Le champ cls_id est de type serial an qu'il utilise une squence 7 . Nous allons aussi lui ajouter une contrainte de cl primaire.
Placez donc maintenant la contrainte de cl primaire sur votre identiant, comme
7. Le champ s'incrmente ainsi automatiquement.

588

PRPARER LA BASE DE DONNES

Figure

36.13  Nommer la table

Figure

36.14  Ajout d'une colonne la table

Figure

36.15  Ajout de la colonne cls_id

589

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES reprsent la gure 36.16.

Figure

36.16  Ajout d'une contrainte de cl primaire

Cliquez sur  Ajouter . Choisissez la colonne cls_id et cliquez sur  Ajouter . Validez ensuite le tout (gure 36.17).

Figure

36.17  Ajout d'une contrainte

Vous avez vu comment crer une table avec PostgreSQL, mais je ne vais pas vous demander de le faire pour chacune d'entre elles, je ne suis pas mchant ce point. Vous n'allez donc pas crer toutes les tables et tous les champs de cette manire, puisque cet ouvrage a pour but de vous apprendre utiliser les BDD avec Java, pas avec le SGBD. . . Voici alors le code web vous donnant accs une archive .zip contenant le script SQL de cration des tables restantes ainsi que de leur contenu. Tlcharger la BDD Code web : 888696  Une fois le dossier dcompress, il ne vous reste plus qu' ouvrir le chier avec PostgreSQL en vous rendant dans l'diteur de requtes SQL (gure 36.18).


Figure

36.18  Icne d'ouverture de l'diteur de requtes

Vous pouvez prsent ouvrir le chier que je vous ai fourni en cliquant sur  Fichier Ouvrir  puis choisir le chier .sql. Excutez la requte en appuyant sur F5 ou dirigez-vous vers le menu  Requte  et choisissez l'action  Excuter . Fermez l'diteur de requtes. 590

SE CONNECTER LA BASE DE DONNES Votre base est maintenant entirement cre, et en plus, elle contient des donnes (gure 36.19) !

Figure

36.19  Votre base de donnes

Se connecter la base de donnes


Beaucoup de choses se passent entre pgAdmin et PostgreSQL 8 ! En eet, le premier est un programme qui tablit une connexion avec la BDD an qu'ils puissent communiquer. Cela peut se schmatiser par la gure 36.20.

Figure

36.20  Communication entre le SGBD et la BDD

Ceux d'entre vous qui ont dj install une imprimante savent que leur machine a besoin d'un driver 9 pour que la communication puisse s'eectuer entre les deux acteurs. Ici, c'est la mme chose : pgAdmin utilise un driver pour se connecter la base de donnes. tant donn que les personnes qui ont dvelopp les deux logiciels travaillent main dans la main, il n'y aura pas de problme de communication ; mais qu'en sera-t-il pour Java ? En fait, avec Java, vous aurez besoin de drivers, mais pas sous n'importe quelle forme : pour vous connecter une base de donnes, il vous faut un chier .jar qui correspond au fameux pilote et qui contient tout ce dont vous aurez besoin pour vous connecter une base PostgreSQL.
8. Les termes  PostgreSQL  et  Postgres  sont souvent indiremment utiliss. 9. Appel aussi pilote, c'est une sorte de mode d'emploi utilis par l'ordinateur.

591

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES

Cela signie-t-il qu'il existe un chier .jar par SGBD ?


Tout fait, il existe un chier .jar pour se connecter :  MySQL ;  SQL Server ;  Oracle ;  d'autres bases. Un bmol toutefois : vous pouvez aussi vous connecter une BDD en utilisant les pilotes ODBC 10 prsents dans Windows. Cela ncessite cependant d'installer les pilotes dans Windows et de les paramtrer dans les sources de donnes ODBC pour, par la suite, utiliser ces pilotes ODBC an de se connecter la BDD dans un programme Java. Je ne parlerai donc pas de cette mthode puisqu'elle ne fonctionne que pour Windows. Pour trouver le driver JDBC qu'il vous faut, une rapide recherche l'aide de votre moteur de recherche rpondra vos attentes (gure 36.21).

Figure

36.21  Recherche des pilotes JDBC pour PostgreSQL

Sur la page de tlchargement des pilotes pour PostgreSQL, choisissez la dernire version disponible ; pour ma part, j'ai opt pour la version JDBC4 (gure 36.22). La version JDBC4 ore des nouveauts et une souplesse d'utilisation accrue de JDBC, mais vous devez savoir qu'il existe trois autres types de drivers JDBC ; au total, il en existe donc quatre :  des drivers JDBC de type 1 : JDBC-ODBC, ce type utilise l'interface ODBC pour se connecter une base de donnes (on en a dj parl) ; au niveau de la portabilit, on trouve mieux ;  des drivers JDBC de type 2 : ils intgrent les pilotes natifs et les pilotes Java ; en fait, la partie Java traduit les instructions en natif an d'tre comprises et interprtes par les pilotes natifs ;  des drivers JDBC de type 3 : crit entirement en Java, ce type convertit les appels en un langage totalement indpendant du SGBD ; un serveur intgr traduit ensuite les instructions dans le langage souhait par le SGBD ;  des drivers JDBC de type 4 : des pilotes convertissant directement les appels JDBC en instructions comprhensibles par le SGBD ; ce type de drivers est cod et propos par les diteurs de BDD.
10.

Open DataBase Connectivity .

592

SE CONNECTER LA BASE DE DONNES

Figure

36.22  Tlchargement des pilotes

Tlchargez donc le chier .jar dans la rubrique  Download  du site ddi : http://jdbc.postgresql.org . Nous nous pencherons bientt sur son utilisation, mais une question se pose encore : o placer l'archive ? Vous avez deux solutions :  l'inclure dans votre projet et l'ajouter au CLASSPATH ;  la placer dans le dossier lib/ext prsent dans le dossier d'installation du JRE. Le tout est de savoir si votre application est voue tre exporte sur dirents postes ; dans ce cas, l'approche CLASSPATH est la plus judicieuse (sinon, il faudra ajouter l'archive dans tous les JRE. . .). En ce qui nous concerne, nous utiliserons la deuxime mthode an de ne pas surcharger nos projets. Je vous laisse donc placer l'archive tlcharge dans le dossier susmentionn.

Connexion
La base de donnes est prte, les tables sont cres, remplies et nous possdons le driver ncessaire ! Il ne nous reste plus qu' nous connecter. Crons un nouveau projet dans Eclipse avec une classe contenant une mthode public static void main(String[] args). Voici le code source permettant la connexion :
GGgv C rsp C y pour gnrer les imports puli lss gonnet { puli stti void min@tring rgsA { try {

593

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES


glssFforxme@4orgFpostgresqlFhriver4AY ystemFoutFprintln@4hriver yFuF4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY ystemFoutFprintln@4gonnexion effetive 34AY } th @ixeption eA { eFprinttkre@AY }

Dtaillons un peu tout cela. Dans un premier temps, nous avons cr une instance de l'objet Driver prsent dans le chier .jar que nous avons tlcharg. Il est inutile de crer une vritable instance de ce type d'objet ; j'entends par l que l'instruction org.postgres.Driver driver = new org.postgres.Driver() n'est pas ncessaire. Nous utilisons alors la rexivit an d'instancier cet objet. ce stade, il existe comme un pont entre votre programme Java et votre BDD, mais le trac routier n'y est pas encore autoris : il faut qu'une connexion soit eective an que le programme et la base de donnes puissent communiquer. Cela se ralise grce cette ligne de code : Connection conn = DriverManager.getConnection(url, user, passwd); . Nous avons dni au pralable trois String contenant respectivement :  l'URL de connexion ;  le nom de l'utilisateur ;  le mot de passe utilisateur. L'URL de connexion est indispensable Java pour se connecter n'importe quelle BDD. La gure 36.23 illustre la manire dont se dcompose cette URL.

Figure

36.23  URL de connexion une BDD via JDBC

Le premier bloc correspond au dbut de l'URL de connexion, qui commence toujours par jdbc:. Dans notre cas, nous utilisons PostgreSQL, la dnomination postgresql: suit donc le dbut de l'URL. Si vous utilisez une source de donnes ODBC, il faut crire jdbc:odbc:. En fait, cela dpend du pilote JDBC et permet Java de savoir quel pilote utiliser. 594

SE CONNECTER LA BASE DE DONNES Dans le deuxime bloc se trouve la localisation de la machine physique sur le rseau ; ici, nous travaillons en local, nous utilisons donc //localhost:5432. En eet, le nom de la machine physique est suivi du numro de port utilis. Enn, dans le dernier bloc, pour ceux qui ne l'auraient pas devin, il s'agit du nom de notre base de donnes.

Les informations des deux derniers blocs dpendent du pilote JDBC utilis. Pour en savoir plus, consultez sa documentation.
En excutant ce code, vous obtiendrez le rsultat ach la gure 36.24.

Figure

36.24  Connexion eective

Cette procdure lve une exception en cas de problme (mot de passe invalide. . .).
L'avantage d'utiliser les chiers .jar comme drivers de connexion est que vous n'tes pas tenus d'initialiser le driver par une mthode telle que la rexivit, tout se passe dans Java. Puisqu'un rappel du protocole utiliser est prsent dans l'URL de connexion, tout est optimal et Java s'en sort tout seul ! Ne vous tonnez donc pas si vous ne voyez plus l'instruction Class.forName("org.postgresql.Driver") par la suite. . .

En rsum
  JDBC  signie  Java DataBase Connectivity .  JDBC permet des programmes Java de communiquer avec des bases de donnes.  Une base de donnes est un systme de chiers stockant des informations regroupes dans des tables.  Vous pouvez interroger une base de donnes grce au langage SQL.  Il existe plusieurs types de drivers JDBC utiliser selon la faon dont vous souhaitez vous connecter la BDD.  Pour vous connecter votre BDD, vous devez utiliser l'objet Connection fourni par l'objet DriverManager.  Celui-ci prend en paramtre une URL de connexion permettant d'identier le type de base de donnes, l'adresse du serveur et le nom de la base interroger, en plus du nom d'utilisateur et du mot de passe de connexion.  Si une erreur survient pendant la connexion, une exception est leve. 595

CHAPITRE 36. JDBC : LA PORTE D'ACCS AUX BASES DE DONNES

596

Chapitre

37
Dicult :

Fouiller dans sa base de donnes

ous continuons notre voyage initiatique au pays de JDBC en abordant la manire d'interroger notre BDD. Eh oui, une base de donnes n'est utile que si nous pouvons consulter, ajouter, modier et supprimer les donnes qu'elle contient. Pour y parvenir, il tait impratif de se connecter au pralable. Maintenant que c'est chose faite, nous allons voir comment fouiner dans notre BDD.

597

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES

Le couple Statement  ResultSet


Voici deux objets que vous utiliserez srement beaucoup ! En fait, ce sont ces deux objets qui permettent de rcuprer des donnes de la BDD et de travailler avec cellesci. An de vous faire comprendre tout cela de faon simple, voici un exemple assez complet (mais tout de mme pas exhaustif) achant le contenu de la table classe :
GGgv C rsp C y pour gnrer les imports puli lss gonnet { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY GGgrtion d9un ojet ttement ttement stte a onnFretettement@AY GGv9ojet esultet ontient le rsultt de l requte v esultet result a stteFexeuteuery@4ivig B pyw lsse4AY GGyn rupre les wetht esultetwetht resultwet a resultFgetwetht@AY ystemFoutFprintln@4nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY GGyn ffihe le nom des olonnes for@int i a IY i `a resultwetFgetgolumngount@AY iCCA ystemFoutFprint @4t4 C resultwetFgetgolumnxme@iAFtoppergse@A C 4t B4AY ystemFoutFprintln@4nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY while@resultFnext@AA{ for@int i a IY i `a resultwetFgetgolumngount@AY iCCA ystemFoutFprint @4t4 C resultFgetyjet@iAFtotring@A C 4t |4AY ystemFoutFprintln@4nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY } resultFlose@AY stteFlose@AY

598

LE COUPLE STATEMENT  RESULTSET


} th @ixeption eA { eFprinttkre@AY }

La gure 37.1 nous montre le rsultat de ce code.

Figure

37.1  Recherche dans la table classe

Les metadatas 1 constituent en ralit un ensemble de donnes servant dcrire une structure. Dans notre cas, elles permettent de connatre le nom des tables, des champs, leur type. . .
J'ai simplement excut une requte SQL et rcupr les lignes retournes. Mais dtaillons un peu plus ce qu'il s'est pass. Dj, vous avez pu remarquer que j'ai spci l'URL complte pour la connexion : sinon, comment savoir quelle BDD se connecter ? Ce dernier point mis part, les choses se sont droules en quatre tapes distinctes :  cration de l'objet Statement ;  excution de la requte SQL ;  rcupration et achage des donnes via l'objet ResultSet ;  fermeture des objets utiliss (bien que non obligatoire, c'est recommand). L'objet Statement permet d'excuter des instructions SQL, il interroge la base de donnes et retourne les rsultats. Ensuite, ces rsultats sont stocks dans l'objet ResultSet, grce auquel on peut parcourir les lignes de rsultats et les acher. Comme je vous
1. Ou, plus communment, les mtadonnes.

599

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES l'ai mentionn, l'objet Statement permet d'excuter des requtes SQL. Ces dernires peuvent tre de dirents types :  CREATE ;  INSERT ;  UPDATE ;  SELECT ;  DELETE. L'objet Statement est fourni par l'objet Connection grce l'instruction conn.createStatement() . Ce que j'ai fait, ensuite, c'est demander mon objet Statement d'excuter une requte SQL de type SELECT : SELECT * FROM classe. Elle demande la BDD de nous envoyer toutes les classes. Puisque cette requte retourne un rsultat contenant beaucoup de lignes, contenant elles-mmes plusieurs colonnes, j'ai stock ce rsultat dans un objet ResultSet, qui permet d'eectuer diverses actions sur des rsultats de requtes SQL. Ici, j'ai utilis un objet de type ResultSetMetaData an de rcuprer les mtadonnes de ma requte, c'est--dire ses informations globales. J'ai ensuite utilis cet objet an de rcuprer le nombre de colonnes renvoy par la requte SQL ainsi que leur nom. Cet objet de mtadonnes permet de rcuprer des informations trs utiles, comme :  le nombre de colonnes d'un rsultat ;  le nom des colonnes d'un rsultat ;  le type de donnes stock dans chaque colonne ;  le nom de la table laquelle appartient la colonne (dans le cas d'une jointure de tables) ;  etc.

Il existe aussi un objet DataBaseMetaData qui fournit des informations sur la base de donnes.
Vous comprenez mieux prsent ce que signie cette portion de code :
ystemFoutFprintln@4nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY GGyn ffihe le nom des olonnes for@int i a IY i `a resultwetFgetgolumngount@AY iCCA ystemFoutFprint @4t4 C resultwetFgetgolumnxme@iAFtoppergse@A C 4t B4AY ystemFoutFprintln@4nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY

Je me suis servi de la mthode retournant le nombre de colonnes dans le rsultat an de rcuprer le nom de la colonne grce son index.

Attention : contrairement aux indices de tableaux, les indices de colonnes SQL commencent 1 !
600

LE COUPLE STATEMENT  RESULTSET Ensuite, je rcupre les donnes de la requte en me servant de l'indice des colonnes :
while@resultFnext@AA{ for@int i a IY i `a resultwetFgetgolumngount@AY iCCA ystemFoutFprint @4t4 C resultFgetyjet@iAFtotring@A C 4t |4AY } ystemFoutFprintln@4nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY

J'utilise une premire boucle me permettant alors de parcourir chaque ligne via la boucle for tant que l'objet ResultSet retourne des lignes de rsultats. La mthode next() permet de positionner l'objet sur la ligne suivante de la liste de rsultats. Au premier tour de boucle, cette mthode place l'objet sur la premire ligne. Si vous n'avez pas positionn l'objet ResultSet et que vous tentez de lire des donnes, une exception est leve ! Je suis parti du principe que le type de donnes de mes colonnes tait inconnu, mais tant donn que je les connais, le code suivant aurait tout aussi bien fonctionn :
while@resultFnext@AA{ ystemFoutFprint@4t4 C resultFgetsnt@4lsid4A C 4t |4AY ystemFoutFprint@4t4 C resultFgettring@4lsnom4A C 4t |4AY ystemFoutFprintln@4nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY }

Je connais dsormais le nom des colonnes retournes par la requte SQL. Je connais galement leur type, il me sut donc d'invoquer la mthode adquate de l'objet ResultSet en utilisant le nom de la colonne rcuprer. En revanche, si vous essayez de rcuprer le contenu de la colonne cls_nom avec la mthode getInt("cls_nom"), vous aurez une exception ! Il existe une mthode getXXX() par type primitif ainsi que quelques autres correspondant aux types SQL :  getArray(int colummnIndex) ;  getAscii(int colummnIndex) ;  getBigDecimal(int colummnIndex) ;  getBinary(int colummnIndex) ;  getBlob(int colummnIndex) ;  getBoolean(int colummnIndex) ;  getBytes(int colummnIndex) ;  getCharacter(int colummnIndex) ;  getDate(int colummnIndex) ;  getDouble(int colummnIndex) ;  getFloat(int colummnIndex) ;  getInt(int colummnIndex) ;  getLong(int colummnIndex) ;  getObject(int colummnIndex) ; 601

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES  getString(int colummnIndex) . Pour nir, je n'ai plus qu' fermer mes objets l'aide des instructions result.close() et state.close(). Avant de voir plus en dtail les possibilits qu'orent ces objets, nous allons crer deux ou trois requtes SQL an de nous habituer la faon dont tout cela fonctionne.

Entranons-nous
Le but du jeu est de coder les rsultats que j'ai obtenus. Voici, en gure 37.2, ce que vous devez rcuprer en premier. Je vous laisse chercher dans quelle table nous allons travailler.

Figure

37.2  Entranement la recherche

Cherchez bien. . . Bon, vous avez srement trouv, il n'y avait rien de compliqu. Voici une des corrections possibles :
GGgv C rsp C y pour gnrer les imports puli lss ixoI { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y

602

LE COUPLE STATEMENT  RESULTSET

gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY ttement stte a onnFretettement@AY esultet result a stteFexeuteuery@4ivig B pyw professeur4AY esultetwetht resultwet a resultFgetwetht@AY ystemFoutFprintln@4E sl y 4 C resultwetFgetgolumngount@A C 4 olonnes dns ette tle4AY for@int i a IY i `a resultwetFgetgolumngount@AY iCCA ystemFoutFprintln@4t B4 C resultwetFgetgolumnxme@iAAY ystemFoutFprintln@4oii les noms et prnoms X 4AY ystemFoutFprintln@4nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY while@resultFnext@AA{ ystemFoutFprint@4t4 C resultFgettring@4profnom4A C 4t |4AY ystemFoutFprint@4t4 C resultFgettring@4profprenom4A C 4t |4AY ystemFoutFprintln@4nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY } resultFlose@AY stteFlose@AY } th @ixeption eA { eFprinttkre@AY }

Allez : on complique la tche, maintenant ; regardez la gure 37.3. Ne vous faites pas exploser la cervelle tout de suite, on ne fait que commencer ! Voici un code possible an d'obtenir ce rsultat :
GGgv C rsp C y pour gnrer les imports puli lss ixoP { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY ttement stte a onnFretettement@AY

603

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES

Figure

37.3  Autre recherche

tring query a 4ivig profnomD profprenomD mtnom pyw professeur4Y query Ca 4 sxxi tysx jmtprof yx jmpprofk a profid4Y query Ca 4 sxxi tysx mtiere yx jmpmtk a mtid yhi f profnom4Y esultet result a stteFexeuteuery@queryAY tring nom a 44Y while@resultFnext@AA{ if@3nomFequls@resultFgettring@4profnom4AAA{ nom a resultFgettring@4profnom4AY ystemFoutFprintln@nom C 4 4 C resultFgettring@4profprenom4A C 4 enseigne X 4AY } ystemFoutFprintln@4ttt E 4 C resultFgettring@4mtnom4AAY } resultFlose@AY stteFlose@AY } th @ixeption eA { eFprinttkre@AY }

Allez, un dernier exemple en gure 37.4.


GGgv C rsp C y pour gnrer les imports puli lss ixoQ {

604

LE COUPLE STATEMENT  RESULTSET

Figure

37.4  Dernire ligne droite

puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY ttement stte a onnFretettement@AY tring query a 4ivig profnomD profprenomD mtnomD lsnom pyw professeur4Y query Ca 4 sxxi tysx jmtprof yx jmpprofk a profid4Y query Ca 4 sxxi tysx mtiere yx jmpmtk a mtid4Y query Ca 4 sxxi tysx jlsjmp yx jmjmpk a jmpid4Y query Ca 4 sxxi tysx lsse yx jmlsk a lsid exh lsid sx@ID UA4Y query Ca 4 yhi f lsnom higD profnom4Y esultet result a stteFexeuteuery@queryAY tring nom a 44Y tring nomglss a 44Y while@resultFnext@AA{ if@3nomglssFequls@resultFgettring@4lsnom4AAA{

605

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES


nomglss a resultFgettring@4lsnom4AY ystemFoutFprintln@4glsse de 4 C nomglss C 4 X4AY

if@3nomFequls@resultFgettring@4profnom4AAA{ nom a resultFgettring@4profnom4AY ystemFoutFprintln@4t B 4 C nom C 4 4 C resultFgettring@4profprenom4A C 4 enseigne X 4AY } ystemFoutFprintln@4ttt E 4 C resultFgettring@4mtnom4AAY

resultFlose@AY stteFlose@AY } th @ixeption eA { eFprinttkre@AY }

Statement
Vous avez vu comment obtenir un objet Statement. Mais je ne vous ai pas tout dit. . . Vous savez dj que pour rcuprer un objet Statement, vous devez le demander gentiment un objet Connection en invoquant la mthode createStatement(). Ce que vous ne savez pas, c'est que vous pouvez spcier des paramtres pour la cration de l'objet Statement. Ces paramtres permettent direntes actions lors du parcours des rsultats via l'objet ResultSet. Le premier paramtre est utile pour la lecture du jeu d'enregistrements :  TYPE_FORWARD_ONLY : le rsultat n'est consultable qu'en avanant dans les donnes renvoyes, il est donc impossible de revenir en arrire lors de la lecture ;  TYPE_SCROLL_SENSITIVE : le parcours peut se faire vers l'avant ou vers l'arrire et le curseur peut se positionner n'importe o, mais si des changements surviennent dans la base pendant la lecture, il ne seront pas visibles ;  TYPE_SCROLL_INSENSITIVE : la dirence du prcdent, les changements sont directement visibles lors du parcours des rsultats. Le second concerne la possibilit de mise jour du jeu d'enregistrements :  CONCUR_READONLY : les donnes sont consultables en lecture seule, c'est--dire que l'on ne peut modier des valeurs pour mettre la base jour ;  CONCUR_UPDATABLE : les donnes sont modiables ; lors d'une modication, la base est mise jour.

Par dfaut, les ralisables.


606

ResultSet issus d'un Statement sont de type TYPE_FORWARD_ONLY pour le parcours et CONCUR_READONLY pour les actions

LES REQUTES PRPARES Ces paramtres sont des variables statiques de la classe ResultSet, vous savez donc comment les utiliser. Voici comment crer un Statement permettant l'objet ResultSet de pouvoir tre lu d'avant en arrire avec possibilit de modication :
ttement stte a onnFretettement@esultetFigyvvsxixssiD esultetFgyxgheefviAY

Vous avez appris crer des Statement avec des paramtres, mais saviez-vous qu'il existait un autre type de Statement ?

Les requtes prpares


Il va falloir vous accrocher un tout petit peu. . . De tels objets sont crs exactement de la mme faon que des Statement classiques, sauf qu'au lieu de cette instruction :
ttement stm a onnFretettement@AY

. . . nous devons crire ceci :


repredttement stm a onnFpreprettement@4ivig B pyw lsse4AY

Jusqu'ici, rien de spcial. Cependant, une dirence est dj eective ce stade : la requte SQL est prcompile ! Cela a pour eet de rduire le temps d'excution dans le moteur SQL de la BDD. C'est normal, tant donn qu'il n'aura pas compiler la requte. En rgle gnrale, on utilise ce genre d'objet pour des requtes contenant beaucoup de paramtres ou pouvant tre excutes plusieurs fois. Il existe une autre dirence de taille entre les objets PreparedStatement et Statement : dans le premier, on peut utiliser des paramtres trous ! En fait, vous pouvez insrer un caractre spcial dans vos requtes et remplacer ce caractre grce des mthodes de l'objet PreparedStatement en spciant sa place et sa valeur (son type tant dni par la mthode utilise). Voici un exemple :
GGgv C rsp C y pour gnrer les imports puli lss repre { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y

607

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES


gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY ttement stte a onnFretettement@ esultetFigyvvsxixssiD esultetFgyxgheefviAY GGyn re l requte tring query a 4ivig profnomD profprenom pyw professeur4Y GGremier trou pour le nom du professeur query Ca 4 rii profnom a c4Y GGheuxime trou pour l9identifint du professeur query Ca 4 y profid a c4Y GGyn re l9ojet ve l requte en prmtre repredttement prepre a onnFpreprettement@queryAY GGyn remple le premier trou pr le nom du professeur prepreFsettring@ID 4wewy4AY GGyn remple le deuxime trou pr l9identifint du professeur prepreFsetsnt@PD PAY GGyn ffihe l requte exute ystemFoutFprintln@prepreFtotring@AAY GGyn modifie le premier trou prepreFsettring@ID 4yy4AY GGyn ffihe nouveu l requte exute ystemFoutFprintln@prepreFtotring@AAY GGyn modifie le deuxime trou prepreFsetsnt@PD ISWUSQAY GGyn ffihe une nouvelle fois l requte exute ystemFoutFprintln@prepreFtotring@AAY prepreFlose@AY stteFlose@AY } th @ixeption eA { eFprinttkre@AY }

Cela nous donne la gure 37.5.

Figure

37.5  Requte prpare

608

LES REQUTES PRPARES

Eectivement ; mais quelles mthodes d'aectation de valeur existe-t-il ?


C'est simple : vous vous souvenez de la liste des mthodes de l'objet ResultSet rcuprant des donnes ? Ici, elle est identique, sauf que l'on trouve setXXX() la place de getXXX(). Tout comme son homologue sans trou, cet objet peut prendre les mmes types de paramtres pour la lecture et pour la modication des donnes lues :
repredttement prepre a onnFpreprettement@ queryD esultetFigyvvsxixssiD esultetFgyxgiehyxv AY

Sachez enn qu'il existe aussi une mthode retournant un objet ResultSetMetaData : il s'agit de getMetaData(). Pour en terminer avec les mthodes de l'objet PreparedStatement que je prsente ici (il en existe d'autres), prepare.clearParameters() permet de rinitialiser la requte prpare an de retirer toutes les valeurs renseignes. Si vous ajoutez cette mthode la n du code que je vous ai prsent et que vous achez nouveau le contenu de l'objet, vous obtenez la gure 37.6.

Figure

37.6  Nettoyage des paramtres

ResultSet

: le retour

Maintenant que nous avons vu comment procder, nous allons apprendre nous promener dans nos objets ResultSet. En fait, l'objet ResultSet ore beaucoup de mthodes permettant d'explorer les rsultats, condition que vous ayez bien prpar l'objet Statement. Vous avez la possibilit de :  vous positionner avant la premire ligne de votre rsultat : res.beforeFirst() ;  savoir si vous vous trouvez avant la premire ligne : res.isBeforeFirst() ;  vous placer sur la premire ligne de votre rsultat : res.first() ;  savoir si vous vous trouvez sur la premire ligne : res.isFirst() ;  vous retrouver sur la dernire ligne : res.last() ; 609

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES        savoir si vous vous trouvez sur la dernire ligne : res.isLast() ; vous positionner aprs la dernire ligne de rsultat : res.afterLast() ; savoir si vous vous trouvez aprs la dernire ligne : res.isAfterLast() ; aller de la premire ligne la dernire : res.next() ; aller de la dernire ligne la premire : res.previous() ; vous positionner sur une ligne prcise de votre rsultat : res.absolute(5) ; vous positionner sur une ligne par rapport votre emplacement actuel : res.relative(-3). Je vous ai concoct un morceau de code que j'ai comment et qui met tout cela en uvre.
GGgv C rsp C y pour gnrer les imports puli lss esultset { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY ttement stte a onnFretettement@esultetFigyvvixssiD esultetFgyxgheefviAY tring query a 4ivig profnomD profprenom pyw professeur4Y esultet res a stteFexeuteuery@queryAY int i a IY ystemFoutFprintln@4ntEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY ystemFoutFprintln@4tvigi exhehF4AY ystemFoutFprintln@4tEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY while@resFnext@AA{ ystemFoutFprintln@4txom X 4CresFgettring@4profnom4A C4 t prnom X 4CresFgettring@4profprenom4AAY GGyn regrde si on se trouve sur l dernire ligne du rsultt if@resFisvst@AA ystemFoutFprintln@4ttB hixsi ive 3n4AY iCCY } GGne fois l leture termineD on ontrle si on se trouve ien GG l9extrieur des lignes de rsultt if@resFiseftervst@AA ystemFoutFprintln@4txous venons de terminer 3n4AY ystemFoutFprintln@4tEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY ystemFoutFprintln@4tveture en sens ontrireF4AY ystemFoutFprintln@4tEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY

610

LES REQUTES PRPARES

GGyn se trouve lors l fin GGyn peut prourir le rsultt en sens ontrire while@resFprevious@AA{ ystemFoutFprintln@4txom X 4CresFgettring@4profnom4A C4 t prnom X 4CresFgettring@4profprenom4AAY GGyn regrde si on se trouve sur l premire ligne du rsultt if@resFispirst@AA ystemFoutFprintln@4ttB iy e hif 3n4AY

GGyn regrde si on se trouve vnt l premire ligne du rsultt if@resFisfeforepirst@AA ystemFoutFprintln@4txous venons de revenir u dut 3n4AY ystemFoutFprintln@4tEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY ystemFoutFprintln@4teprs positionnement solu du urseur l ple x 4C iGP C 4F4AY ystemFoutFprintln@4tEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY GGyn positionne le urseur sur l ligne iGP GGpeu importe o on se trouve resFsolute@iGPAY while@resFnext@AA ystemFoutFprintln@4txom X 4CresFgettring@4profnom4A C4 t prnom X 4C resFgettring@4profprenom4AAY ystemFoutFprintln@4tEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY ystemFoutFprintln@4teprs positionnement reltif du urseur l ple x 4C@iE@iEPAA C 4F4AY ystemFoutFprintln@4tEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4AY GGyn ple le urseur l ligne tuelle moins iEP GGi on n9vit ps mis de signe moinsD on urit vn de iEP lignes resFreltive@E@iEPAAY while@resFnext@AA ystemFoutFprintln@4txom X 4CresFgettring@4profnom4A C4 t prnom X 4CresFgettring@4profprenom4AAY resFlose@AY stteFlose@AY } th @ixeption eA { eFprinttkre@AY }

La gure 37.7 montre le rsultat obtenu. Il est trs important de noter l'endroit o vous vous situez dans le parcours de la requte ! 611

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES

Figure

37.7  Utilisation d'un ResultSet

612

MODIFIER DES DONNES

Il existe des emplacements particuliers. Par exemple, si vous n'tes pas encore positionns sur le premier lment et que vous procdez un rs.relative(1), vous vous retrouvez sur le premier lment. De mme, un rs.absolute(0) correspond un rs.beforeFirst().
Ce qui signie que lorsque vous souhaitez placer le curseur sur la premire ligne, vous devez utiliser absolute(1) quel que soit l'endroit o vous vous trouvez ! En revanche, cela ncessite que le ResultSet soit de type TYPE_SCROLL_SENSITIVE ou TYPE_SCROLL_INSENSITIVE , sans quoi vous aurez une exception.

Modier des donnes


Pendant la lecture, vous pouvez utiliser des mthodes qui ressemblent celles que je vous ai dj prsentes lors du parcours d'un rsultat. Souvenez-vous des mthodes de ce type :  res.getAscii() ;  res.getBytes() ;  res.getInt() ;  res.getString() ;  etc. Ici, vous devez remplacer getXXX() par updateXXX(). Ces mthodes de mise jour des donnes prennent deux paramtres :  le nom de la colonne (String) ;  la valeur attribuer la place de la valeur existante (cela dpend de la mthode utilise).

Comment a,  cela dpend de la mthode utilise  ?


C'est simple :  updateFloat(String nomColonne, float value) prend un float en paramtre ;  updateString(String nomColonne, String value) prend une chane de caractres en paramtre ;  et ainsi de suite. Changer la valeur d'un champ est donc trs facile. Cependant, il faut, en plus de changer les valeurs, valider ces changements pour qu'ils soient eectifs : cela se fait par la mthode updateRow(). De la mme manire, vous pouvez annuler des changements grce la mthode cancelRowUpdates(). Sachez que si vous devez annuler des modications, vous devez le faire avant la mthode de validation, sinon l'annulation sera ignore. Je vous propose d'tudier un petit exemple de mise jour : 613

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES


GGgv C rsp C y pour gnrer les imports puli lss wodif { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY GGyn utorise l mise jour des donnes GGet l mise jour de l9ffihge ttement stte a onnFretettement@ esultetFigyvvsxixssiD esultetFgyxgheefviAY GGyn v herher une ligne dns l se de donnes tring query a 4ivig profidD profnomD profprenom pyw professeur 4 C 4rii profnom a 9wewy94Y esultet res a stteFexeuteuery@queryAY resFfirst@AY GGyn ffihe e que l9on trouve ystemFoutFprintln@4xyw X 4 C resFgettring@4profnom4A C 4 4 E ixyw X C resFgettring@4profprenom4AAY GGyn met jour les hmps resFupdtetring@4profnom4D 4gyiv4AY resFupdtetring@4profprenom4D 4engelo4AY GGyn vlide resFupdteow@AY GGyn ffihe les modifitions ystemFoutFprintln@4BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY ystemFoutFprintln@4ei wyhspsgesyx X 4AY ystemFoutFprintln@4txyw X 4 C resFgettring@4profnom4A C 4 E ixyw X 4 C resFgettring@4profprenom4A C 4n4AY GGyn remet les informtions de dprt resFupdtetring@4profnom4D 4wewy4AY resFupdtetring@4profprenom4D 4hniel4AY GGyn vlide nouveu resFupdteow@AY GGit voil 3 ystemFoutFprintln@4BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB4AY ystemFoutFprintln@4ei iwyhspsgesyx X 4AY ystemFoutFprintln@4txyw X 4 C resFgettring@4profnom4A C 4 E ixyw X 4 C resFgettring@4profprenom4A C 4n4AY

614

STATEMENT, TOUJOURS PLUS FORT


resFlose@AY stteFlose@AY } th @ixeption eA { eFprinttkre@AY }

La gure 37.8 reprsente ce que nous obtenons.

Figure

37.8  Mise jour d'une ligne pendant la lecture

En quelques instants, les donnes ont t modies dans la base de donnes, nous avons donc russi relever le d ! Nous allons voir comment excuter les autres types de requtes avec Java.

Statement ,

toujours plus fort

Vous savez depuis quelque temps dj que ce sont les objets Statement qui sont chargs d'excuter les instructions SQL. Par consquent, vous devez avoir devin que les requtes de type INSERT, UPDATE, DELETE et CREATE sont galement excutes par ces objets. Voici un code d'exemple :
GGgv C rsp C y pour gnrer les imports puli lss tte { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY GGyn utorise l mise jour des donnes

615

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES


GGet l mise jour de l9ffihge ttement stte a onnFretettement@ esultetFigyvvixssiDesultetFgyxgheefviAY repredttement prepre a onnFpreprettement@ 4hei professeur set profprenom a c 4C 4rii profnom a 9wewy94AY GGyn v herher une ligne dns l se de donnes tring query a 4ivig profnomD profprenom pyw professeur 4C 4rii profnom a9wewy94Y GGyn exute l requte esultet res a stteFexeuteuery@queryAY resFfirst@AY GGyn ffihe ystemFoutFprintln@4nthyxxii h9ysqsxi X 4AY ystemFoutFprintln@4tEEEEEEEEEEEEEEEEEEE4AY ystemFoutFprintln@4txyw X 4 C resFgettring@4profnom4A C 4 E ixyw X 4 C resFgettring@4profprenom4AAY GGyn prmtre notre requte prpre prepreFsettring@ID 4qrrd4AY GGyn exute prepreFexeutepdte@AY res a stteFexeuteuery@queryAY resFfirst@AY GGyn ffihe nouveu ystemFoutFprintln@4ntt ei wet X 4AY ystemFoutFprintln@4tt B xyw X 4 C resFgettring@4profnom4A C 4 E ixyw X4 C resFgettring@4profprenom4AAY GGyn effetue une mise jour prepreFsettring@ID 4hniel4AY prepreFexeutepdte@AY res a stteFexeuteuery@queryAY resFfirst@AY GGyn ffihe une nouvelle fois ystemFoutFprintln@4ntt iwsi e iy X 4AY ystemFoutFprintln@4tt B xyw X 4 C resFgettring@4profnom4A C 4 E ixyw X4 C resFgettring@4profprenom4AAY prepreFlose@AY resFlose@AY stteFlose@AY } th @glssxotpoundixeption eA { eFprinttkre@AY } th @vixeption eA { eFprinttkre@AY

616

GRER LES TRANSACTIONS MANUELLEMENT


}

Cela correspond la gure 37.9.

Figure

37.9  Mise jour des donnes

Ici, nous avons utilis un PreparedStatement pour compliquer immdiatement, mais nous aurions tout aussi bien pu utiliser un simple Statement et invoquer la mthode executeUpdate(String query) . Vous savez quoi ? Pour les autres types de requtes, il sut d'invoquer la mme mthode que pour la mise jour. En fait, celle-ci retourne un boolen indiquant si le traitement a russi ou chou. Voici quelques exemples :
stteFexeutepdte@4sxi sxy professeur @profnomD profprenomA evi@9evwyx9D 9hyln9A4AY stteFexeutepdte@4hivii pyw professeur rii profnom a 9wewy94AY

Grer les transactions manuellement


Je ne sais pas si vous tes au courant, mais certains moteurs SQL comme PostgreSQL vous proposent de grer vos requtes SQL grce ce que l'on appelle des transactions. Par o commencer ? Lorsque vous insrez, modiez ou supprimez des donnes dans PostgreSQL, il se produit un vnement automatique : la validation des modications par le moteur SQL. C'est aussi simple que a. . . Voici un petit schma en gure 37.10 pour que vous visualisiez cela. Lorsque vous excutez une requte de type INSERT, CREATE, UPDATE ou DELETE, le type de cette requte modie les donnes prsentes dans la base. Une fois qu'elle est excute, le moteur SQL valide directement ces modications ! Cependant, vous pouvez avoir la main sur ce point (gure 37.11). Comme cela, c'est vous qui avez le contrle sur vos donnes an de matriser l'intgrit de vos donnes. Imaginez que vous deviez excuter deux requtes, une modication et 617

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES

Figure

37.10  Validation automatique d'une transaction

Figure

37.11  Gestion manuelle des transactions

une insertion, et que vous partiez du principe que l'insertion dpend de la mise jour. . . Comment feriez-vous si de mauvaises donnes taient mises jour ? L'insertion qui en dcoule serait mauvaise. Cela, bien sr, si le moteur SQL valide automatiquement les requtes excutes. Pour grer manuellement les transactions, on spcie au moteur SQL de ne pas valider automatiquement les requtes SQL grce une mthode (qui ne concernera toutefois pas l'objet Statement, mais l'objet Connection) prenant un boolen en paramtre :
GGgv C rsp C y pour gnrer les imports puli lss rnst { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4tterie4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY onnFseteutogommit@flseAY } th @ixeption eA { eFprinttkre@AY }

618

GRER LES TRANSACTIONS MANUELLEMENT Lorsque vous souhaitez que vos requtes soient prises en compte, il vous faut les valider en utilisant la mthode conn.commit().

En mode setAutoCommit(false), si vous ne validez pas vos requtes, elles ne seront pas prises en compte.
Vous pouvez revenir tout moment au mode de validation automatique grce setAutoCommit(true) . Voici un exemple :
GGgv C rsp C y pour gnrer les imports puli lss rnst { puli stti void min@tring rgsA { try { glssFforxme@4orgFpostgresqlFhriver4AY tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4tterie4Y gonnetion onn a hriverwngerFgetgonnetion@urlD userD psswdAY onnFseteutogommit@flseAY ttement stte a onnFretettement@esultetFigyvvixssiD esultetFgyxgheefviAY tring query a 4hei professeur i profprenom a 9gyrille9 4C 4rii profnom a 9wewy94Y esultet result a stteFexeuteuery@4ivig B pyw professeur4C 4 rii profnom a 9wewy94AY resultFfirst@AY ystemFoutFprintln@4xyw X 4 C resultFgettring@4profnom4A C 4 E ixyw X 4 C resultFgettring@4profprenom4AAY stteFexeutepdte@queryAY result a stteFexeuteuery@ 4ivig B pyw professeur rii profnom a 9wewy94AY resultFfirst@AY ystemFoutFprintln@4xyw X 4 C resultFgettring@4profnom4A C 4 E ixyw X 4 C resultFgettring@4profprenom4AAY resultFlose@AY stteFlose@AY } th @ixeption eA { eFprinttkre@AY }

619

CHAPITRE 37. FOUILLER DANS SA BASE DE DONNES


}

Vous pouvez excuter ce code autant de fois que vous voulez, vous obtiendrez toujours la mme chose que sur la gure 37.12.

Figure

37.12  Transaction manuelle

Vous voyez que malgr sa prsence, la requte de mise jour est inoprante. Vous pouvez voir les modications lors de l'excution du script, mais tant donn que vous ne les avez pas valides, elles sont annules la n du code. Pour que la mise jour soit eective, il faudrait eectuer un conn.commit() avant la n du script.

En rsum
        Les recherches se font via les objets Statement et ResultSet. L'objet Statement stocke et excute la requte SQL. L'objet ResultSet, lui, stocke les lignes rsultant de l'excution de la requte. Il existe des objets ResultSetMetaData et DataBaseMetaData donnant accs des informations globales sur une requte (le premier) ou une base de donnes (pour le second). Il existe un autre objet qui fonctionne de la mme manire que l'objet ResultSet, mais qui prcompile la requte et permet d'utiliser un systme de requte trous : l'objet PreparedStatement. Avec un ResultSet autorisant l'dition des lignes, vous pouvez invoquer la mthode updateXXX() suivie de la mthode updateRow(). Pour la mise jour, la cration ou la suppression de donnes, vous pouvez utiliser la mthode executeUpdate(String query) . En utilisant les transactions manuelles, toute instruction non valide par la mthode commit() de l'objet Connection est annule.

620

Chapitre

38
Dicult :

Limiter le nombre de connexions

ous savez dsormais comment vous connecter une BDD depuis Java. Je vous ai montr comment lire et modier des donnes. Aprs vous avoir fait dcouvrir tout cela, je me suis dit que montrer une approche un peu plus objet ne serait pas du luxe. C'est vrai, tablir sans arrt la connexion notre base de donnes commence tre fastidieux. Je vous propose donc d'y remdier avec ce chapitre en dcouvrant le pattern singleton.

621

CHAPITRE 38. LIMITER LE NOMBRE DE CONNEXIONS

Pourquoi ne se connecter qu'une seule fois ?


Pourquoi veux-tu absolument qu'on ait une seule instance de notre objet Connection ?
Parce que cela ne sert pas grand-chose de rinitialiser la connexion votre BDD. Rappelez-vous que la connexion sert tablir le pont entre votre base et votre application. Pourquoi voulez-vous que votre application se connecte chaque fois la BDD ? Une fois la connexion eective, pourquoi vouloir l'tablir de nouveau ? Votre application et votre BDD peuvent discuter !

Bon, c'est vrai qu'avec du recul, cela parat superu. . . Du coup, comment fais-tu pour garantir qu'une seule instance de Connection existe dans l'application ?
C'est ici que le pattern singleton intervient ! Ce pattern est peut-tre l'un des plus simples comprendre mme, s'il contient un point qui va vous faire bondir. Le principe de base de ce pattern est d'interdire l'instanciation d'une classe, grce un constructeur dclar private.

Le pattern singleton
Nous voulons qu'il soit impossible de crer plus d'un objet de connexion. Voici une classe qui permet de s'assurer que c'est le cas :
GGgv C rsp C y pour gnrer les imports puli lss dzgonnetion{ GGv de onnexion privte tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y GGxom du user privte tring user a 4postgres4Y GGwot de psse de l9utilisteur privte tring psswd a 4postgres4Y GGyjet gonnetion privte stti gonnetion onnetY GGgonstruteur priv privte dzgonnetion@A{ try { onnet a hriverwngerFgetgonnetion@urlD userD psswdAY } th @vixeption eA { eFprinttkre@AY }

622

LE PATTERN SINGLETON
} GGwthode qui v nous retourner notre instne GGet l rer si elle n9existe ps puli stti gonnetion getsnstne@A{ if@onnet aa nullA{ new dzgonnetion@AY } return onnetY }

Nous avons ici une classe avec un constructeur priv : du coup, impossible d'instancier cet objet et d'accder ses attributs, puisqu'ils sont dclars private ! Notre objet Connection est instanci dans le constructeur priv et la seule mthode accessible depuis l'extrieur de la classe est getInstance(). C'est donc cette mthode qui a pour rle de crer la connexion si elle n'existe pas, et seulement dans ce cas. Pour en tre bien srs, nous allons faire un petit test. . . Voici le code un peu modi de la mthode getInstance().
puli stti gonnetion getsnstne@A{ if@onnet aa nullA{ new dzgonnetion@AY ystemFoutFprintln@4sxexgsesyx hi ve gyxxisyx v 3 4AY } else{ ystemFoutFprintln@4gyxxisyx v isexi 3 4AY } return onnetY }

Cela nous montre quand la connexion est rellement cre. Ensuite, il ne nous manque plus qu'un code de test. Oh ! Ben a alors ! J'en ai un sous la main :
GGgv C rsp C y pour gnrer les imports puli lss est { puli stti void min@tring rgsA { try { GGxous ppelons qutre fois l mthode getsnstne@A repredttement prepre a dzgonnetionFgetsnstne@A Fpreprettement@4ivig B pyw lsse rii lsnom a c4AY ttement stte a dzgonnetionFgetsnstne@AFretettement@AY dzgonnetionFgetsnstne@AFseteutogommit@flseAY

623

CHAPITRE 38. LIMITER LE NOMBRE DE CONNEXIONS

htsewetht met a dzgonnetionFgetsnstne@AFgetwetht@AY } th @vixeption eA { eFprinttkre@AY }

La mthode en question est appele quatre fois. Que croyez-vous que ce code va acher (voir la gure 38.1) ?

Figure

38.1  Utilisation d'un singleton

Vous avez la preuve que l'instanciation ne se fait qu'une seule fois et donc que notre connexion la BDD est unique ! La classe SdzConnection peut tre un peu simplie :
GGgv C rsp C y pour gnrer les imports puli lss dzgonnetion{ privte privte privte privte stti stti stti stti tring url a 4jdXpostgresqlXGGlolhostXSRQPGiole4Y tring user a 4postgres4Y tring psswd a 4postgres4Y gonnetion onnetY

puli stti gonnetion getsnstne@A{ if@onnet aa nullA{ try { onnet a hriverwngerFgetgonnetion@urlD userD psswdAY } th @vixeption eA { eFprinttkre@AY } } return onnetY }

Attention toutefois, vous devrez rajouter la dclaration static vos paramtres de connexion. Vous pouvez relancer le code de test, vous verrez qu'il fonctionne toujours ! J'avais commenc par insrer un constructeur priv car vous deviez savoir que cela existait, mais remarquez que c'tait superu dans notre cas. . . 624

LE SINGLETON DANS TOUS SES TATS Par contre, dans une application multithreads, pour tre srs d'viter les conits, il vous sut de synchroniser la mthode getInstance() et le tour est jou. Mais  parce qu'il y a un mais  cette mthode ne rgle le problme qu' avant l'instanciation de la connexion. Autrement dit, une fois la connexion instancie, la synchronisation ne sert plus rien. Le problme du multithreading ne se pose pas vraiment pour une connexion une BDD puisque ce singleton sert surtout de passerelle entre votre BDD et votre application. Cependant, il peut exister d'autres objets que des connexions SQL qui ne doivent tre instancis qu'une fois ; tous ne sont pas aussi laxistes concernant le multithreading. Voyons donc comment parfaire ce pattern avec un exemple autre qu'une connexion SQL.

Le singleton dans tous ses tats


Nous allons travailler avec un autre exemple et vu que j'tais trs inspir, revoici notre superbe singleton :
puli lss dzingleton { GGve singleton privte stti dzingleton singleY GGrile d9instne privte tring nme a 44Y GGgonstruteur priv privte dzingleton@A{ thisFnme a 4won singleton4Y ystemFoutFprintln@4ttgesyx hi v9sxexgi 3 3 34AY } GGwthode d9s u singleton puli stti dzingleton getsnstne@A{ if@single aa nullA single a new dzingleton@AY } return singleY

GGeesseur puli tring getxme@A{ return thisFnmeY }

Ce n'est pas que je manquais d'inspiration, c'est juste qu'avec une classe toute simple, on comprend mieux les choses. . . Et voici notre classe de test : 625

CHAPITRE 38. LIMITER LE NOMBRE DE CONNEXIONS


puli lss estingleton { puli stti void min@tring rgsA { for@int i a IY i ` RY iCCA ystemFoutFprintln@4eppel x 4 C i C 4 X 4 C dzingletonFgetsnstne@AFgetxme@AAY }

Cela nous donne la gure 38.2.

Figure

38.2  Un petit singleton

La politique du singleton est toujours bonne. Mais je vais vous poser une question : quand croyez-vous que la cration d'une instance soit la plus judicieuse ? Ici, nous avons excut notre code et l'instance a t cre lorsqu'on l'a demande pour la premire fois ! C'est le principal problme que posent le singleton et le multithreading : la premire instance. . . Une fois celle-ci cre, les problmes se font plus rares. Pour limiter les ennuis, nous allons donc laisser cette lourde tche la JVM, ds le chargement de la classe, en instanciant notre singleton lors de sa dclaration :
puli lss dzingleton { GGve singleton privte stti dzingleton single a new dzingleton@AY GGrile d9instne privte tring nme a 44Y GGgonstruteur priv privte dzingleton@A{ thisFnme a 4won singleton4Y ystemFoutFprintln@4ttgesyx hi v9sxexgi 3 3 34AY } GGwthode d9s u singleton puli stti dzingleton getsnstne@A{ if@single aa nullA single a new dzingleton@AY } return singleY

GGeesseur

626

LE SINGLETON DANS TOUS SES TATS


puli tring getxme@A{ return thisFnmeY }

Avec ce code, c'est la machine virtuelle qui s'occupe de charger l'instance du singleton, bien avant que n'importe quel thread vienne taquiner la mthode getInstance(). . . Il existe une autre mthode permettant de faire cela, mais elle ne fonctionne parfaitement que depuis le JDK 1.5. On appelle cette mthode  le verrouillage double vrication . Elle consiste utiliser le mot cl volatile combin au mot cl synchronized. Pour les lecteurs qui l'ignorent, dclarer une variable volatile permet d'assurer un accs ordonn des threads une variable (plusieurs threads peuvent accder cette variable), marquant ainsi le premier point de verrouillage. Ensuite, la double vrication s'eectue dans la mthode getInstance() : on eectue la synchronisation uniquement lorsque le singleton n'est pas cr. Voici ce que cela nous donne :
puli lss dzingleton { privte voltile stti dzingleton singleY privte tring nme a 44Y privte dzingleton@A{ thisFnme a 4won singleton4Y ystemFoutFprintln@4nttgesyx hi v9sxexgi 3 3 34AY } puli stti dzingleton getsnstne@A{ if@single aa nullA{ synhronized@dzingletonFlssA{ if@single aa nullA single a new dzingleton@AY } } return singleY } puli tring getxme@A{ return thisFnmeY }

En rsum
 Pour conomiser les ressources, vous ne devriez crer qu'un seul objet de connexion.  Le pattern singleton permet de disposer d'une instance unique d'un objet.  Ce pattern repose sur un constructeur priv associ une mthode retournant l'instance cre dans la classe elle-mme. 627

CHAPITRE 38. LIMITER LE NOMBRE DE CONNEXIONS  An de pallier au problme du multithreading, il vous sut d'utiliser le mot cl synchronized dans la dclaration de votre mthode de rcupration de l'instance, mais cette synchronisation n'est utile qu'une fois. la place, vous pouvez instancier l'objet au chargement de la classe par la JVM, avant tout appel celle-ci.

628

Chapitre

39
Dicult :

TP : un testeur de requtes

ous avez appris un tas de choses sur JDBC et il est grand temps que vous les mettiez en pratique ! Dans ce TP, je vais vous demander de raliser un testeur de requtes SQL. Vous ne voyez pas o je veux en venir ? Lisez donc la suite. . .

629

CHAPITRE 39. TP : UN TESTEUR DE REQUTES

Cahier des charges


Voici ce que j'attends de vous :  crer une IHM permettant la saisie d'une requte SQL dans un champ ;  lancer l'excution de la requte grce un bouton se trouvant dans une barre d'outils ;  si la requte renvoie 0 ou plusieurs rsultats, les acher dans un JTable ;  le nom des colonnes devra tre visible ;  en cas d'erreur, un pop-up ( JOptionPane) contenant le message s'achera ;  un petit message en bas de fentre achera le temps d'excution de la requte ainsi que le nombre de lignes retournes. Voil : vous avez de quoi faire ! Si vous ne savez pas comment procder pour le temps d'excution de la requte, voici un indice : System.currentTimeMillis() retourne un long. . .

Quelques captures d'cran


Les gures 39.1, 39.2 et 39.3 vous montrent ce que j'ai obtenu avec mon code. Inspirezvous-en pour raliser votre programme.

Figure

39.1  Au lancement

Je n'ai plus qu' vous souhaiter bonne chance et bon courage ! Let's go !

Correction
Pour la correction du TP, je vous invite utiliser le code web suivant. Copier la correction Code web : 962726  630


CORRECTION

Figure

39.2  Excution d'une requte

Figure

39.3  Erreur dans une requte

Bien sr, ce code n'est pas parfait, vous pouvez l'amliorer ! Voil d'ailleurs quelques pistes :  vous pouvez utiliser un autre composant que moi pour la saisie de la requte, par exemple un JTextPane pour la coloration syntaxique ;  vous pouvez galement crer un menu qui vous permettra de sauvegarder vos requtes ;  vous pouvez galement crer un tableau interactif autorisant la modication des donnes. Bref, ce ne sont pas les amliorations qui manquent !

631

CHAPITRE 39. TP : UN TESTEUR DE REQUTES

632

Chapitre

40
Dicult :

Lier ses tables avec des objets Java : le pattern DAO

ous voulez utiliser vos donnes dans des objets, et c'est normal ! Vous avez sans doute essay de faire en sorte que les donnes de votre base collent vos objets, l'aide des mthodes de rcupration, de cration, de mise jour et (ou) de suppression, sans obtenir le rsultat escompt. Avec le pattern DAO 1 , vous allez voir comment procder et surtout, comment rendre le tout stable !

1. Data Access Object.

633

CHAPITRE 40. LIER SES TABLES AVEC DES OBJETS JAVA : LE PATTERN DAO

Avant toute chose


Vous voulez que les donnes de la base puissent tre utilises via des objets Java. En tout premier lieu, il faut crer une classe par entit (les tables, exceptes celles de jointure), ce qui nous donnerait les classes suivantes :  Eleve ;  Matiere ;  Professeur ;  Classe. Et, si nous suivons la logique des relations entre nos tables, nos classes sont lies suivant le diagramme de classes correspondant la gure 40.1.

Figure

40.1  Diagramme de classe de notre BDD

Grce ce diagramme, nous voyons les liens entre les objets : une classe est compose de plusieurs lves et de plusieurs professeurs, et un professeur peut exercer plusieurs matires. Les tables de jointures de la base sont symbolises par la composition

dans nos objets.

Une fois que cela est fait, nous devons coder ces objets avec les accesseurs et les mutateurs adquats :  getters et setters pour tous les attributs de toutes les classes ;  mthodes d'ajout et de suppression pour les objets constitus de listes d'objets. On appelle ce genre d'objet des POJO, pour Plain Old Java Object ! Ce qui nous donne ces codes source :

Classe Eleve.java
pkge omFsdzFenY puli lss ileve {

634

AVANT TOUTE CHOSE


GGsh privte int id a HY GGxom de l9lve privte tring nom a 44Y GGrnom de l9lve privte tring prenom a 44Y puli ileve@int idD tring nomD tring prenomA { thisFid a idY thisFnom a nomY thisFprenom a prenomY } puli ileve@A{}Y puli int getsd@A { return idY } puli void setsd@int idA { thisFid a idY } puli tring getxom@A { return nomY } puli void setxom@tring nomA { thisFnom a nomY } puli tring getrenom@A { return prenomY } puli void setrenom@tring prenomA { thisFprenom a prenomY }

Classe Matiere.java
pkge omFsdzFenY puli lss wtiere { GGsh privte int id a HY GGxom du professeur privte tring nom a 44Y

635

CHAPITRE 40. LIER SES TABLES AVEC DES OBJETS JAVA : LE PATTERN DAO
puli wtiere@int idD tring nomA { thisFid a idY thisFnom a nomY } puli wtiere@A{} puli int getsd@A { return idY } puli void setsd@int idA { thisFid a idY } puli tring getxom@A { return nomY } puli void setxom@tring nomA { thisFnom a nomY }

Classe Professeur.java
pkge omFsdzFenY import jvFutilFrshetY import jvFutilFetY puli lss rofesseur { GGsh privte int id a HY GGxom du professeur privte tring nom a 44Y GGrnom du professeur privte tring prenom a 44Y GGviste des mtires dispenses privte et`wtiereb listwtiere a new rshet`wtiereb@AY puli rofesseur@int idD tring nomD tring prenomA { thisFid a idY thisFnom a nomY thisFprenom a prenomY }

636

AVANT TOUTE CHOSE


puli rofesseur@A{} puli int getsd@A { return idY } puli void setsd@int idA { thisFid a idY } puli tring getxom@A { return nomY } puli void setxom@tring nomA { thisFnom a nomY } puli tring getrenom@A { return prenomY } puli void setrenom@tring prenomA { thisFprenom a prenomY } puli et`wtiereb getvistwtiere@A { return listwtiereY } puli void setvistwtiere@et`wtiereb listwtiereA { thisFlistwtiere a listwtiereY } GGejoute une mtire un professeur puli void ddwtiere@wtiere mtiereA{ thisFlistwtiereFdd@mtiereAY } GGetire une mtire un professeur puli void removewtiere@wtiere mtiereA{ thisFlistwtiereFremove@mtiereAY } }

637

CHAPITRE 40. LIER SES TABLES AVEC DES OBJETS JAVA : LE PATTERN DAO

Classe Classe.java
pkge omFsdzFenY GGgv C rsp C y pour gnrer les imports puli lss glsse { GGsh privte int id a HY GGxom du professeur privte tring nom a 44Y GGviste des professeurs privte et`rofesseurb listrofesseur a new rshet`rofesseurb@AY GGviste des lves privte et`ileveb listileve a new rshet`ileveb@AY puli glsse@int idD tring nomA { thisFid a idY thisFnom a nomY } puli glsse@A{} puli int getsd@A { return idY } puli void setsd@int idA { thisFid a idY } puli tring getxom@A { return nomY } puli void setxom@tring nomA { thisFnom a nomY } puli et`rofesseurb getvistrofesseur@A { return listrofesseurY } puli void setvistrofesseur@et`rofesseurb listrofesseurA { thisFlistrofesseur a listrofesseurY } puli void ddrofesseur@rofesseur profA { if@3listrofesseurFontins@profAA listrofesseurFdd@profAY }

638

LE PATTERN DAO

puli void removerofesseur@rofesseur prof A { thisFlistrofesseurFremove@profAY } puli et`ileveb getvistileve@A { return listileveY } puli void setvistileve@et`ileveb listileveA { thisFlistileve a listileveY } GGejoute un lve l lsse puli void ddileve@ileve eleveA{ if@3thisFlistileveFontins@eleveAA thisFlistileveFdd@eleveAY } GGetire un lve de l lsse puli void removeileve@ileve eleveA{ thisFlistileveFremove@eleveAY } puli oolen equls@glsse lsA{ return thisFgetsd@A aa lsFgetsd@AY }

Nous avons des objets prts l'emploi. Maintenant, comment faire en sorte que ces objets puissent recevoir les donnes de notre base ? Au lieu de faire des essais ttons, nous allons dnir le pattern DAO et voir comment il fonctionne avant de l'implmenter.

Le pattern DAO
Contexte
Vous disposez de donnes srialises dans une base de donnes et vous souhaitez les manipuler avec des objets Java. Cependant, votre entreprise est en pleine restructuration et vous ne savez pas si vos donnes vont :  rester o elles sont ;  migrer sur une autre base de donnes ;  tre stockes dans des chiers XML ;  ... Comment faire en sorte de ne pas avoir modier toutes les utilisations de nos objets ? Comment raliser un systme qui pourrait s'adapter aux futures modications 639

CHAPITRE 40. LIER SES TABLES AVEC DES OBJETS JAVA : LE PATTERN DAO de supports de donnes ? Comment procder an que les objets que nous allons utiliser restent tels qu'ils sont ?

Le pattern DAO
Ce pattern permet de faire le lien entre la couche d'accs aux donnes et la couche mtier d'une application (vos classes). Il permet de mieux matriser les changements susceptibles d'tre oprs sur le systme de stockage des donnes ; donc, par extension, de prparer une migration d'un systme un autre (BDD vers chiers XML, par exemple. . .). Ceci se fait en sparant accs aux donnes (BDD) et objets mtiers (POJO). Je me doute que tout ceci doit vous sembler trs ou. C'est normal, mais ne vous en faites pas, je vais tout vous expliquer. . . Dj, il y a cette histoire de sparation des couches mtier et des couches d'accs aux donnes. Il s'agit ni plus ni moins de faire en sorte qu'un type d'objet se charge de rcuprer les donnes dans la base et qu'un autre type d'objet (souvent des POJO) soit utilis pour manipuler ces donnes. Schmatiquement, a nous donne la gure 40.2. Les objets que nous avons crs plus haut sont nos POJO, les objets utiliss par le programme pour manipuler les donnes de la base. Les objets qui iront chercher les donnes en base devront tre capables d'eectuer des recherches, des insertions, des mises jour et des suppressions ! Par consquent, nous pouvons dnir un super type d'objet an d'utiliser au mieux le polymorphisme. . . Nous allons devoir crer une classe abstraite (ou une interface) mettant en uvre toutes les mthodes sus-mentionnes.

Comment faire pour demander nos objets DAO de rcuprer tel type d'objet ou de srialiser tel autre ? Avec des cast ?
Soit avec des cast, soit en crant une classe gnrique (gure 40.3) !

Classe DAO.java
pkge omFsdzFdoY import jvFsqlFgonnetionY import omFsdzFonnetionFdzgonnetionY puli strt lss hey`b { proteted gonnetion onnet a nullY puli hey@gonnetion onnA{ thisFonnet a onnY }

640

LE PATTERN DAO

Figure

40.2  Fonctionnement du pattern DAO

Figure

40.3  Classe DAO 641

CHAPITRE 40. LIER SES TABLES AVEC DES OBJETS JAVA : LE PATTERN DAO
GBB B wthode de rtion B dprm oj B dreturn oolen BG puli strt oolen rete@ ojAY GBB B wthode pour effer B dprm oj B dreturn oolen BG puli strt oolen delete@ ojAY GBB B wthode de mise jour B dprm oj B dreturn oolen BG puli strt oolen updte@ ojAY GBB B wthode de reherhe des informtions B dprm id B dreturn BG puli strt find@int idAY

Classe EleveDAO.java
pkge omFsdzFdoFimplementY GGgv C rsp C y pour gnrer les imports puli lss ilevehey extends hey`ileveb { puli ilevehey@gonnetion onnA { super@onnAY } puli oolen rete@ileve ojA { return flseY } puli oolen delete@ileve ojA { return flseY } puli oolen updte@ileve ojA { return flseY } puli ileve find@int idA {

642

LE PATTERN DAO

ileve eleve a new ileve@AY try { esultet result a thisFonnetFretettement@ esultetFigyvvsxixssiD esultetFgyxgiehyxv AFexeuteuery@ 4ivig B pyw eleve rii elvid a 4 C id AY if@resultFfirst@AA eleve a new ileve@idD resultFgettring@4elvnom4AD resultFgettring@4elvprenom4AAY } th @vixeption eA { eFprinttkre@AY } return eleveY

Classe MatiereDAO.java
pkge omFsdzFdoFimplementY GGgv C rsp C y pour gnrer les imports puli lss wtierehey extends hey`wtiereb { puli wtierehey@gonnetion onnA { super@onnAY } puli oolen rete@wtiere ojA { return flseY } puli oolen delete@wtiere ojA { return flseY } puli oolen updte@wtiere ojA { return flseY } puli wtiere find@int idA { wtiere mtiere a new wtiere@AY try { esultet result a thisFonnetFretettement@

643

CHAPITRE 40. LIER SES TABLES AVEC DES OBJETS JAVA : LE PATTERN DAO
esultetFigyvvsxixssiD esultetFgyxgiehyxv AFexeuteuery@ 4ivig B pyw mtiere rii mtid a 4 C id AY if@resultFfirst@AA mtiere a new wtiere@idD resultFgettring@4mtnom4AAY } th @vixeption eA { eFprinttkre@AY } return mtiereY

Classe ProfesseurDAO.java
pkge omFsdzFdoFimplementY GGgv C rsp C y pour gnrer les imports puli lss rofesseurhey extends hey`rofesseurb { puli rofesseurhey@gonnetion onnA { super@onnAY } puli oolen rete@rofesseur ojA { return flseY } puli oolen delete@rofesseur ojA { return flseY } puli oolen updte@rofesseur ojA { return flseY } puli rofesseur find@int idA { rofesseur professeur a new rofesseur@AY try { esultet result a thisFonnetFretettement@ esultetFigyvvsxixssiD esultetFgyxgiehyxv AFexeuteuery@ 4ivig B pyw professeur 4C 4vip tysx jmtprof yx jmpprofk a profid 4 C 4exh profid a 4C id C 4 sxxi tysx mtiere yx jmpmtk a mtid4 AY

644

LE PATTERN DAO
if@resultFfirst@AA{ professeur a new rofesseur@idD resultFgettring@4profnom4AD resultFgettring@4profprenom4A AY resultFeforepirst@AY wtierehey mtho a new wtierehey@thisFonnetAY while@resultFnext@AA professeurFddwtiere@mthoFfind@resultFgetsnt@4mtid4AAAY

} } th @vixeption eA { eFprinttkre@AY } return professeurY

puli oolen updte@rofesseur ojA { return flseY }

Classe ClasseDAO.java
pkge omFsdzFdoFimplementY GGgv C rsp C y pour gnrer les imports puli lss glssehey extends hey`glsseb { puli glssehey@gonnetion onnA { super@onnAY } puli oolen rete@glsse ojA { return flseY } puli oolen delete@glsse ojA { return flseY } puli oolen updte@glsse ojA { return flseY } puli glsse find@int idA { glsse lsse a new glsse@AY try { esultet result a thisFonnetFretettement@

645

CHAPITRE 40. LIER SES TABLES AVEC DES OBJETS JAVA : LE PATTERN DAO
esultetFigyvvsxixssiD esultetFgyxgiehyxv AFexeuteuery@ 4ivig B pyw lsse rii lsid a 4 C id AY if@resultFfirst@AA{ lsse a new glsse@idD resultFgettring@4lsnom4AAY result a thisFonnetFretettement@A Fexeuteuery@ 4ivig profidD profnomD profprenom from professeur 4 C 4sxxi tysx jmtprof yx profid a jmpprofk 4 C 4sxxi tysx jlsjmp yx jmpid a jmjmpk exh jmlsk a 4 C id AY rofesseurhey profho a new rofesseurhey@thisFonnetAY while@resultFnext@AA lsseFddrofesseur@profhoFfind@resultFgetsnt@4profid4AAAY ilevehey eleveho a new ilevehey@thisFonnetAY result a thisFonnetFretettement@AFexeuteuery@ 4ivig elvidD elvnomD elvprenom pyw eleve 4 C 4sxxi tysx lsse yx elvlsk a lsid exh lsid a 4 C id AY while@resultFnext@AA lsseFddileve@elevehoFfind@resultFgetsnt@4elvid4AAAY

} th @vixeption eA { eFprinttkre@AY } return lsseY

Pour ne pas compliquer la tche, je n'ai dtaill que la mthode de recherche des donnes, les autres sont des coquilles vides. Mais vous devriez tre capables de faire a tout seuls.

Premier test
Nous avons ralis une bonne partie de ce pattern, nous allons pouvoir faire notre premier test. 646

LE PATTERN DAO

Je tiens prciser que j'utilise toujours le singleton cr il y a quelques chapitres !


Voici un code de test :
import omFsdzFenFglsseY GGgv C rsp C y pour gnrer les imports puli lss pirstest { puli stti void min@tring rgsA { GGestons des lves hey`ileveb eleveho a new ilevehey@dzgonnetionFgetsnstne@AAY for@int i a IY i ` SY iCCA{ ileve eleve a elevehoFfind@iAY ystemFoutFprintln@4ilve x4 C eleveFgetsd@A C 4 E 4 C eleveFgetxom@A C 4 4 C eleveFgetrenom@AAY } ystemFoutFprintln@4nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBn4AY GGoyons voir les professeurs hey`rofesseurb profho a new rofesseurhey@dzgonnetionFgetsnstne@AAY for@int i a RY i ` VY iCCA{ rofesseur prof a profhoFfind@iAY ystemFoutFprintln@profFgetxom@A C 4 4 C profFgetrenom@A C 4 enseigne X 4AY for@wtiere mt X profFgetvistwtiere@AA ystemFoutFprintln@4t B 4 C mtFgetxom@AAY } ystemFoutFprintln@4nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBn4AY GGit lD 9est l lsse hey`glsseb lsseho a new glssehey@dzgonnetionFgetsnstne@AAY glsse lsse a lssehoFfind@IIAY ystemFoutFprintln@4glsse de 4 C lsseFgetxom@AAY ystemFoutFprintln@4nviste des lves X4AY for@ileve eleve X lsseFgetvistileve@AA ystemFoutFprintln@4 E 4 C eleveFgetxom@A C 4 4 C eleveFgetrenom@AAY ystemFoutFprintln@4nviste des professeurs X4AY for@rofesseur prof X lsseFgetvistrofesseur@AA ystemFoutFprintln@4 E 4 C profFgetxom@A C 4 4 C profFgetrenom@AAY

Ce qui me donne la gure 40.4. 647

CHAPITRE 40. LIER SES TABLES AVEC DES OBJETS JAVA : LE PATTERN DAO

Figure

40.4  Test de notre DAO

648

LE PATTERN FACTORY Vous avez compris comment tout a fonctionnait ? Je vous laisse quelques instants pour lire, tester, relire, tester nouveau. . . Nous utilisons des objets spciques an de rechercher dans la base des donnes. Nous nous en servons pour instancier des objets Java habituels.

Le pattern factory
Nous allons aborder ici une notion importante : la fabrication d'objets ! En eet, le pattern DAO implmente aussi ce qu'on appelle le pattern factory. Celui-ci consiste dlguer l'instanciation d'objets une classe. En fait, une fabriqu