Le Cours Java en Français

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction à Java

I-A. Apparition du langage

Vers la fin de 1995, le langage de programmation Java surgit sur la grande scène d'Internet et obtient immédiatement un énorme succès. La prétention de Java est de constituer la colle universelle capable de connecter les utilisateurs aux informations, que celles-ci proviennent de serveurs Web de bases de données, de fournisseurs d'informations ou de toute autre source imaginable. Et Java se trouve en bonne position pour accomplir ce pari. Il s'agit d'un langage de conception très performant qui a été adopté par la majorité des fournisseurs. Ses caractéristiques intégrées de sécurité offrent un sentiment de confiance au programmeurs comme aux utilisateurs des applications. De plus, Java incorpore des fonctionnalités qui facilitent grandement certaines tâches de programmation avancées comme la gestion des réseaux, la connectivité des bases de données ou le développement d'applications multitâches.

La réputation de Java en tant que langage informatique est exagérée : Java est assurément un bon langage de programmation. Il s'agit, sans aucun doute, de l'un des meilleurs disponibles pour un programmeur sérieux. Java aurait, potentiellement, pu être un grand langage de programmation, mais il est probablement trop tard pour cela. Lorsqu'un langage commence à être exploité se pose le problème de la compatibilité avec le code existant. De plus, même lorsque des modifications sont possibles sans révolutionner le code existant, il est très difficile pour les créateurs d'un langage qui a suscité autant d'intérêt de reconnaître qu'un élément x pourrait être plus mauvais ou meilleur qu'un élément y. Même si nous espérons une amélioration de Java avec le temps, sa structure de demain restera, à la base, très proche de celle d'aujourd'hui.

I-B. Les avantages de Java

L'un des avantages évidents de ce langage est une bibliothèque d'exécution qui se veut indépendante de la plateforme : en théorie, il vous est possible d'utiliser le même code pour Windows 95/98/NT, Solaris, UNIX, Macintosh, etc. Cette propriété est indispensable pour une programmation sur Internet (cependant, par rapport à la disponibilité sur Windows et Solaris les implémentations sur d'autres plates-formes ont toujours un léger décalage).

Image non disponible
Architecture classique avec un bytecode différent
Image non disponible
Architecture Java, le bytecode passe par l'intermédiaire d'un interpréteur

Un autre avantage de ce langage de programmation réside dans le fait que la syntaxe de Java est analogue à celle de C++ ce qui le rend économique et professionnel.

Le fait de créer une autre version d'un langage C++ n'est cependant pas suffisant. Le point clé est le suivant : il est beaucoup plus facile d'obtenir du code sans erreur à l'aide de Java qu'avec C++. Pourquoi ? Les concepteurs de Java ont beaucoup réfléchi à la raison pour laquelle le code C++ contenait autant d'erreurs. Cette réflexion les a amenés à ajouter dans Java des fonctions destinées à éliminer la possibilité de créer du code contenant les types d'erreurs les plus courants (selon certaines estimations, le code C++ contient au moins une erreur toutes les cinquante lignes).

  • Les concepteurs de Java ont supprimé l'allocation et la libération de mémoire manuelles. La mémoire dans Java est allouée et libérée automatiquement. Vous n'avez jamais à vous préoccuper de pertes de mémoire.
  • Ils ont éliminé l'arithmétique des pointeurs introduisant du même coup une vraie gestion de tableau. La notion de référence sur une zone mémoire remplace avantageusement celle de « pointeur », car elle supprime la possibilité d'écraser toute zone mémoire à cause d'un compteur erroné.
  • Ils ont éliminé toute possibilité de confusion entre une affectation et un test d'égalité dans une instruction conditionnelle. Une instruction if (ntries - 3) ne pourra pas franchir l'étape de la compilation.
  • Ils ont supprimé l'héritage multiple en le remplaçant par une nouvelle notion d'interface dérivée d'Objective C. Les interfaces vous offrent tout ce que vous pouvez obtenir à partir de l'héritage multiple, sans la complexité de la gestion de hiérarchie d'héritage multiple.

I-C. Caractéristiques

Les créateurs de Java ont écrit un livre blanc qui présente les caractéristiques fondamentales de Java. Ce livre est articulé autour des 11 termes suivants :

  • Distribué
    Java possède une importante bibliothèque de routines permettant de gérer les protocoles TCP/IP tels que HTTP et FTP. Les applications Java peuvent charger et accéder à des fichiers sur Internet via des URL avec la même facilité qu'elles accèdent à un fichier local sur le système.
    « Nous avons trouvé que les fonctionnalités réseau de Java sont à la fois fiables et d'utilisation aisée. Toute personne ayant essayé de faire de la programmation pour Internet avec un autre langage se réjouira de la simplicité de Java lorsqu'il s'agit de mettre en œuvre des tâches lourdes, comme l'ouverture d'une connexion avec un socket. De plus, Java rend plus facile l'élaboration des scripts CGI (Common Gateway Interface), et un mécanisme élégant, nommé servlet, augmente considérablement l'efficacité du traitement côté serveur, assuré par Java. De nombreux serveurs Web, parmi les plus courants, supportent les servlets. Le mécanisme d'invocation de méthode à distance (RMI) autorise la communication entre objets distribués. »
  • Fiabilité
    Java a été conçu pour que les programmes qui l'utilisent soient fiables sous différents aspects. Sa conception encourage le programmeur à traquer préventivement les éventuels problèmes, à lancer des vérifications dynamiques en cours d'exécution et à éliminer les situations génératrices d'erreurs… La seule et unique grosse différence entre C++ et Java réside dans le fait que ce dernier intègre un modèle de pointeur qui écarte les risques d'écrasement de la mémoire et d'endommagement des données.
  • Orienté objet
    Pour rester simples, disons que la conception orientée objet est une technique de programmation qui se concentre sur les données (les objets) et sur les interfaces avec ces objets. Pour faire une analogie avec la menuiserie, on pourrait dire qu'un menuisier « orienté objet » s'intéresse essentiellement à la chaise - l'objet qu'il fabrique - et non à sa conception (le « comment »). Par opposition, le menuisier « non orienté objet » penserait d'abord au « comment »…
  • Simple
    Nous avons voulu créer un système qui puisse être programmé simplement sans nécessiter un apprentissage ésotérique, et qui tire parti de l'expérience standard actuelle. En conséquence, même si nous pensions que C++ ne convenait pas, Java a été conçu de façon relativement proche de ce langage dans le dessein de faciliter la compréhension du système. De nombreuses fonctions compliquées, mal comprises, rarement utilisées de C++, qui nous semblaient par expérience apporter plus d'inconvénients que d'avantages, ont été supprimées de Java.
  • Sécurité
    Java a été conçu pour être exploité dans des environnements serveur et distribués. Dans ce but, la sécurité n'a pas été négligée. Java permet le construction de systèmes inaltérables et sans virus.
  • Architecture neutre
    Le compilateur génère un format de fichier objet dont l'architecture est neutre - le code compilé est exécutable sur de nombreux processeurs - , à partir du moment où le système d'exécution de Java est présent. Pour ce faire, le compilateur Java génère des instructions en bytecode qui n'ont de lien avec aucune architecture particulière. Au contraire, ces instructions ont été conçues pour être à la fois faciles à interpréter et faciles à traduire en code natif.
  • Portable
    A la différence du C/C++, on ne trouve pas les aspects de dépendance de la mise en œuvre dans la spécification. Les tailles des types de données primaires sont spécifiées, ainsi que le comportement arithmétique qui leur est applicable.
  • Interprété
    L'interpréteur Java peut exécuter les bytecodes directement sur n'importe quelle machine sur laquelle il a été porté. Dans la mesure où la liaison est un processus plus incrémentiel et léger, le processus de développement peut se révéler plus rapide et exploratoire.
  • Performances élevées
    En général, les performances des bytecodes interprétés sont tout à fait suffisantes, il existe toutefois des situations dans lesquelles des performances plus élevées sont nécessaires. Les bytecodes peuvent être traduits à la volée en code machine pour l'unité centrale destinée à accueillir l'application.
  • Multithread
    Les avantages du multithread sont une meilleure interactivité et un meilleur comportement en temps réel.

II. Le JDK de Sun

Le JDK de Sun (les créateurs de Java) est l'outil essentiel pour programmer en Java. Il permet la compilation, le débogage, et l'exécution d'applications et d'applets Java. Il comprend également des fonctions avancées comme les signatures numériques, la création d'archives et de documentation ou l'intégration de code natif C.

La documentation du JDK est en fait l'API de Java (le détail de toutes les fonctions du langage si vous préférez). Ceci explique sa taille importante (16 Mo). Elle est au format HTML. Vous ne pourrez pas créer de gros programmes sans y avoir recours.

Ces 2 outils sont disponibles dans la rubrique LIENS/RESSOURCES de ce site, à l'adresse http://perso.wanadoo.fr/guillaume/liens.htm

II-A. Installation

Après avoir téléchargé le JDK, vous devez l'installer en suivant les indications qui s'affichent à l'écran. L'installation prend environ 60 Mo. Il est important de ne pas avoir d'espace dans le nom des répertoires qui mènent au JDK. Les espaces peuvent causer certaines erreurs (les fonctions basiques fonctionnent quand même). Par exemple il est déconseillé d'installer le JDK dans « program files ». Préférez un chemin simple comme « C:\JDK\ ».

Une fois les fichiers du JDK copiés, il faut définir un CLASSPATH ou « Chemin des classes ». Ce Classpath est la source de nombreuses crises de nerfs chez les débutants (j'en ai souffert…), c'est pourquoi il est important de bien le définir.

POUR WINDOWS 95 : Allez sous DOS, allez à la racine du disque dur (utilisez « cd.. » pour descendre dans l'arborescence). Une fois dans « C:\ », tapez « edit autoexec.bat ». Un éditeur apparaît avec les lignes de l'« autoexec.bat ». Rajoutez cette ligne : « path = C:\JDK\bin\ ». Enregistrez le fichier, redémarrez votre ordinateur.

Image non disponible

POUR WINDOWS 98 : Ouvrez le menu Démarrer, allez dans Exécuter, tapez « msconfig », une fenêtre s'ouvre, allez sur le 3e onglet qui correspond à « autoexec.bat », cliquez sur Nouveau et tapez « path = C:\JDK\bin\ ».Vérifiez que la petite case à gauche de cette ligne est bien cochée et redémarrez votre ordinateur.

Note : « path = C:\JDK\bin\ » ne fonctionne que si « C:\JDK\ » est votre répertoire d'installation du JDK. Si ce n'est pas le cas, remplacez-le par votre vrai répertoire.

Image non disponible

II-B. Compiler

Écrivez votre programme Java avec un éditeur de TEXTE BRUT (ex : NotePad). Sauvegardez-le avec l'extension « .java ». (ex : « HelloWorld.java »). Le nom de votre fichier doit être le même que celui de votre classe principale (RESPECTER LA CASSE) :

 
Sélectionnez
public class HelloWorld {
    // code
}

Le nom de votre fichier sera HelloWorld.java

Une fois le fichier enregistré, ouvrez une fenêtre DOS et rendez-vous dans le répertoire où vous avez enregistré votre fichier. (« cd nomDuRépertoire » pour monter d'un niveau et « cd.. » pour descendre). Une fois dans le répertoire où est votre fichier, tapez :

 
Sélectionnez
javac nomDuFichier.java

Respectez la casse et tapez toutes les lettres (pas de « nomDe~1 »). Le compilateur Java reconnaît les noms longs.

Normalement vous ne devez avoir aucun message, sinon, c'est que vous avez fait une erreur dans votre programme, vérifiez alors la syntaxe. Vous verrez vite que toutes les erreurs ne sont pas détectées par javac, certains programmes se compilent mais affichent une erreur à l'exécution… C'est terrible… Mais pour l'instant pas de problème.

Quand javac compile un programme, il crée un fichier « *.class » (ex : « HelloWorld.class »). Ce fichier est compilé et sera interprété par la machine virtuelle.

II-C. Exécuter

Sous DOS, placez-vous dans le répertoire où javac a créé le fichier « *.class » (le même que celui où vous avez au début enregistré votre fichier texte brut « *.java »). Tapez :

 
Sélectionnez
java nomDuFichier

Respectez la casse et ne mettez pas l'extension. Java accepte aussi les noms de fichier longs. Le programme s'exécute. Ouf…!!!

Image non disponible

III. Initiation à Java : le projet HelloWorld

III-A. Débuter un programme

Importer les packages nécessaires
Écrire le corps du programme (déclaration de variables, création des méthodes, création de l'IU…)
Écrire la méthode main() :

 
Sélectionnez
public static void main (String  x[ ]) {
    …// votre code
}

Note : « x » représente la matrice d'« arguments » c'est pourquoi il sera le plus souvent remplacé par « arguments » ou « args ». Vous pouvez cependant choisir n'importe quel nom. Note : tous les programmes (pas les applets…) doivent avoir une méthode « main() », car c'est ce qui les définit en tant que programme !

III-B. Débuter une applet

Importer les packages nécessaires.
Déclarer la classe principale :

 
Sélectionnez
public class x extends java.applet.Applet {
    …// votre code
}

Note : « x » représente le nom de votre programme ainsi que le nom de son fichier source (« x.java » et « x.class »).
Note : pour programmer des applets en Java 2, on remplace « java.applet.Applet » par « JApplet ». Il est cependant recommandé de programmer vos applets en Java 1.1 ou mieux, en Java 1.02 car les dernières versions des principaux navigateurs (IE5, Communicator 4.7) ne supportent pas Java 2. Java 2 est supporté par le navigateur HotJava Browser de SUN (http://www.sun.java.fr), ainsi que par l'appletviewer (!), outil qui vous permettra de tester vos applets (inclus dans les JDK).

III-C. Insérer des commentaires

Les commentaires sont des lignes dans le programme qui ne sont pas prises en compte par le compilateur. Ils servent seulement à accroître la lisibilité du code source. Ils sont le plus souvent en vert dans les environnements de développement comme Kawa, JBuilder ou VisualCafé.
Voici comment on crée un commentaire :

  • Ce code est pris en compte par le compilateur // ce code n'est plus pris en compte par le compilateur.
  • /* Les deux slash ne permettent d'écrire des commentaires que sur 1 seule ligne, alors que cette méthode avec une belle étoile et encore un slash permettent d'écrire sur plusieurs lignes des romans ou des fables de centaines de pages commençant par Il était une fois et finissant par le sempiternel ils se marièrent et eurent beaucoup d'enfants…………………….. */

Résumons :

 
Sélectionnez
// sur 1 seule ligne
/* … */ sur plusieurs lignes

III-D. Écrire du texte

Le titre de ce paragraphe ne veut rien dire car en programmation, « on n'écrit pas de texte », on affiche du texte sur un périphérique de sortie (par défaut l'écran de l'ordinateur !) ; on peut aussi afficher du texte dans un composant d'une IU (par exemple, l'intitulé du menu « fichier » de votre navigateur). Dans notre exemple, on affichera du texte dans la zone de sortie : ici, la fenêtre de ligne de commande (MS-DOS pour les PC sous Windows) dans laquelle a été lancée l'application (cf. rubrique JDK/exécution d'un programme).
Pour afficher du texte en ligne de commande, on utilise la méthode :

 
Sélectionnez
System.out.println("texte à afficher");
System.out.print("les deux méthodes sont équivalentes");

Il est plus difficile (c'est relatif…) d'afficher du texte dans une applet, car on doit l'afficher dans un composant (une applet est lancée dans une sorte de cadre inséré dans le navigateur) graphique de l'applet, les deux méthodes ci-dessus ne fonctionnent pas. On utilise la méthode « paint() » de l'applet pour définir l'affichage et la méthode « drawString() » pour écrire le texte :

 
Sélectionnez
public void paint(Graphics screen) {
    screen.drawString("Bonjour", 5, 40);
}

Note : 5 et 40 sont les coordonnées du texte dans un repère qui a pour origine de coin haut gauche de l'écran.

III-E. Application : le programme Hello World !

Hello World ! est célèbre : c'est traditionnellement le premier programme que l'on fait faire à une personne qui débute dans un langage de programmation. Il a pour but d'afficher le texte Hello World ! Il faut donc pour l'exécuter créer un programme, avec la méthode « main() », et utiliser la méthode « System.out.println() » pour afficher notre texte. Au travail !

 
Sélectionnez
class HelloWorld { // début du programme
    public static void main (String args[ ]) {  // début de ma méthode  main()
        System.out.println("Hello World !");  // affichage du texte désiré
    }  // fin de ma méthode  main()
}

Note : pour compiler le programme, vous devez nommer votre fichier « HelloWorld.java », en respectant la casse.

Voici le programme exécuté :

Image non disponible

IV. Les Variables : le projet Chocos

Il est possible de télécharger les sources du programme.

IV-A. Introduction

Il est facile de concevoir ce que sont les variables. Prenons comme exemple des boites de chocolat. Ces boites sont remplies avec plusieurs catégories de chocolats  : les Truffes, les MonChéri, les Cœurs et les Mokas. Ce sont les 4 pauvres variétés de chocolats que vend le chocolatier. Vous pouvez choisir par exemple 8 Truffes et 20 MonChéri dans votre première boite et 4 Cœurs, 10 Mokas et 14 MonChéri dans votre seconde boite. Imaginons maintenant en programmation : on crée des objets boite (cf. chapitre sur la POO pour les objets) avec pour variables : Truffes, MonCheri, Cœurs, Moka. Dans le cas de la première boite, on va associer la valeur 8 à la variable Truffe, et la valeur 20 à la variable MonCheri.

IV-B. Types de variables

Il y a différents types de variables en Java, qui ne stockent pas les mêmes valeurs. Regardez le tableau ci-dessous regroupant les variables les plus utilisées  :

NOM PLACE EN BITS VALEURS STOCKEES COMMENTAIRES
byte 8 De -128 à 127 Vous ne l'utiliserez pas souvent
short 16 -32 768 à 32 767  
int 32 -2x109 à 2x109 Appelée INTEGER (entier en français), très utilisée
long 64 -9x1018 à 9x1018  
boolean 1 booléennes Valeurs binaires : true ou false
String   chaînes Considéré à ce stade comme une variable bien que cela n'en soit pas une. Ne pas oublier la majuscule.
BigInteger + de 64 ? Importer java.math.BigInteger
double     Pratique pour les décimales. Très utilisé.
float   Virgule flottante Pi, e…

Note : vous pouvez créer vos propres types de variables, nous verrons plus tard…

IV-C. Déclaration de variables

La création d'une variable est appelée « déclaration ». On va donc déclarer nos variables en chocolat, elles stockeront le nombre de chocolats de chaque type contenus dans une boite. Elles seront du type integer.

 
Sélectionnez
int Truffes;
int MonCheri;
int Moka;
int Coeur;

On peut également déclarer toutes ces variables d'un seul coup car elles appartiennent au même type, c'est-à-dire les entiers (integer).

 
Sélectionnez
int Truffes, MonCheri, Moka, Coeur;

IV-D. Initialisation des variables

Initialiser une variable signifie lui donner une valeur de départ (cette valeur peut changer au cours du programme, normal, c'est variable !). Prenons le cas de la première boite de chocolats  :

 
Sélectionnez
int Truffes = 8;
int MonCheri = 20;

Note : ceci déclare les variables avant de les initialiser. Ces lignes regroupent donc chacune deux opérations en une seule.

IV-E. Opérateurs d'affectation

On a une variable x, déclarée avec une valeur bien précise. On veut lui ajouter la valeur de y (qui est aussi déclarée et initialisée). On écrit alors : x = x + y. Et x prend alors une nouvelle valeur (son ancienne ajoutée à celle de y, qui, elle ne change pas). On peut aussi multiplier, diviser… :

OPERATION A REALISER OPERATION DEVELOPPEE OPERATION SIMPLIFIEE
Addition x = x + y x += y
Soustraction x = x - y x -= y
Multiplication x = x * y x *= y
Division x = x / y x /= y

IV-F. Incrémentation et décrémentation

Incrémenter c'est augmenter de 1 la valeur d'une variable et décrémenter, diminuer de 1. Ces procédés sont particulièrement utiles dans les boucles (cf. chapitre sur les bouclesBoucles et Conditions : le projet NamesLoop). On incrémente à l'aide de ++ et on décrémente à l'aide de --.

 
Sélectionnez
int x = 7  ;  // déclaration de x, initialisée avec 7 pour valeur
x++ ;  // on incrémente x, x a maintenant le valeur 8

IV-G. Comparaison de variables

Le titre est assez parlant… on regarde si deux variables sont égales, différentes, si la première est supérieure à la seconde, si la seconde est inférieure ou égale à la première…

OPERATEUR DESCRIPTION
== Egal à
!= Différent de
< Inférieur à
> Supérieur à
<= Inférieur ou égal à
>= Supérieur ou égal à

Note : ceci ne fonctionne qu'avec les variables et pas avec les objets (dans ce cas le programme compare si c'est le même objet, pas s'il a la même valeur). Cela ne fonctionne donc pas avec String qui est un objet…

IV-H. Les constantes

Les constantes sont des variables constantes (!) (si, si, je vous jure…). En fait elles sont utilisées pour les mêmes choses que les variables ; stocker des valeurs, mais une fois initialisées, la valeur ne peut plus changer… Elles sont déclarées avec le mot clé final.

 
Sélectionnez
final float pi = 3.14159;

Vous n'allez quand même pas essayer de changer la valeur de pi ? ;-)

IV-I. Blocs et portée

En Java, les programmes sont très structurés. Ils sont organisée en blocs. Par exemple tout ce qui est contenu dans la méthode main() est un seul et même bloc (souvent subdivisé en autres petits blocs). De même, les instructions de la méthode paint() d'une applet sont dans un seul et même bloc. Pour les reconnaître  : ils commencent par une accolade ouvrante { et finissent par une fermante }.
Les variables classiques ont une portée dans le bloc qui les contient. Si vous faites référence dans un bloc à une variable déclarée dans un autre bloc, le compilateur générera une erreur. (ne dites pas « bogue » pour l'instant… Il y a une grosse différence entre un bogue et l'erreur décrite ci-dessus). Mais il est possible en Java de créer des variables spéciales qui ont pour portée tout le programme (ou la classe, c'est un synonyme de programme). Ces variables bien pratiques sont appelées variables de classe. On les déclare à l'aide du mot clé static.

 
Sélectionnez
static int nombreDeBilles = 200 ; // ce garçon a beaucoup de billes !
static String surnom = "Drizzt" ;  /* comme il s'appelle Djkelimbfastlichtz, on le surnomme 
Drizzt, la valeur de type String (chaîne de caractères) de la variable «  surnom  » est donc 
Drizzt*/

IV-J. Application : le programme Chocos

Le programme Chocos va déclarer plusieurs variables. Les valeurs de ces variables vont changer puis être affichées sur le périphérique de sortie, ligne de commande. On utilisera : System.out.println() pour afficher la valeur des variables.

 
Sélectionnez
class Chocos { // début du programme
    static String mangeur = "Gargantua"; //variable statique. portée = tout le programme 

    public static void main(String args[]) { // début de la méthode main()

        int nombreDeChocolats = 40; //variable non-statique. portée = ce bloc main()

        System.out.println(mangeur + " a " + nombreDeChocolats + " chocolats");
        System.out.println("Il en mange 3 d'un coup");

        nombreDeChocolats = nombreDeChocolats - 3; // changement de valeur de la variable
        System.out.println("Il en reste : " + nombreDeChocolats);
        System.out.println("Il renverse la boite, 15 sont perdus");

        nombreDeChocolats = nombreDeChocolats - 15;
        System.out.println("Il en reste : " + nombreDeChocolats);
        System.out.println("Pour se venger," + mangeur + " finit la boite");

        nombreDeChocolats = nombreDeChocolats - 22;
        System.out.println("Il en reste : " + nombreDeChocolats);
        System.out.println("Mais " + mangeur + " a encore une boite&#8230;");
    }
}
Image non disponible

V. Les Matrices : le projet ArrayTest

Il est possible de télécharger les sources du programme.

V-A. Définition

Les matrices sont des sortes de conteneurs à variables. Toutes les données dans une même matrice doivent être du même type, on parle ainsi de matrices d'entiers, de matrices de chaînes, etc.

V-B. Utilité

On peut déclarer 200 variables de type int en 200 lignes et une matrice de 200 int en 1 ligne… On gagne ainsi en rapidité, lisibilité et légèreté du code. De plus les matrices sont utiles si l'on doit par exemple stocker les prénoms de plusieurs personnes, puis leur nom de famille, puis leur âge… On crée à cet effet 3 matrices. Enfin, il est plus utile de travailler avec les matrices car on connaît le nombre d'éléments qu'elles contiennent (on peut donc par exemple créer un matrice de prénoms puis une autre de noms de famille sans oublier aucune entrée.

V-C. Syntaxe

Déclaration d'une matrice :

 
Sélectionnez
String mots[]; 
String [] mots;

Dans les deux cas, le programme crée une matrice de chaînes ayant pour nom mots. On note la syntaxe très proche des déclarations de variables.

Initialisation d'une matrice :

 
Sélectionnez
String[] nomDesJoueurs = new String[10]; 
nomDesJoueurs[0] = "franck"; 
nomDesJoueurs[1] = "john";

Ces commandes créent un matrice de chaînes de nom nomDesJoueurs et contenant 10 « cases ». Elles donnent ensuite la valeur franck à la première de ces « cases » et john à la seconde.
Note : les valeurs des matrices sont numérotées à partir de 0.

 
Sélectionnez
String[] prenoms = {"franck", "john", "gerthrud", "moloss", "grota"};

Cette commande crée un tableau de String prenoms et lui attribue directement des valeurs. La matrice contient donc 5 « cases ».

V-D. Application : Projet ArrayTest

Le programme ArrayTest crée une matrice contenant les prénoms de programmeurs célèbres. Il affiche cette matrice, puis crée une autre matrice de la même grandeur (avec le même nombre de « cases »). Cette seconde matrice contient les noms de famille correspondant à chaque prénom. Le résultat est affiché.

 
Sélectionnez
class ArrayTest { // classe principale

    // création de la première matrice de prénoms
    String[] firstNames = { "Dennis", "Grace", "Bjarne", "James" }; 

    // la seconde matrice contient le même nombre d'arguments que la première
    String[] lastNames = new String[firstNames.length]; 

    void printNames() { // méthode pour afficher le contenu de la 2de matrice 
        int i = 0; // i du type integer et égal à 0

        // afficher la valeur i+0=0 de la matrice 1 et de la matrice 2
        // ceci consiste donc à afficher le contenu de la première case 
        //des 2 matrices
        System.out.println(firstNames[i] + " " + lastNames[i]); 

        // (i=0)i=i+1, donc de la seconde case des matrices 
        i++; 
        System.out.println(firstNames[i] + " " + lastNames[i]); 
        // (1=1) 1=1+2, donc de la seconde case des matrices 
        i++; 
        System.out.println(firstNames[i] + " " + lastNames[i]); 
        i++; 
        System.out.println(firstNames[i] + " " + lastNames[i]); 
    } 

    public static void main (String arguments[]) { 
        ArrayTest a = new ArrayTest(); // appel de la classe
        a.printNames(); // applet de la méthode printNames()
        System.out.println("-----"); 
        // définition des valeurs des cases de la 2de matrice
        a.lastNames[0] = "Richie"; 
        a.lastNames[1] = "Hopper"; 
        a.lastNames[2] = "Stroustrup"; 
        a.lastNames[3] = "Gosling"; 
        a.printNames(); // appel de la méthode printNames()
    } 
}
Image non disponible

VI. Boucles et conditions : le projet NamesLoop

Il est possible de télécharger les sources du programme.

VI-A. Introduction, les conditions if…else

Les conditions utilisent des données booléennes, true ou false. Elles vérifient si une condition est remplie. Si oui, elles effectuent un bout de code prédéfini, sinon, elles exécutent au autre bout de code prédéfini ou passent directement au reste du programme. Elles ont la forme if … else …

 
Sélectionnez
if (BeaucoupDeFric == true) 
    Restaurant = "Jardin des sens"; 
else 
    Restaurant = "McDo"

Si le personne est riche elle ira manger dans un certain restaurant, sinon, elle ira ailleurs…
Note : on peut en faire à plusieurs possibilités : if… else if … else if… else if… else…

 
Sélectionnez
if (Fric == 100) 
    Resto = McDo; 
else if (Fric == 200) 
    Resto = Quick; 
else if (Fric == 300) 
    Resto = Flunch; 
else 
    Resto = chezMoi;

VI-B. Switch…Case

Les conditions switch…case remplacent les conditions if…else if…else quand le nombre de else if est trop important. Elles sont en effet plus rapides à écrire :

 
Sélectionnez
switch (note) { 
    case 'A'&#160;: 
        System.out.println ("Très Bien"); break; 
    case 'B'&#160;: 
        System.out.println ("Bien"); break; 
    case 'Z'&#160;: 
        System.out.println ("Lobotomisé !"); break; 
    default&#160;: System.out.println ("Tricheur !"); 
}

Note : pour sortir de la condition, on utilise le mot break, regardez bien l'utilisation du « ; » pour terminer les instructions (et pas les lignes !).

VI-C. Boucles for

Les boucles for testent une condition et exécutent le bout de code attaché à la boucle tant que la condition n'est pas remplie. Leur syntaxe officielle est la suivante :

 
Sélectionnez
for (initialization ; test ; increment) { statement ; }

Ceci ne vous évoque certainement rien, alors examinez le code suivant :

 
Sélectionnez
String [] salutation = new String[10]; 
int i; 
for (i = 0 ; i < salutation.length ; i++) 
    salutation[i] = "M.";

Le programme crée une matrice du nom de salutation qui peut contenir 10 éléments. Il crée ensuite une variable i de type Integer. La boucle for commence : la valeur de i est 0, tant que la valeur de i est inférieure à la taille de la matrice (taille obtenue par la commande salutation.length), le code de la dernière ligne est exécuté. i est incrémenté de 1, puis la condition est re-vérifiée, ainsi de suite jusqu'à i = 10.

VI-D. Boucles while

Les boucles while sont très semblables aux boucles for. Elles fonctionnent ainsi :

 
Sélectionnez
while (i < 10) { 
    // corps de la boucle 
    i++ ; 
}

Tant que i < 10, le corps de la boucle est exécuté, puis i est incrémenté et la condition est re-testée.

VI-E. Boucles do…while

Les boucles do…while sont des variantes des boucles while. Leur particularité réside dans le fait que la condition est testée après la première exécution de la boucle. Le code est exécuté tant que la condition n'est pas satisfaite mais il sera dans tous les cas exécuté au moins une fois.

 
Sélectionnez
{ 
    // corps de la boucle 
} while (i < 10)

Voici un exemple plus concret sur l'utilisation des boucles :

 
Sélectionnez
class BoucleDo {
    public static void main(String args [ ]) {
        int x = 1;
        do {
            System.out.println("La boucle est bouclée; passage" + x);
            x++ ;
        } while (x <= 100) ;
    }
}

Vous pouvez compiler ce programme, il fonctionne ! Nommez le fichier source « BoucleDo.java ».

VI-F. Break et Continue

break sert à interrompre une instruction. Dans un switch case, il permet d'en sortir sans passer dans les case suivants. Dans une boucle, il permet de sortir de la boucle sans réaliser les itérations suivantes.

continue permet de passer directement à l'itération suivante d'une boucle sans exécuter le code qui est entre le continue et la fin de la boucle.

VI-G. Application : Projet NamesLoop

Ce programme, une fois de plus de ligne de commande, crée une matrice contenant des prénoms de programmeurs célèbres et les associe à leur nom de famille. On utilise donc les matrices, les boucles for, la création d'une méthode, l'affichage de texte. Ce programme est extrait de l'excellent ouvrage Java2 (Roger Cadenhead & Laura Lemay) Ed. CampusPress.

 
Sélectionnez
class NamesLoop { // Création de la classe 
    String[] firstNames = { "Dennis", "Grace", "Bjarne", "James" }; // matrice des 
    //prénoms 
    String[] lastNames = new String[firstNames.length]; //matrice des noms (vide)
    void printNames() { // méthode pour afficher
        for(inti = 0; i < firstNames.length; i++) // boucle for
            System.out.println(firstNames[i] + " " + lastNames[i]); //instruction
    } 

    public static void main (String arguments[]) { 
        // remplissage de la seconde matrice avec les prénoms 
        // appel de la méthode d'affichage  
        NamesLoop a = newNamesLoop(); 
        a.printNames(); // méthode d'affichage
        System.out.println("-----"); 
        a.lastNames[0] = "Ritchie"; 
        a.lastNames[1] = "Hopper"; 
        a.lastNames[2] = "Stroustrup"; 
        a.lastNames[3] = "Gosling"; 
        a.printNames(); // méthode d'affichage
    } 
}

Note : Ici la boucle for sert à déterminer la taille de la matrice des noms de famille. Elle compte le nombre d'éléments dans la matrice des prénoms, ce nombre d'éléments est associé à la matrice des noms de famille (car chaque personne a un prénom et un nom de famille)

Image non disponible

VII. Objets ou Instances : le projet EgaliteTest

Il est possible de télécharger les sources du programme.

VII-A. Introduction

Dans le chapitre sur les variables, nous avions défini les différentes sortes de chocolats dans une boîte. Nous avions utilisé par commodité les notations première et seconde boîte, mais l'ordinateur, lui, ne sait pas que les chocolats sont contenus dans une boîte, et encore moins qu'il y a 2 boîtes différentes ! En termes informatiques, ces boîtes seraient des objets, également appelés instances. A ce niveau vous pourriez confondre un objet avec une matrice… Conteneurs de chocolats… Mais les matrices sont des sortes d'objets. On parle de langage de programmation orienté objet pour Java, ce qui signifie qu'il travaille avec des objets, leur assignant des propriétés (par exemple contenir des chocolats au lait et noirs) et des comportements (se re-remplir automatiquement de chocolats une fois vide…). La pratique vous aidera à éclaircir ce concept flou.

VII-B. Déclaration (ou création de nouveaux objets)

 
Sélectionnez
String teamName = new String() ; 
Dinosaure Trex = new Dinosaure(); 
BoiteChocos auLait = new BoiteChocos();

Si vous ajoutez ces lignes dans un de vos programmes, il refusera de se compiler. Lui ne sait pas ce qu'est un Dinosaure() ou un BoiteChocos(). Pouvez-vous me décrire un szertysprzchutde la planète sakasksproucht ? Non. Pouvez-vous me décrire … un chien … oui. De même pour l'ordinateur qui connaît la classe String car ses propriétés et son comportement ont été préalablement définis. (Dans l'API de Java.)
Il est défini dans les propriétés de String qu'il reçoit comme argument (ce qui vient entre les parenthèses) une chaîne. Si vous essayez de lui assigner autre chose qu'une chaîne comme argument, il générera une erreur et le programme ne se compilera pas.
De même, par exemple, pour Point qui admet comme arguments ses coordonnées en abscisse et ordonnée. (Dans (O, i, j), O situé en haut à gauche de l'écran et les coordonnées des vecteurs i et j exprimées en pixels).

 
Sélectionnez
Point A = new Point(10, 3) ;  // fonctionne
Point B = new Point("Bonjour") ;  // ne fonctionne pas
Image non disponible

Le compilateur nous dit qu'il ne peut pas convertir une valeur de type chaîne (String) en argument pour Point.

VII-C. Accès aux valeurs

On peut par l'intermédiaire de méthodes (fonctions, ou série d'actions qui définissent un comportement) avoir accès aux valeurs des objets. On prendra pour exemple le composant TextField de l'interface utilisateur AWT de Java et lui assigner une valeur.

Image non disponible
Image non disponible

Le nom de cet objet est textField1. Il a été déclaré comme ceci :

 
Sélectionnez
TextField textField1 = new TextField();

On peut définir le texte qu'il affichera en utilisant la méthode setText() :

 
Sélectionnez
textField1.setText("Bonjour !");

On a ainsi eu accès à sa valeur d'affichage de texte qui était auparavant fixée nulle.

VII-D. Comparaison d'objets

On utilise les mêmes opérateurs que pour les variables, par exemple == pour égal ou != pour différent.

 
Sélectionnez
Point A = new Point(10, 3) ; 
Point B = new Point(11, 4); 
System.out.println("Même objet ?" + (A == B));

On compare ainsi les objets : « est-ce que A est B ? » et non pas « est-ce que A a la même valeur que B ? ». Pour savoir s'ils ont la même valeur, on utilise la méthode equals().

VII-E. Application : le programme EgaliteTest

Dans ce programme nous allons revenir sur la comparaison des objets et la comparaison de leur valeur.
Note : souvenez vous dans le chapitre sur les variables : String n'en était pas une…

 
Sélectionnez
class EgaliteTest { 
    public static void main(String args[]){ 
        String str1, str2; // 2 objets de type String
        str1 = "Voila un exemple !"; // valeur du premier

        str2 = str1; // le second est le premier

        System.out.println("Chaine 1 " + str1); 
        System.out.println("Chaine 2 " + str2); 
        System.out.println("Même objet ? " + (str1 == str2)); 

        // on re-crée le second objet
        str2 = new String(str1); // le second a la valeur du premier

        System.out.println("Chaine 1 " + str1); 
        System.out.println("Chaine 2 " + str2); 
        System.out.println("Même objet ? " + (str1 == str2)); 
        System.out.println("Même valeur ? " + str1.equals(str2)); 
    } 
}
Image non disponible

La partie concernant les objets est énorme : c'est normal, java est un langage orienté objet… Nous verrons de nouvelles applications dans d'autres chapitres.

VIII. Méthodes : le projet ReHello

Il est possible de télécharger les sources du programme.

VIII-A. Définition

Nous avons créé des objets. Nous avons assigné des propriétés à ces objets. Il ne nous reste plus qu'à leur associer un comportement, car s'ils se contentaient de rester plantés sur place on tomberait vite dans le très descriptif HTML ;-).
On peut aussi appeler les méthodes des fonctions ou des routines (ce terme est peu usité en Java, il vient du C++).

Note concernant ce chapitre : plusieurs paragraphes de ce chapitre concernant des fonctions plus ou moins évoluées ne sont pas développés ; je trouve que c'est préférable ainsi, et qu'après une brève définition pour vous informer sur l'existence de la chose, il vaut mieux ne pas vous noyer sous des exemples qui devraient faire appel à des concepts qui ne vous sont pas encore familiers et dont vous n'aurez pas l'utilité immédiate.

VIII-B. Généralités

La création de la méthode elle-même n'est pas compliquée, ce qui est plus délicat est de lui assigner un comportement. Les méthodes sont reconnaissables à leurs parenthèses, elles sont délimitées comme les classes par des accolades. Vous êtes libre du choix de leur nom (choisissez quand même un truc intelligent…).

Si une méthode ne retourne pas de valeur, (les System.out.print() ne sont pas considérés comme retournant des valeurs), il faut la déclarer à l'aide du mot clé void. Si elle retourne une valeur, on la déclare avec le mot clé du type de valeur qu'elle retourne. Pour qu'une méthode retourne une valeur, on emploie return. On peut assigner à une méthode des arguments (sous la forme de variables classiques, par opposition aux variables de classe), on place ces éléments entre les parenthèses. Ainsi dans une classe, 2 méthodes peuvent avoir la même nom, seuls leurs arguments respectifs les différencieront aux yeux du compilateur. On appelle ce concept surcharge de méthodes.

 
Sélectionnez
// ne retourne pas de valeur 
void imprime() { 
    int i = 10 + 20; 
    System.out.println("Résultat&#160;: " + i); 
} 
 
// retourne une valeur 
int imprime() { 
    int i = 10 + 20; 
    return i; 
} 

// admet un argument 
int imprime(int i) {
    i = 10 + i; 
    return i; 
}

On notera que l'habituel public static void main(String args[]) {…} déclare en fait une méthode publique (voir chapitre sur les modificateursLes Modificateurs), statique (voir aussi ce très utile chapitre), qui ne retourne pas de valeur, qui se nomme main et qui a pour argument une matrice de chaînes nommée args. Ouf…

VIII-C. Constructeurs

Les constructeurs sont des méthodes particulières qui servent à créer des objets à partir d'une classe. Elles portent exactement (toujours la casse…) le même nom que la classe qui les contient. Elles n'ont pas de type de retour.

VIII-D. Le mot clé this

Ce mot clé est utile pour la lisibilité du code. Il sert dans le cas où une variable d'instance et une variable de classe portent le même nom. this est alors employé pour faire référence à la variable de classe. Vous pouvez ainsi attribuer plusieurs fois le même nom de variable.

 
Sélectionnez
this.nomDeLaVariable = nomDeLaVariable;

VIII-E. Le mot clé super

Le mot clé super permet d'accéder à l'implémentation d'une méthode de la super classe.

 
Sélectionnez
public class Mere {
    public void methode() {
        System.out.println("méthode mere");
    }
}

public class Fille extends Mere {
    public void methode() {
        super.methode(); // Appel à la méthode de la classe Mere
        System.out.println("méthode fille");
    }
}

VIII-F. Finaliser

La méthode finalize() peut être appelée lorsque qu'un objet est détruit (retiré de la mémoire vive), mais ce n'est pas obligatoire. C'est le garbage collector qui décide de la destruction d'un objet. Il est possible de provoquer une exécution du garbage collector avec System.gc().

 
Sélectionnez
protected void finalize() throws Throwable { 
    ...
}

VIII-G. Application : ReHello

Le programme ReHello est la seconde mouture de HelloWorld, il crée un méthode qui sert à afficher du texte. Ce très court programme est plus simple que plusieurs des chapitres précédents et il n'utilise pas de concept évolué. C'est donc un jeu d'enfant…

 
Sélectionnez
class ReHello { // déclaration de la classe principale

    public static void imprime() { // création de la méthode qui affiche le texte
        // ci-dessous les instructions de la méthode
        System.out.println("HelloWorld ! Encore une fois&#8230;"); 
    } // fin de la méthode imprime()

    public static void main(String args[]) { // la méthode main()&#8230;
        imprime(); // &#8230; qui fait appel à la méthode imprime()
    } 
}

On note que notre méthode imprime() est statique (déclarée ainsi par le mot clé static), car on ne peut faire référence dans une première méthode déclarée statique à une seconde méthode que si cette dernière est statique. C'est le cas de la méthode main() qui est statique est qui ne peut contenir que des références à des méthodes statiques. (voir le chapitre sur les modificateursLes Modificateurs pour plus amples informations)

Image non disponible

IX. Classes et Héritage

IX-A. Définition

Chaque logiciel Java, qu'il s'agisse d'une applet ou d'une application, se compose toujours d'au moins une classe. Toutes les variables, méthodes et lignes d'instructions doivent toujours se trouver dans une classe. Les seules exceptions sont les instructions d'importation de classes, ainsi que celles qui définissent une classe comme appartenant à une bibliothèque de classes.
Une classe dont vous programmez le code source peut se représenter comme un plan de construction de l'objet. Elle se compose de données et de méthodes qui ont un quelconque rapport conceptuel. Définition du Grand Livre Java 2 chez Micro Application.

On retient ici qu'une classe est un programme Java (ce sont quasiment des synonymes). Par exemple, si MSOffice était écrit en Java, on aurait une classe pour Word, une autre pour Excel et encore une autre pour Outlook, etc. MSOffice serait alors le package (paquetage en français) ou le rassemblement de plusieurs classes. Cette vision est naïve car NotePad à lui seul regrouperait plusieurs classes (on pourrait tout faire dans la même classe mais ce serait incompréhensible, imaginez que vous vous retrouvez devant 300 pages de programme à la suite !), mais elle permet de comprendre le concept de classe.

IX-B. Héritage

Une classe est donc un programme qui définit des objets, variables, méthodes etc. Disons que dans Word 1, il existe une classe (composée de plusieurs méthodes) pour ouvrir un fichier. Dans sa version 2, M… veut améliorer la gestion de l'ouverture des fichiers, tout en gardant les méthodes - qui fonctionnaient parfaitement - de la version 1. La classe de la version 2 doit alors hériter des propriétés de la classe de la version 1. Ceci est comme un héritage génétique : une même base avec certaines choses qui changent.
Si vous avez déjà examiné le code source d'une applet, vous avez eu l'occasion de voir une commande d'héritage. On déclare la classe principale d'une applet ainsi :

 
Sélectionnez
public class NomDeLaClasse extends java.applet.Applet {&#8230;}

Votre classe (ici, NomDeLaClasse) étend la classe Applet. Ceci signifie qu'elle hérite des propriétés de cette classe. Une de ces propriétés est par exemple la création d'une zone d'affichage graphique (dans votre navigateur). Sans ceci le programme n'est pas une applet. java.applet est le chemin d'accès (classpath) qui dit au programme d'aller chercher la classe Applet dans le package java, puis dans le répertoire applet de celui-ci. Dans la bibliothèque de classes de Java, les classes sont classées (!) dans des répertoires.
La classe NomDeLaClasse est une sous-classe de la classe Applet du package java.applet qui est elle-même sa super-classe.
En Java, une classe ne peut pas hériter de plusieurs classes. Java ne supporte donc pas l'héritage multiple. Java est donc moins flexible que d'autres langages, mais il évite ainsi nombre d'erreurs. Ceci est compensé en partie par les interfaces.

Image non disponible

Note : sur le graphique, JApplet remplace Applet car il s'agit de la classe de Java2 (non supporté par les navigateurs actuels).
Si vous souhaitez interdire l'héritage d'une de vos classes, vous devez la déclarer final.

 
Sélectionnez
final class NonHeritable {&#8230;

Si vous voulez un schéma d'héritage complet de Java 1.1, téléchargez le PDF (157Ko) à cette adresse : http://perso.wanadoo.fr/guillaume/Ressources/api_java1.pdf

IX-C. Création de classes

Les classes sont déclarées avec le mot clé class, le code est enfermé entre deux accolades. On utilise le mot clé extends pour l'héritage.

IX-D. Classes imbriquées

On peut créer une classe dans une autre classe (sauf si elle est déclarée statique avec le mot clé static, voir chapitre sur les modificateurs). Voici un beau petit exemple :

Image non disponible

Comme une classe ne peut hériter que d'une seule autre classe, on peut créer des classes imbriquées qui vont résoudre le problème. Les classes imbriquées dans vos programmes devront être gérées avec la plus grande attention, car on se mélange facilement les pinceaux ! sans parler des problèmes de portée de variables…
Ce qui nous amène à aborder un nouveau concept : le polymorphisme. Si on appelle une méthode dans une classe, le programme regarde si cette méthode existe (nom + arguments). Si elle existe, elle est exécutée. Si cette méthode n'existe pas, le programme la cherche dans la super-classe de la classe qui fait appel à elle. Et on monte ainsi les niveaux jusqu'à ce qu'une méthode adéquate soit trouvée ou que la « remontée » se termine (dans ce cas, le compilateur générera une erreur). Lorsqu'une méthode définie dans une sous-classe a le même nom ou les mêmes paramètres qu'une méthode d'une des classes ancêtres (super-classe), elle cache la méthode de la classe ancêtre à la sous-classe. Ceci est très important : une méthode de « bas niveau » cache une méthode de « haut niveau » quand on redéfinit son comportement.

IX-E. Classes abstraites

A mesure que l'on remonte dans la hiérarchie des classes, celles-ci deviennent plus générales et souvent plus abstraites. A un certain moment, la classe ancêtre devient tellement générale qu'on la considère surtout comme un moule pour des classes dérivées et non plus comme une véritable classe dotée d'instances. Une classe abstraite définit donc une « ligne de conduite » pour ses méthodes. Elle vous met « sur la voie » pour définir plus précisément votre propre classe. Cette classe abstraite ne peut donc pas être instanciée (adaptée en objet). Elle peur contenir des méthodes abstraites mais ce n'est pas une obligation. Les classes abstraites sont déclarées à l'aide du mot clé abstract.

 
Sélectionnez
public abstract class NomDeLaClasse {&#8230;}

Il est surtout important de retenir qu'il est avantageux de placer le plus de fonctionnalités possible dans une super-classe, abstraite ou non.

IX-F. Importation de classes

On ne va pas s'éterniser là-dessus : vous connaissez la commande import qui permet au début du programme de rendre des classes accessibles. Par exemple pour, dans une applet, travailler avec des images, on importera java.awt.image avec la commande suivante :

 
Sélectionnez
import java.awt.image.*;

IX-G. Les packages JDK les plus utiles

Package Description
java.applet Contient la classe Applet et 3 interfaces. Elles servent d'intermédiaires entre une applet et le navigateur.
java.awt Interface utilisateur issue de Java 1. Également chargement de graphiques, impression, distribution d'éléments graphiques…
java.awt.datatransfer Support du presse-papier (copier/coller…)
java.awt.event Gestionnaire d'événements AWT
java.awt.image Gestion des images
java.beans Gestion des beans
java.io Gestion des entrées/sorties (écriture et lecture de données)
java.lang Contient la classe racine Object, types de données avancés…
java.math Fonctions mathématiques
java.net Client/serveur
java.rmi Modules RMI (Remote Method Invocation) pour invoquer des méthodes à distance
java.security Fonctions de sécurisation des transmissions
java.sql Permet l'accès aux bases de données relationnelles par l'intermédiaire du langage SQL
java.text Formatage des chaînes de texte
java.util Conversions, structures de données, gestion d'événements
javax.swing(le x est volontaire) Tous les composants de l'interface utilisateur SWING de Java 2

issu de Au cœur de Java 2 par Cay S. Horstmann & Gary Cornell aux éditions Sun (Campus Press).

X. Transmission d'arguments : le projet Palindrome

X-A. Introduction

Dans ce chapitre, nous allons transmettre des arguments à un application et à une applet Java, c'est-à-dire leur donner des valeurs, chiffres ou lettres, qu'elles attendent pour leur bonne exécution. Par exemple, le programme doit savoir s'il y a plus ou moins de 100 g de chocolats dans la boîte, il attendra alors un argument spécifié par l'utilisateur. Cet argument est susceptible de changer à chaque exécution du programme, c'est pourquoi il ne peut être directement spécifié dans le code source.
Capter un argument de ligne de commande est pénible en Java, heureusement c'est quasiment inutile car la plupart de vos programmes posséderont une Interface Utilisateur et ne se contenteront pas de s'exécuter dans une fenêtre de ligne de commande (DOS pour Microsoft…) (la procédure pour récupérer un argument à partir d'une IU étant beaucoup plus simple).
Par contre, pour les applets, c'est bien utile et moins compliqué.

X-B. Transmettre un argument à une application

Un argument se transmet à une application à l'exécution :

 
Sélectionnez
// sans transmission d'argument 
java NomDuProgramme 
// avec transmission d'argument 
java NomDuProgramme PremierArgument SecondArgument TroisiemeArgument EtCaetera

On note que les arguments sont séparés d'un espace. Dans le cas d'un argument qui comprend plusieurs mots qui doivent être séparés, on utilise les guillemets : "Federico Garcia Lorca" est considéré comme 1 seul argument.

X-C. Récupérer un argument à partir d'une application

On doit créer une boucle for qui parcourt le programme à la recherche d'arguments :

 
Sélectionnez
//partie théorique 
for( int i = 0 ; i < arguments.length ; i++ ) {&#8230;} 

//partie pratique 
class MesArguments { 
    public static void main(String args[ ]) { 
        for( int i = 0 ; i < arguments.length ; i++ ) { 
            System.out.println ("Arguments " + i + "&#160;: " + arguments[ i ]; 
        } 
    } 
}

Le petit exemple présenté ci-dessus affiche les arguments avec leur numéro. Vous pouvez compiler ce programme, il fonctionne.

X-D. Transmettre un argument à une applet

On transmet un argument à une applet par l'intermédiaire du code HTML :

 
Sélectionnez
<PARAM NAME="*" VALUE="*"> 
<PARAM NAME="font" VALUE="Arial">

Les * symbolisent les valeurs que vous devez spécifier, la première le nom du paramètre et la seconde sa valeur.

X-E. Récupérer un argument à partir d'une applet

Pour récupérer à partir d'une applet les arguments transmis par le HTML, on utilise la méthode getParameter().

 
Sélectionnez
TypeDeDonnée NomDeLaVariable = getParameter ("nomDuParamètre"); 
String theFont = getParameter("font");

X-F. Applet : Palindrome

L'applet Palindrome vient du livre Java 2 plate-forme de Roger Cadenhead et Laura Lemay. Elle récupère et affiche le texte spécifié par …

 
Sélectionnez
<PARAM NAME="palindrome" VALUE="Écrivez ici ce que vous voulez" >
 
Sélectionnez
import java.awt.Graphics; //importation de la classe qui gère les graphismes
import java.awt.Font; // "" qui gère les polices
import java.awt.Color; // "" qui gère les couleurs
public class Palindrome extends java.applet.Applet { // c'est une applet !
    Font f = new Font("TimesRoman", Font.BOLD, 36); // définition de la police f
    String palindrome; // déclaration de la chaîne "palindrome"

    public void paint(Graphics screen) { // méthode qui servira à fixer les paramètres d'affichage
        screen.setFont(f); // attribuer la police f à tous les textes de l'applet
        screen.setColor(Color.red); // "" la couleur rouge
        screen.drawString(palindrome, 5, 50); // écrire le texte contenu dans palindrome aux coordonnées &#8230;
    } 

    public void init() { // équivalent de main() dans les applications: le prog débute
        palindrome = getParameter("palindrome"); // on récupère le paramètre
        if( palindrome == null) // s'il n'y en a pas &#8230;
            palindrome = "Spécifiez un argument, SVP"; // &#8230; afficher ceci
    } 
}
Image non disponible

XI. Les exceptions

XI-A. Définition

La cause du mauvais fonctionnement d'un programme peut être la conséquence de 2 types d'erreurs : une erreur de programmation ou une erreur pendant l'exécution du programme. Si le programmeur commet une erreur de programmation, le programme ne se compilera généralement pas, mais il existe des erreurs de programmation qui surviennent après la compilation, à l'appel de la machine virtuelle par java.exe (pour je JDK 1.2 de Sun). Toutes ces erreurs peuvent et doivent être corrigées par le programmeur. Dans les deux cas précédents, le programme ne démarre pas.
Le second type d'erreur survient pendant l'exécution du programme. Ce sont en quelque sorte des « bogues ». On distingue 2 catégories : les erreurs de la machine virtuelle (vous ne pouvez quasiment rien y faire), et les exceptions que vous devez gérer. Ces exceptions peuvent se produire dans beaucoup de cas, elles ont cependant plus de chance de survenir lors d'un transfert de données. Par exemple, si un programme essaie d'écrire sur un disque plein ou protégé en écriture, une exception de type IOException (input/output ou entrée/sortie de données) sera générée. La gestion de cette exception permettra au programme de ne pas « planter ». Vous pouvez spécifier ce que le programme doit faire lors de l'apparition d'exceptions.

XI-B. try…catch

try…catch peut être expliqué comme : « essaye ce bout de code (try), si une exception survient, attrape-la (catch) et exécute le code de remplacement (s'il y en a un) ».

 
Sélectionnez
try{ 
    //code susceptible de produire des exceptions 
}  catch(Exception e) { 
    // code de remplacement, se limite souvent à un System.out.println(&#8220;Une erreur&#160;: &#8220;+e); 
}
Image non disponible

Exception est la super-classe de toutes les exceptions, elle capte toutes les exceptions. Elle fonctionne dans tous les cas, cependant il est préférable de bien canaliser l'exception en spécifiant le type d'exception le plus précis possible (voir le schéma ci-dessus). On doit spécifier un nom à cette exception créée, ici c'est e, on choisit généralement e ou ex. Vous pouvez, en raison de la portée de variables, spécifier le même nom pour toutes vos exceptions (ce nom n'est reconnu qu'à l'intérieur de catch).

XI-C. Finally

La clause finally permet d'exécuter le code qu'elle renferme quoiqu'il arrive. Qu'il y ait une exception ou pas, les instructions de la clause finally sont exécutées. Elle fonctionne également avec try.

 
Sélectionnez
try{ 
    // instructions à essayer de réaliser 
    return; 
}  finally{ 
    // instructions à réaliser absolument 
} 
return;

XI-D. Déclarer des méthodes susceptibles de générer des exceptions

On utilise la clause throws dans la déclaration de méthode. Exemples :

 
Sélectionnez
public boolean myMethod (xxx) throwsAnException {&#8230;} 
public boolean myMethod (xxx) throwsAnException, ASecondException, AThirdException {&#8230;} 
public void myMethod() throwsIOException {&#8230;}

XI-E. Générer des exceptions

Ceci sert à faire croire au programme qu'une exception d'un certain type est apparue.

 
Sélectionnez
NotInServiceException nis = new NotInServiceException("Exception&#160;: DataBase out of use"); 
throw nis;

On note qu'il s'agit de throw et pas de throws.

XI-F. Créer des exceptions

Dans des programmes complexes, il se peut que les exceptions standard de Java ne soient pas suffisantes et que vous ayez par conséquent besoin de créer vos propres définitions. Dans ce cas, vos exceptions devront hériter d'une exception plus haute dans la hiérarchie.

 
Sélectionnez
public class SunSpotException extends Exception {
    public SunSpotException () {}
    public SunSpotException(String msg) {
        super(msg);
    }
}

XI-G. En Pratique

Au début, vous ne saurez pas quand utiliser ou ne pas utiliser les exceptions. Les automatismes viennent avec la pratique… Il faut savoir que les exceptions ralentissent les programmes, n'en usez donc pas trop souvent… De toute façon, le compilateur générera un message d'erreur si à un endroit vous avez oublié d'intercepter une exception, et en plus, il vous indiquera quelle exception vous devez intercepter !

Image non disponible

XII. Applets : quelques généralités

XII-A. Introduction

Ce chapitre présente des généralités sur les applets (principalement les méthodes d'une applet). Mais, d'abord, il faut expliquer ce qu'est une applet : une applet est un programme qui définit automatiquement (sans action du programmeur ni de l'utilisateur) une zone graphique dans laquelle le programme s'exécute. Une applet est exécutable par l'intermédiaire de la machine virtuelle d'un navigateur Web. Elle doit donc être insérée dans une page HTML.

XII-B. Restrictions

On dit souvent que Java ne permet pas de lire ou d'écrire sur un disque dur. C'est faux. Les applets exécutées par les navigateurs comme IE5 ou Communicator 4.7 subissent des restrictions dans la mesure ou certaines des potentialités de JAVA ne sont pas prises en compte par défaut. L'utilisateur doit l'accepter (en validant manuellement dans une boîte de dialogue) pour que ces fonctionnalités soient disponibles. Ceci permet notamment de garantir une certaine sécurité. Ainsi, par défaut les applets ne peuvent pas lire/écrire sur un disque dur, un serveur autre que celui où elles sont stockées (elle ne peuvent donc pas avoir accès à vos programmes ou formater votre disque ;-) sauf si vous les y autorisez). Un système de signature numérique a été mis en place pour les applets nécessitant des niveaux de liberté supérieurs à celui par défaut. Vous pouvez obtenir ces certificats auprès d'entreprises comme VerySign et signer vos archives jar. Enfin, tout ceci concerne uniquement les applets et nullement les applications.

XII-C. Création d'une applet

La classe principale doit étendre la classe Applet. Les importations de classes se font comme pour les applications. Il n'y a pas de méthode main().

 
Sélectionnez
public class * extends java.applet.Applet {&#8230;}  // création d'applet Java 1.1 et antérieur
public class * extends Japplet {&#8230;}  // création d'applet Java 2

XII-D. Méthodes d'une applet

XII-D-1. Initialiser

 
Sélectionnez
public void init() {&#8230;}

XII-D-2. Démarrer

 
Sélectionnez
public void start() {&#8230;}

XII-D-3. Arrêter

 
Sélectionnez
public void stop() {&#8230;}

XII-D-4. Dessiner (et écrire)

 
Sélectionnez
public void paint(Graphics g) {&#8230;}

XIII. Applets : classes Graphics : le projet Floride

Il est possible de télécharger les sources du programme.

XIII-A. Introduction

Ce chapitre présente les rudiments graphiques disponibles pour une applet. Nous verrons comment dessiner des lignes, rectangles, ovales, arcs de cercle, chaînes de texte… Avant de commencer, il faut savoir qu'une applet est en gros une application exécutée par l'intermédiaire d'un navigateur web, qui définit automatiquement un cadre de travail. Les dimensions de ce cadre sont définis par le code HTML accompagnant l'applet. La plupart de ces procédés appartiennent à Java 1.1. Dans Java 2, on a une classe Graphics2D beaucoup plus performante, mais dans la mesure où elle n'est pas utilisable pour les applets destinées à IE5 ou Netscape 4.7, la classe Graphics vous sera bien utile pour des graphiques simples.

XIII-B. Système de coordonnées

On place des éléments dans le cadre d'une applet en définissant leur position par des coordonnées. Le repère a pour origine le point le plus en haut et le plus à gauche du cadre.

XIII-C. Segments de droites

Pour tracer le segment de droite [AB], on utilise la commande drawLine(xA,yA,xB,yB).

Image non disponible

XIII-D. Rectangles

Il existe 4 types de rectangles : rectangle aux angles droits vide ou plein, rectangle aux angles arrondis vide ou plein.

 
Sélectionnez
drawRect(x,y,L,h); //
fillRect(x,y,L,h);
drawRoundRect(x,y,L,h,&#946;,&#955;);
fillRoundRect(x,y,L,h, &#946;,&#955;);

(x,y) sont les coordonnées de l'angle supérieur gauche du rectangle.
L et h sont la largeur et la hauteur du rectangle.
β et λ sont les valeurs de largeur et de hauteur de l'angle.

Image non disponible

XIII-E. Polygones

Les polygones sont des ensembles de segments de droites joints. Il y a 2 types de polygones : les vides et les pleins (comme les rectangles). On peut les construire de 2 manières : soit en définissant manuellement tous les segments qui définissent le polygone soit en créant une matrice de coordonnées x et une autre de y.

 
Sélectionnez
polygon(int[], int[], int);

Le 3e entier représente le nombre de points du polygone. Un petit exemple (pas tout à fait fonctionnel) :

 
Sélectionnez
int x[] = {10, 20, 30, 40, 50}; 
int y[] = {50, 60, 70, 80, 90}; 
int points = x.length; 
Polygon poly = new Polygon(x, y, points); 
*.drawPolygon(poly);

L'astérisque peut changer de valeur, on trouve souvent screen ou g. Nous verrons cela plus tard.

XIII-F. Ovales

Soient (x,y) les coordonnées du point supérieur gauche,

 
Sélectionnez
drawOval(x,y,largeur,hauteur); 
fillOval();

XIII-G. Arcs de cercle

Là, il faut un schéma…

 
Sélectionnez
drawArc(x,y,largeur,hauteur,angle,nombreDeDegres); 
fillArc();
Image non disponible

(x,y) les coordonnées du point haut gauche
angle = l'angle à partir duquel l'arc commence (ici, 90°)
nombreDeDegres = nombre de degrés que parcourt l'arc (ici, 180°)

XIII-H. Copier/Couper

Ce n'est pas vraiment un copier/coller mais on peut s'en servir comme… Ces commandes copient ou coupent une zone rectangulaire.

 
Sélectionnez
copyArea();
clearRect();

XIII-I. Texte et polices

Pour écrire du texte, on utilise la commande drawString(texte, x, y). On peut mettre une police en état normal, italique, ou gras :

 
Sélectionnez
Font.PLAIN ; //état normal
Font.BOLD ; // état gras
Font.ITALIC ; // état italique

Un petit exemple (encore pas tout à fait fonctionnel) :

 
Sélectionnez
Font f = new Font ("TimesRoman", Font.BOLD + Font.ITALIC, 24) ; // 24 est la taille
Screen.setFont(f) ; 
Screen.drawString("Bonjour !", 30, 30);

Pour obtenir des informations sur du texte :

 
Sélectionnez
stringWidth(String) // largeur totale de la chaîne
charWidth(char) // largeur du caractère
getHeight // hauteur de la police

XIII-J. Applet : Floride

 
Sélectionnez
import java.awt.Graphics; 
import java.awt.Polygon; 

public class Floride extends java.applet.Applet { 
    public void paint(Graphics screen) { 
        screen.drawString("Florida", 185, 75); 
        screen.drawLine(185,80,222,80); 
        screen.drawRect(2, 2, 345, 345); 
        screen.drawRoundRect(182,61,43,24,10,8); 
        int x[] = { 10, 234, 253, 261, 344, 336, 295, 259, 205, 211, 
            195, 191, 120, 94, 81, 12, 10}; 
        int y[] = { 12, 15, 25, 71, 209, 278, 310, 274, 188, 171, 174, 
            118, 56, 68, 49, 37, 12}; 
        int pts = x.length; 
        Polygon poly = new Polygon(x, y, pts); 
        screen.drawPolygon(poly); 
        screen.fillOval(235,140,15,15); 
        screen.fillOval(225,130,15,15); 
        screen.fillOval(245,130,15,15); 
        for(int ax = 50; ax < 150; ax += 10) 
            for(int ay = 120; ay < 320; ay += 10) 
                screen.drawArc(ax, ay, 10, 10, 0, -180); 
    } 
}

Une petite explication : les codes de ce chapitre n'étaient pas fonctionnels car ils n'étaient pas dans la méthode paint() de l'applet. Ici la méthode paint est déclarée avec l'objet Graphics nommé screen, on aurait pu l'appeler g. screen. g.screen doit être mis avant chaque instruction qui trace une ligne ou une chaîne. Le fichier class généré par la compilation doit être lancé par l'intermédiaire d'un navigateur compatible Java 2 (disons que l'appletviewer et toujours la meilleure alternative), avec le code HTML suivant :

 
Sélectionnez
<body bgcolor="#c4c4c4"> 
    <div align="center"> 
        <applet code="Floride.class" height=350 width=350> 
        </applet> 
    </div> 
</body>

Cet exemple est tiré de l'excellent livre JAVA 2 de Roger Cadenhead & Laura Lemay aux éditions Campus Press (titre original : Teach yourself Java in 21 days).

Image non disponible

XIV. Applets : Java2D (Graphics2D) : le projet Floride2D

Il est possible de télécharger les sources du programme.

XIV-A. Introduction

En Java 2, Java2D remplace les classes Graphics de Java 1. Java2D est plus performant et gère les couleurs.

XIV-B. Convertir un objet en 2D

Pour créer des graphiques avec Java 2D, on déclare la méthode paint() de l'applet comme avant, mais dans les instructions qui accompagnent cette méthode, on doit convertir l'objet Graphics en objet Graphics2D.

 
Sélectionnez
public void paint (Graphics screen) { 
    Graphics2D screen2D = (Graphics2D) screen; 
    // suite des instructions 
}

XIV-C. Couleurs

Pour colorer quelque chose, on doit d'abord créer un objet Color et ensuite attribuer cet objet à la chose que l'on veut colorer.

 
Sélectionnez
Color c1 = new Color(0.807F, 1F, 0F) ; // nombres à virgule flottante
Color c2 = new Color(255, 204, 102); // nombres normaux
screen2D.setColor(Color.yellow); // couleur basique prédéfinie

La 3e instruction indique que toutes les opérations de dessin se feront dans la couleur définie (ici, le jaune). Pour modifier les couleurs de fond d'écran (background) et de dessin (foreground), on utilise ces méthodes :

 
Sélectionnez
setBackground(Color.white); 
setForeground(Color.black);

Voici un tableau avec les principales couleurs :

Nom de la couleur en Java Valeur RVB En français
black (0,0,0) Noir
blue (0,0,255) Bleu
cyan (0,255,255) Cyan (bleu primaire)
darkGray (64,64,64) Gris foncé
gray (128,128,128) Gris
green (0,255,0) Vert
lightGray (192,192,192) Gris clair
magenta (255,0,255) Magenta (rouge primaire)
orange (255,200,0) Orangé
pink (255,175,175) Rose
red (255,0,0) Rouge (scarlet)
white (255,255,255) Blanc
yellow (255,255,0) Jaune

Les couleurs RVB représentent les valeurs entre 0 et 255 de rouge, vert et bleu. En fonction de leur concentration, les couleurs se nuancent. La capture d'écran de Macromedia Freehand illustre le choix d'une couleur Camel (189,156,82).

Image non disponible

XIV-D. Dégradés de couleurs

Le titre est très parlant…

 
Sélectionnez
GradientPaint(x1,y1,Color1,x2,y2,Color2,boolean);

x1,x2 et Color1 représentent les coordonnées et la couleur du point de départ du dégradé.
x2,y2 et Color2 représentent les coordonnées et la couleur du point d'arrivée du dégradé.
boolean est true si le dégradé est cyclique, sinon, il n'est pas nécessaire de le préciser.

XIV-E. Définir un type de trait

Une des nouveautés de Java2D est la possibilité de faire de beaux traits. Ce qui est beau, ce sont les extrémités ou les raccord entre 2 traits.

Image non disponible

Traits :

  • CAP_BUT
  • CAP_SQUARE
  • CAP_ROUND

Jointures

  • JOIN_MITER
  • JOIN_ROUND
  • JOIN_BEVEL

Vous remarquerez qu'il existe une différence de longueur entre les traits 1 et 2. C'est l'unique différence entre CAP_BUT (le classique) et CAP_SQUARE.

Pour créer un trait, il faut utiliser la méthode setStroke() de l'objet BasicStroke(). Elle admet 3 arguments :

  • Valeur float pour la largeur de la ligne (en pixel).
  • Valeur int pour le style d'ornement, extrémité de ligne.
  • Valeur int pour le style d'ornement, jonction entre 2 lignes.
 
Sélectionnez
BasicStroke pen = BasicStroke (2.0f, 
        BasicStroke.CAP_BATT, 
        BasicStroke.JOIN_ROUND); 
screen2D.setStroke(pen);

XIV-F. Créer des objets à dessiner

Les arguments sont les mêmes que pour des objets classiques (allez donc voir le chapitre Graphics pour plus d'informations). Tous ces objets font partie de java.awt.geom.

Lignes :

 
Sélectionnez
Lines2D.Float ligne = new Line2D.Float();

Rectangles :

 
Sélectionnez
Rectangle2D.Float rectangle = new Rectangle2D.Float();

Ellipses :

 
Sélectionnez
Ellipse2D.Float ellipse = new Ellipse2D.Float();

Arcs :

 
Sélectionnez
Arcs2D.Float = new Arc2D.Float(&#8230;&#8230;.Arc2D.OPEN);
  • Arc2D.OPEN
  • Arc2D.CHORD
  • Arc2D.PIE

Polygones :

 
Sélectionnez
GeneralPath polly = new GeneralPath(); // création d'un "chemin" encore "vide"
polly.moveTo(5f,0f); // premier trait
polly.moveTo(205f,0f); // deuxième trait
polly.moveTo(5f,90f); // troisième trait 
polly.closePath(); // on referme automatiquement par un quatrième "plus court possible" trait

XIV-G. Applet Floride2D

Cette applet est une amélioration de Floride présentée au chapitre précédent. Bien sûr, elle fait également partie de l'excellent livre Java 2 Plate-Forme de Roger Cadenhead et Laura Lemay aux éditions CampusPress.

 
Sélectionnez
import java.awt.*; 
import java.awt.geom.*; 

public class Floride2D extends java.applet.Applet { 
    public void paint(Graphics screen) { 
        Graphics2D screen2D = (Graphics2D)screen; 
        setBackground(Color.blue); 

        // dessine les vagues
        screen2D.setColor(Color.white); 
        BasicStroke pen = new BasicStroke(2F, 
                BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND); 
        screen2D.setStroke(pen); 
        for (int ax = 10; ax < 340; ax += 10) 
            for(int ay = 30; ay < 340; ay += 10) { 
                Arc2D.Float wave = new Arc2D.Float(ax, ay, 
                        10, 10, 0, 180, Arc2D.OPEN); 
                screen2D.draw(wave); 
            } 

        // dessine la Floride
        GradientPaint gp = new GradientPaint(0F,0F,Color.green, 
                50F,50F,Color.orange,true); 
        screen2D.setPaint(gp); 
        GeneralPath fl = new GeneralPath(); 
        fl.moveTo(10F,12F); 
        fl.lineTo(234F,15F); 
        fl.lineTo(253F,25F); 
        fl.lineTo(261F,71F); 
        fl.lineTo(344F,209F); 
        fl.lineTo(336F,278F); 
        fl.lineTo(295F,310F); 
        fl.lineTo(259F,274F); 
        fl.lineTo(205F,188F); 
        fl.lineTo(211F,171F); 
        fl.lineTo(195F,174F); 
        fl.lineTo(191F,118F); 
        fl.lineTo(120F,56F); 
        fl.lineTo(94F,68F); 
        fl.lineTo(81F,49F); 
        fl.lineTo(12F,37F); 
        fl.closePath(); 
        screen2D.fill(fl); 

        // dessine les ovales
        screen2D.setColor(Color.black); 
        BasicStroke pen2 = new BasicStroke(); 
        screen2D.setStroke(pen2); 
        Ellipse2D.Float e1 = new Ellipse2D.Float(235,140,15,15); 
        Ellipse2D.Float e2 = new Ellipse2D.Float(225,130,15,15); 
        Ellipse2D.Float e3 = new Ellipse2D.Float(245,130,15,15); 
        screen2D.fill(e1); 
        screen2D.fill(e2); 
        screen2D.fill(e3); 
    } 
}

Ce code HTML est à joindre :

 
Sélectionnez
<applet code="Floride2D.class" height=370 width=350> 
</applet>

Et voilà !

Image non disponible

XV. Les Modificateurs

XV-A. Définition

Les modificateurs sont des mots clé qui permettent de définir l'accessibilité de méthodes, variables ou classes dans le programme dans lequel ils sont utilisés ou dans d'autres programmes ayant une interaction avec le programme dans lequel ils sont utilisés (héritage…).

XV-B. Accessibilité

En Java, il y a 4 niveaux de restriction d'accessibilité : public, protected, par défaut, private (du moins au plus restrictif).

XV-B-1. Public

Les méthodes et les variables sont accessibles (et modifiables pour les variables) par n'importe quelle classe.

XV-B-2. Protected

Limite l'accès aux sous-classes de la classe ou aux autres classes du même package ; les autres ne peuvent pas y accéder.

XV-B-3. Par défaut

Pareil à protected sauf l'accès par une sous classe d'un package différent qui est restreint.

XV-B-4. Private

Les méthodes et variables déclarées ne sont visibles qu'à l'intérieur de leur propre classe.

XV-C. Résumé

Image non disponible

XV-D. D'autres modificateurs

Sur un point, la définition proposée plus haut est fausse : les modificateurs ne font pas que modifier l'accessibilité. Ils modifient en général les propriétés des classes, méthodes et variables. Certains doivent vous être familiers :

XVI. Insérer des sons dans un programme (exemple pour une applet)

Il est possible de télécharger les sources du programme.

XVI-A. Introduction

Destinées au web, les applets sont le plus souvent utiles de part leurs fonctionnalités multimédia. Nous allons voir dans ce chapitre comment jouer un son dans une applet. Ce cours n'a pas beaucoup de points techniques, c'est plutôt une « recette ».

XVI-B. Accéder aux fichiers

Les fichiers de sons lisibles par la JVM sont au format AIFF, WAV, AU, RMF, MIDI(1 et 2). Sous les versions antérieures à Java 2, seul le format AU était supporté.

L'accès aux fichiers se fait grâce à l'appel d'une URL :

 
Sélectionnez
AudioClip clip = getAudioClip(getCodeBase(), "*.*") ; // pour applets
AudioClip clip = new AudioClip("*.*); // pour applications

Les *.* représentent le nom du fichier et son extension. (ex : « son.wav »).

Sur les clips audio, on peut appeler les méthodes suivantes : play(), stop(), loop().

XVI-C. Exemple concret

Cet exemple est tiré du grand livre JAVA 2 plate-forme de Roger Cadenhead & Laura Lemay ed. Campus Press

 
Sélectionnez
// importation des classes nécessaires à la lecture des sons
import java.awt.Graphics; 
import java.applet.AudioClip; 

public class AudioLoop extends java.applet.Applet implements Runnable { // voir chapitre sur les Threads

    // création des 2 objets AudioClip 
    AudioClip bgSound; 
    AudioClip beep; 
    Thread runner; 

    // voir le chapitre sur les Threads
    public void start() { 
        if(runner == null) { 
            runner = newThread(this); 
            runner.start(); 
        } 
    } 

    // l'applet s'arrête arrêt de tous les sons en cours de lecture 
    public void stop() { 
        if(runner != null) { 
            if(bgSound != null) 
                bgSound.stop(); 
            runner = null; 
        } 
    } 

    // initialisation de l'applet 
    public void init() { 
        // on indique quels sont les fichiers à lire
        bgSound = getAudioClip(getCodeBase(),"loop.au"); 
        beep = getAudioClip(getCodeBase(), "beep.au"); 
    } 
    
    // l'applet débute 
    public void run() { 
        if(bgSound != null) // le fichier loop.au n'est pas en cours de lecture&#8230; 
            bgSound.loop(); // &#8230; alors, il est lu en boucle
        Thread thisThread = Thread.currentThread(); 
        while(runner == thisThread) { 
            try{ 
                Thread.sleep(5000); // 5 secondes d'arrêt du programme
            } catch(InterruptedException e) { } 
            if(beep != null) // si le fichier beep.au n'est pas en cours de 
                //lecture&#8230;
                beep.play(); // &#8230; le lire
        } 
    } 

    // méthode d'affichage du texte accompagnant la lecture des sons 
    public void paint(Graphics screen) { 
        screen.drawString("Playing Sounds &#8230;", 10, 10); 
    } 
}

Les 2 fichiers sonores sont disponibles à l'adresse suivante : http://perso.wanadoo.fr/guillaume/Exemples/AudioLoop/

A insérer accompagné du HTML suivant :

 
Sélectionnez
<applet code="AudioLoop.class" height=100 width=200> 
</applet>

Pas d'image… c'est du son !

XVII. Animations (exemple pour une applet)

Il est possible de télécharger les sources du programme.

XVII-A. Introduction

Ce chapitre a pour but de montrer comment créer des séquences animées et surtout comment réduire l'effet de vacillement présent dans certaines animations. Pour créer une animation, on affichera une suite d'images à grande vitesse (méthode de création des GIF animés). Pour cela, il faudra utiliser les threads (voir chapitre sur les Threads pour plus de renseignements), les méthodes de dessin Graphics de l'applet, les méthodes de l'applet (init(), update()…) et la mise en mémoire tampon.

XVII-B. Réduire les vacillements

Pour créer une animation, il suffit donc d'afficher une première image, de l'effacer, d'afficher une seconde, de l'effacer, d'en afficher une troisième et de l'effacer et ainsi de suite à très grande vitesse. Se pose alors le problème du rafraîchissement de l'écran : Java va redessiner toute la zone de l'applet, ce qui nous donne une impression d'affichage saccadé. Pour résoudre ce problème, on peut avoir recours à deux méthodes : utiliser la méthode repaint() (synthèse de paint() et de update()) en le redéfinissant pour qu'elle n'efface que les zones concernées par le changement. Cette solution est lourde et incommode. La seconde solution consiste à redéfinir paint() et update() en utilisant une double mise en mémoire tampon (Double-buffering), les images et seulement les images seront stockées en mémoire tampon, ensuite on affichera cette mémoire tampon (donc seulement les images et pas le reste du cadre).

XVII-C. 1e méthode

A tout hasard, voici une redéfinition de update() :

 
Sélectionnez
public void update(Graphics g) { 
    g.setColor(getBackground()) ; 
    g.fillRect(0,0,size().width, size().height); 
    g.setColor(getForeground()); 
    paint(g); 
} 

public void update(Graphics screen) { // utilisation de la méthode précédemment définie
    paint(screen); 
}

XVII-D. 2e méthode

  • Créer des variables d'instance pour stocker les images ;
  • créer les images et le contexte graphique au moment d'initialisation de l'applet ;
  • effectuer les opérations de dessin dans le tampon ;
  • dessiner le tampon à l'écran à la fin de la méthode paint().
 
Sélectionnez
// 1
Images offScrenImage ;
Graphics offScreen ;
// 2
offScreenImage = createImage(size().width, size().height);
offscreen = offscreenImage.getGraphics();
// 3
offscreen.drawImage(bug, 10, 10, this);
screen.drawImage(offscrenImage, 0, 0, this);
// 4
public void update(Graphics g) {
    paint(g);
}

XVII-E. Application : applet Neko

L'applet Neko est issue de JAVA 2 le programmeur par Roger Cadenhead et Laura Lemay aux éditions Campus Press, elle représente un petit chat parcourant la fenêtre de l'applet. La technique utilisée est celle des threads. La technique du programme est simple : pour chaque action du chat on écrit une méthode qui appelle l'image correspondante un certain nombre de fois. On spécifie ensuite ce nombre en fonction de la durée de l'animation.

 
Sélectionnez
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.Color; 

public class Neko extends java.applet.Applet 
        implements Runnable { // nécessaire pour les threads 

    Image nekoPics[] = newImage[9]; // matrice d'images
    Image currentImg; // image courante
    Thread runner; // déclaration du thread
    int x; // abscisse de l'image
    int y = 50; // son ordonnée

    public void init() { // initialisation de l'applet
        String nekoSrc[] = { "right1.gif", "right2.gif", 
                "stop.gif", "yawn.gif", "scratch1.gif", 
                "scratch2.gif","sleep1.gif", "sleep2.gif", 
                "awake.gif"}; // on remplit la matrice avec les images
        for(int i=0; i < nekoPics.length; i++) { 
            nekoPics[i] = getImage(getCodeBase(), 
                    "images/"+ nekoSrc[i]); 
        } 
    } 

    public void start() { //méthode start de l'applet, opérations sur les threads
        if(runner == null) { 
            runner = newThread(this); 
            runner.start(); 
        } 
    } 

    public void stop() { // comment arrêter l'animation
        runner = null; 
    } 

    public void run() { // lancer l'applet
        setBackground(Color.white); 
        // part d'un côté de l'écran vers le milieu
        nekoRun(0, size().width / 2); 
        // pause
        currentImg = nekoPics[2]; 
        repaint(); 
        pause(1000); 
        // baille 3 fois
        currentImg = nekoPics[3]; 
        repaint(); 
        pause(1000); 
        // se gratte 4 fois
        nekoScratch(4); 
        // dort 5 "temps"
        nekoSleep(5); 
        // se réveille et s'en va
        currentImg = nekoPics[8]; 
        repaint(); 
        pause(500); 
        nekoRun(x, size().width + 10); 
    } 

    void nekoRun(int start, int end) { // méthode qui permet d'exécuter les 
        //mouvements
        // définis précédemment ici: courir et bailler)
        for(int i = start; i < end; i += 10) { 
            x = i; 
            // images pour le bâillement
            if(currentImg == nekoPics[0]) 
                currentImg = nekoPics[1]; 
            else currentImg = nekoPics[0]; 
            repaint(); 
            pause(150); 
        } 
    } 

    void nekoScratch(int numTimes) { // pour se gratter&#8230;
        for(int i = numTimes; i > 0; i--) { 
            currentImg = nekoPics[4]; 
            repaint(); 
            pause(150); 
            currentImg = nekoPics[5]; 
            repaint(); 
            pause(150); 
        } 
    } 

    void nekoSleep(int numTimes) { // &#8230; dormir
        for(int i = numTimes; i > 0; i--) { 
            currentImg = nekoPics[6]; 
            repaint(); 
            pause(250); 
            currentImg = nekoPics[7]; 
            repaint(); 
            pause(250); 
        } 
    } 

    void pause(int time) { // une pause dans l'animation
        try{ 
            Thread.sleep(time); 
        } catch(InterruptedException e) { } 
    } 

    public void paint(Graphics screen) { // affichage de l'animation
        if(currentImg != null) 
            screen.drawImage(currentImg, x, y, this); 
    } 
}
 
Sélectionnez
<applet code="Neko.class" width=300 height=200> 
</applet>

XVIII. AWT - Interface Utilisateur

XVIII-A. Introduction

AWT (Abstract Windowing Toolkit) est une série de classes Java permettant de construire une interface utilisateur (UI en anglais ou IU). AWT fut la première UI de Java, elle est maintenant largement remplacée par Swing (sauf pour les applets car Swing est une nouveauté de Java 2). Une interface utilisateur se compose principalement de :

  • une fenêtre de travail ;
  • une zone où afficher les composants, dans cette fenêtre de travail ;
  • une mise en page des composants (en ligne, en colonne…) ;
  • des composants insérés dans cette fenêtre (boutons, cases à cocher, menus, barre de tâches…) ;
  • des gestionnaires d'événements qui répondent par un comportement particulier aux actions de l'utilisateur.

Tout ceci est un peu compliqué à première vue et il peut paraître maladroit de dire qu'il faut définir une mise en page des composants avant de dire qu'il faut des composants, mais en Java, les opérations se font généralement dans cet ordre.
Dans la mesure où AWT est utilisé majoritairement pour les applets, vous n'aurez le plus souvent pas à vous occuper de la création de la fenêtre de travail (il s'agit du navigateur) ni de la zone d'affichage des composants (il s'agit de l'applet elle-même). Ces 2 étapes sont cependant nécessaires à l'utilisation d'une UI dans une application.
Nous commencerons par étudier les composants, puis leur mise en page, car même si ces opérations sont inversées en programmation, il est plus facile de les concevoir dans cet ordre, et finalement les cadres…

XVIII-B. Les Composants

La bibliothèque de composants AWT est assez limitée, Swing la complète. Nous ne verrons donc que les composants « classiques ».

Image non disponible

XVIII-B-1. Boutons

Il n'y a pas beaucoup d'explications à donner sur un bouton…

 
Sélectionnez
Button leNomDuBouton = new Button("Texte du bouton ici !"); 
add(leNomDuBouton);

XVIII-B-2. Label

Un label est une zone d'affichage d'un texte. C'est le programmeur qui définit le texte et l'utilisateur ne peut pas le changer.

 
Sélectionnez
label() // un label tout simple (et vide) 
label(String) // la chaîne String représente le texte à afficher dans ce label
label(String, int) // int peut être label.RIGHT, label.CENTER ou label.LEFT, ce qui détermine 
// le texte devra être affiché dans le label.

Pour le créer :

 
Sélectionnez
label leNomDuLabel = new label("Bonjour! ", label.######); 
add(leNomDuLabel); 
leNomDuLabel.setText("Zoubida !!!!!!!!!!! ");

Note : pour insérer un composant, la méthode est toujours la même, elle ne sera donc par répétée.

On peut utiliser la méthode setText()pour redéfinir le texte du label (par exemple en résultat d'une action de l'utilisateur)

XVIII-B-3. Cases à cocher

On coche une case pour valider l'option correspondante. On peut cocher toutes les cases, certaines, ou aucune.

 
Sélectionnez
Checkbox() // case toute simple
Checkbox(String) // String est le libellé de la case

// Méthode à appeler sur un Checkbox pour cocher par défaut une option&#160;: 
setState(boolean)

XVIII-B-4. Boutons Radio

Les boutons radio sont des sortes de cases, on ne peut cocher qu'une seule case dans tout le groupe.
Un exemple :

 
Sélectionnez
CheckboxGroup p = new CheckboxGroup(); 
Checkbox p1 = new Checkbox("Manger", p, true); 
Checkbox p2 = new Checkbox("Boire", p, false); 
// On rattache chaque bouton radio à un groupe, dans ce groupe, un seul est sélectionnable. 
// p1 est cochée par défaut (boolean = true)

XVIII-B-5. Listes de choix

Les listes de choix sont des menus déroulants, on ne peut sélectionner qu'une seule option.

 
Sélectionnez
Choice c = new Choice() ; // création du menu
c.addItem("Bonjour! "); // ajout d'une entrée avec Java 1.02
c.add("Au revoir!"); // ajout d'une entrée avec Java 2

Voici les méthodes que l'on peut employer avec Choice :

 
Sélectionnez
getItem(int) // renvoie le numéro de la case sélectionnée par l'utilisateur
countItems() // renvoie le nombre ce cases, pour Java 2
getItemsCount() // même chose pour Java 1.02
getSelectedItem() // renvoie la position de l'objet sélectionné 
Select(int) // sélectionne l'élément n°x
Select(String) // sélectionne l'élément ayant le nom indiqué par String

XVIII-B-6. Champs de texte

Ceci devient intéressant : ce composant permet de capturer un texte (court) entrépar l'utilisateur.

 
Sélectionnez
TextField() // vide
TextField(int) // spécifie la largeur (déconseillé en Java 2)
TextField(String) // la chaîne entrée dans le TextField
TextField(String, int) // les 2 combinés

Méthodes utiles :

 
Sélectionnez
getText() // retourne le texte contenu dans le champ
setText() // définit un texte
setEditable(boolean) // définit si l'utilisateur peut éditer le texte du champ, true = il peut
isEditable() // indique si le champ est éditable (retourne un boolean)
setEchoCharacter('*') // remplace les caractères tapés par une *, pour Java 1.02
setEchoChar() // même chose pour Java 2

XVIII-B-7. Zones de texte

Ce sont de grands champs de texte permettant à l'utilisateur de raconter sa vie ;-).
Les méthodes sont les mêmes que celles du champ de texte (sauf setEchoChar()).

 
Sélectionnez
TextArea() // tout simple
TextArea(int, int) // nombre de lignes et largeur d'une ligne
TextArea(String) // avec une valeur de départ &#8230;
TextArea(String, int, int) // les 2 combinés

XVIII-B-8. Listes à défilement

Ce sont des listes de choix dans lesquelles on peut sélectionner plusieurs entrées.

 
Sélectionnez
List() 
List(int, boolean) // nombre d'entrées visibles en même temps, si plusieurs éléments peuvent 
//être sélectionnés (true), ou non (false)

XVIII-B-9. Barres de défilement

Elles permettent de « scroller » ou de faire défiler le texte pour voir le bas d'une page (les barres à droite dans les traitements de texte, par exemple).

 
Sélectionnez
ScrollBar(int, int, int, int, int)

Dans l'ordre, les int correspondent à :

  • l'orientation : Scrollbar.VERTICAL ou Scrollbar.HORIZONTAL ;
  • valeur initiale du niveau de la barre de défilement ;
  • largeur globale du curseur, 0 = valeur de départ ;
  • valeur minimale de la barre ;
  • valeur maximale de la barre.

XVIII-C. Layouts

Il existe plusieurs types de layout qui correspondent à différentes techniques de disposition des composants. AWT possède par défaut 5 layouts : FlowLayout, GridLayout, BorderLayout, CardLayout, GridBagLayout. Si vous utilisez une IDE de développement graphique comme Borland JBuilder, Symantec VisualCafé ou IBM VisualAge, vous rencontrerez de nouveaux layouts, plus performants que ceux fournis par défaut. Ils possèdent cependant plusieurs défauts : premièrement il faut que l'utilisateur possède le package duquel est issu le layout. Deuxièmement, les proportions dans le placement des composants ne sont souvent pas conservées lors du redimensionnement de la fenêtre. Par exemple, un XYLayout spécifie les coordonnées du composant dans un cadre, si ce cadre est redimensionné, les proportions ne sont pas gardées ; alors qu'elles sont conservées avec un layout qui placerait un composant à 50% par rapport à la hauteur de la fenêtre et 40% en fonction de sa largeur.

XVIII-C-1. FlowLayout

Ce layout dispose tous les composants à la suite, en ligne, de gauche à droite.

 
Sélectionnez
FlowLayout flow = new FlowLayout(FlowLayout.LEFT) ; 
setLayout(flow);
Image non disponible

XVIII-C-2. GridLayout

GridLayout dispose les composants à la suite, sur 1 seule ligne.

 
Sélectionnez
BridLayout grid = new GridLayout(a,b,c,d) ; 
SetLayout(grid); 
// a = nombre de lignes 
// b = nombre de colones 
// c = espacement horizontal 
// d = espacement vertical
Image non disponible

XVIII-C-3. BorderLayout

Ce layout dispose les éléments en 5 parties : Nord, Sud, Est, Ouest, Centre.

 
Sélectionnez
BorderLayout bd = new BorderLayout(a,b) ; 
setLayout(bd); 
// a = espacement horizontal 
// b = espacement vertical
Button b = new Button("BBBB!"); 
add("NORTH", b); 
// Au choix: NORTH, SOUTH, EAST, WEST, CENTER
Image non disponible

XVIII-C-4. CardLayout

C'est un layout un peu particulier : « à onglets ».

XVIII-C-5. GridBagLayout

C'est le plus intéressant des layouts proposés par AWT. Il est cependant plus compliqué d'utilisation.

  • Concevoir une grille, placer au moins 1 élément par case (1 élément peut prendre plusieurs cases.)
    Numéroter cette grille selon le schéma suivant :
    Image non disponible
  • Créer la méthode buildConstraints() ;
     
    Sélectionnez
    void buildConstraints(GridBagConstraints gbc, int gx, int gy, int gw, int gh, int wx, int wy) { 
        gbc.gridx = gx; 
        gbc.gridy = gy; 
        gbc.gridwidth = gw; 
        gbc.gridheight = gh; 
        gbc.weightx = wx; 
        gbc.weighty = wy; 
    } 
    
    // gw et gh = le nombre de cellules sur lesquelles le composant s'étend 
    // gx, gy = les coordonnées du composant, par exemple 0.2 pour le bouton OK 
    // wx et wy = largeur et profondeur des lignes.
  • Ajouter les composants ;
     
    Sélectionnez
    // Création du layout 
    GridBagLayout gridbag = new GridBagLayout(); 
    GridBagConstraints constraints = new GridBagConstraints(); 
    SetLayout(gridbag); 
    
     
    // Exemple pour le label NOM 
    buildConstraints(constraints, 0, 0, 1, 1, 10, 40); 
    constraints.fill = GridBagConstraints.NONE; 
    constraints.anchor = GridBagConstraints.EAST; 
    Label label1 = new Label("Nom ", Label.LEFT); 
    gridbag.setConstraints(label1, constraints); 
    add(label1); 
     
    // Exemple pour le textfield du mot de passe 
    buildConstraints(constraints, 1, 1, 1, 1, 0, 0); 
    constraints.fill = GridBagConstraints.HORIZONTAL; 
    constraints.anchor = GridBagConstraints.CENTER; 
    TextField tpas = new TextField(); 
    tpas.setEchoChar('*'); 
    gridbag.setConstraints(tpas, constraints); 
    add(tpas); 
    
    // Faire de même pour les autres composants
  • Fill détermine dans quel sens l'étirement des composants doit se faire (vers la droite, gauche, haut, bas…) BOTH (2 sens), NONE (plus petite taille possible), HORIZONTAL (étirement horizontal), VERTICAL (…).
    Anchor définit comment les composants qui ne remplissent pas toute une cellule doivent être disposés. NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTH, SOUTHEAST, WEST, NORTHWEST.

XVIII-C-6. Insets

La méthode insets() (ou getInsets() en Java 2) détermine les espacements en HAUT, BAS, GAUCHE, DROITE (dans cet ordre) entre le bord de la fenêtre et le layout. (On l'utilise généralement avec GridLayout).

 
Sélectionnez
public Insets insets() { 
    return new Insets(haut, bas, gauche, droite); 
}

XVIII-C-7. Exemple complet

Vous devez maintenant être en mesure de comprendre pratiquement tout le code écrit pour mon applet Convert. Cette applet est disponible à l'adresse suivante : http://perso.wanadoo.fr/guillaume/Programmes/Convert/.
Elle ne fonctionne pas avec IE5 ni Communicator 4.7, cependant vous pouvez l'utiliser avec appletviewer ou Netscape 6.
Les lignes générales de cette applet :

  • BUT : convertir des Francs en Euros et vice-versa ;
  • UI : AWT, GridBagLayout, 4 Labels, 4 TextFields, 1 Bouton ;
  • DONNEES : type double pour le taux de conversion : 6,55957 ;
  • METHODES :
    • Conversion d'euros en francs,
    • Conversion de francs en euros ;
  • METHODES UTILISEES SUR LES COMPOSANTS : getText() et setText(.)

Voici le code source :

 
Sélectionnez
import java.awt.*; 

/**************************************************************** 
 *                   Bonjour !                                  * 
 * Ceci est ma première applet. Sa fonction est de convertir des* 
 * francs français en euros et vice-versa.                      * 
 *        guillaume.florimond@wanadoo.fr                        * 
 ***************************************************************/

public class Convert extends java.applet.Applet{ 

    // Définition des variables du programme
    String labelBouton = new String("Convertir !"); 
    // Le bouton contenant le texte "Convertir !"
    Button bouton = new Button(labelBouton); 
    // Case  taper le nombre * d' euros à convertir 
    TextField textEuro = new TextField(11); 
    // Case  taper le nombre * de francs à convertir
    TextField textFranc = new TextField(11); 
    // Case  lire le résultat de la conversion 
    TextField textResultat = new TextField(26); 
    // franc vers euro   
    TextField textResultat2 = new TextField(26);// Case  lire le résultat de la conversion 
    // euro vers franc
    // Définition de la police par défaut du programme
    Font f = new Font("Helvetica", Font.BOLD, 15); 
    Label titre = new Label("Convertisseur de francs français en euros",Label.LEFT);
    Label labelEuro = new Label("Valeur en euroe:",Label.RIGHT); 
    Label labelFranc = new Label("Valeur en francs:",Label.RIGHT); 
    Label labelResultat = new Label("Résultat de la conversion (en euros):",Label.RIGHT); 
    Label labelResultat2 = new Label("Résultat de la conversion (en francs):",Label.RIGHT); 
    String FrancChaine = new String(); // Valeur entrée par l'utilisateur dans le TextField "textFranc"
    String EuroChaine = new String(); // Valeur entrée par l'utilisateur dans le TextField "textEuro"
    double taux = 6.55957; // Taux définitif de conversion de l'euro en franc au 1er Janvier 2000
    double FrancEntier; // Valeur convertie en "double" que l'utilisateur a entrée dans "textFranc"
    double EuroEntier; // Valeur convertie en "double" que l'utilisateur a entrée dans "textEuro"
    Label copyright = newLabel("Copyright Guillaume Florimond 1999", Label.RIGHT); // (&#8230;) ;-)

    void buildConstraints(GridBagConstraints gbc, int gx, int gy, int gw, int gh, int wx, int wy) { 
        gbc.gridx = gx; 
        gbc.gridy = gy; 
        gbc.gridwidth = gw; 
        gbc.gridheight = gh; 
        gbc.weightx = wx; 
        gbc.weighty = wy; 
        /* Les lignes précédentes représentent la définition des variables nécessaires 
        pour la création d'une interface GridBagLayout */
    } 

    public void init () { 
        /* Les lignes suivantes représentent le paramétrage et l'insertion sur le 
        container principal Applet 
        de la seule police utilisée, des couleurs de premier et second plan, ainsi que 
        des éléments propres 
        à l'interface AWT tels que les TextArea et les Labels créés plus haut. */

        setFont(f); // police 

        setBackground(Color.cyan); // couleur arrière plan
        setForeground(Color.magenta); // couleur de la police

        GridBagLayout gridbag = new GridBagLayout(); 
        GridBagConstraints constraints = new GridBagConstraints(); 
        setLayout(gridbag); 

        // Titre
        buildConstraints(constraints, 1,0,4,1,0,5); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.CENTER; 
        gridbag.setConstraints(titre, constraints); 
        add(titre); 

        // labelFranc
        buildConstraints(constraints, 0,1,1,1,30,20); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.EAST; 
        gridbag.setConstraints(labelFranc, constraints); 
        add(labelFranc); 

        // labelEuro
        buildConstraints(constraints, 0,2,1,1,30,20); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.EAST; 
        gridbag.setConstraints(labelEuro, constraints); 
        add(labelEuro); 

        // bouton
        buildConstraints(constraints, 0,3,2,1,0,0); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.CENTER; 
        gridbag.setConstraints(bouton, constraints); 
        add(bouton); 

        // textFranc 
        buildConstraints(constraints, 1,1,1,1,20,20); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.WEST; 
        gridbag.setConstraints(textFranc, constraints); 
        add(textFranc); 

        // textEuro
        buildConstraints(constraints, 1,2,1,1,20,20); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.WEST; 
        gridbag.setConstraints(textEuro, constraints); 
        add(textEuro); 

        // labelResultat
        buildConstraints(constraints, 2,1,1,1,30,20); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.EAST; 
        gridbag.setConstraints(labelResultat, constraints); 
        add(labelResultat); 

        // labelResultat2
        buildConstraints(constraints, 2,2,1,1,30,20); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.EAST; 
        gridbag.setConstraints(labelResultat2, constraints); 
        add(labelResultat2); 

        // textResultat
        buildConstraints(constraints, 3,1,1,1,20,20); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.WEST; 
        gridbag.setConstraints(textResultat, constraints); 
        add(textResultat); 

        // textResultat2
        buildConstraints(constraints, 3,2,1,1,20,20); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.WEST; 
        gridbag.setConstraints(textResultat2, constraints); 
        add(textResultat2); 

        // Copyright
        buildConstraints(constraints, 3,3,2,1,0,0); 
        constraints.fill = GridBagConstraints.NONE; 
        constraints.anchor = GridBagConstraints.CENTER; 
        gridbag.setConstraints(copyright, constraints); 
        add(copyright); 
    } 

    public void convertir (Button b) { /* ma méthode convertir() qui permet de 
            convertir des euros en francs et vice-versa appelée quand une action sur le bouton b 
            se produit */

        if(b == bouton) {  // si le bouton * est le bouton b 
            FrancChaine = textFranc.getText(); // prendre la chaîne tapée par l'utilisateur 
            //dans textFranc
            FrancEntier = Double.parseDouble(FrancChaine); // convertir cette valeur en 
            //Double
            FrancEntier = FrancEntier / taux; // diviser par le taux de conversion officiel
            String resultat = new String(FrancEntier + ""); // convertir la valeur Double 
            //retournée en String 
            textResultat.setText(resultat); // afficher cette valeur dans textResultat

            EuroChaine = textEuro.getText(); 
            EuroEntier = Double.parseDouble(EuroChaine); 
            EuroEntier = EuroEntier * taux; 
            String resultat2 = new String(EuroEntier + ""); 
            textResultat2.setText(resultat2); 
        } 
    } 

    // les lignes suivantes définissent le gestionnaire d'événement
    public boolean action(Event evt, Object arg) { 
        if(evt.target instanceof Button) { 
            convertir((Button)evt.target); // appeler la méthode convertir()
            return true; 
        } else return false; 
    } 
}

XVIII-C-8. Cadres

Nous avons vu que dans le cas des applets, un cadre où afficher les composants est par défaut le cadre d'affichage de l'applet. Pour l'instant, toutes les applications présentées dans ce cours étaient de ligne de commande, c'est à dire sans Interface Utilisateur. Nous allons maintenant en créer avec une UI, en définissant un cadre d'affichage grâce à un objet Frame. Voici un petit schéma d'héritage de la classe Frame. Un cadre (Frame) est une sorte de fenêtre (Window), une fenêtre est un conteneur (Container) à composants, les cadres, fenêtres et conteneurs sont des composants Java.

Voici un exemple de création de fenêtre :

 
Sélectionnez
// Crée une nouvelle fenêtre du nom de Win 
// "Ma fenêtre" est affiché comme intitulé de la fenêtre 
win = new Frame("Ma fenêtre"); 
// Assigner un Layout à cette fenêtre 
win.setLayout(new BorderLayout(10, 20); 
// Ajouter 2 boutons à cette fenêtre 
win.add("North", new Button("Bonjour")); 
win.add("South", new Button("Au revoir")); 
// La réduire aussi petite que possible en fonction des composants 
// qu'elle contient 
win.pack(); 
// La redimensionner à la taille voulue (en pixels) 
win.resize(100, 200); 
// Afficher la fenêtre précédemment créée 
win.show(); 
// La masquer 
win.hide();
Image non disponible

XVIII-C-9. Gestion d'événements

Vous savez maintenant créer un nouvelle fenêtre et y insérer des composants suivant le mode de mise en page désiré. Cependant, ces composants ne servent strictement à rien tant que vous ne leur assignez pas un comportement en réponse aux actions de l'utilisateur.
Avec AWT, cette gestion d'événements se fait en 2 temps : on crée une méthode qui exécute les opérations données avec pour argument, par exemple, un bouton. Ensuite, on crée une seconde méthode qui répond aux actions d'un composant spécifié (pour continuer sur le même exemple, le bouton).
Pour donner un exemple concret, on peut reprendre l'applet Convert :

 
Sélectionnez
public void convertir (Button b) { /* ma méthode convertir() qui permet de convertir 
des euros en francs et vice-versa appelée quand une action sur le bouton b se 
produit */
    if(b == bouton) {  // si le bouton * est le bouton b
 
Sélectionnez
// les lignes suivantes définissent le gestionnaire d'événement
public boolean action(Event evt, Object arg) { 
    if(evt.target instanceof Button) { 
        convertir((Button)evt.target); // appeler la méthode convertir()
        return true; 
    } else return false; 
}

Ce bouton réagit à toutes les actions de la même façon : il exécute le méthode convertir(). Cependant, on peut définir d'autres comportements en fonction du type d'action effectué (RollOver, RollOut…)

 
Sélectionnez
boolean mouseDown(Event evt, int x, int y) // clic
boolean mouseDrag() // déplacement avec bouton de souris enfoncé
boolean mouseMove() // souris déplacée
boolean mouseEnter() // souris entre dans une zone
boolean mouseExit() // souris sort de cette zone
boolean KeyUp() // touche du clavier relâchée
boolean KeyDown() // touche appuyée 
// etc&#8230;

Il existe bien d'autres comportements mais je ne vais pas les détailler car il ne sont que rarement utiles. Je ne vais pas nonplus parler de l'utilisation des événements pré-cités car la gestion d'événements est complètement remaniée avec Swing (celle d'AWT n'est vraiment pas performante). Je vous conseille pour de petits projets d'utiliser une méthode passe-partout comme action(Event ev, Object arg) accompagnée d'une instruction de reconnaissance du composant qui a subi l'action de l'utilisateur :
if (evt.target instanceof Button) {} (= si l'élément qui a subi l'action est une instance de la classe Button, exécuter le code entre accolades).

XVIII-C-10. Schéma général d'héritage d'AWT

Image non disponible

XIX. SWING - Interfaces Utilisateur : les Bases

XIX-A. Introduction

Swing est la 2e bibliothèque de classes, après AWT, qui permet de créer une Interface Utilisateur et de la gérer. La procédure de construction d'une interface Swing est similaire à celle d'AWT : créer un cadre, des composants dans ce cadre, une mise en page pour ces composants, des méthodes en réponse aux actions de l'utilisateur. Il n'est pas possible de faire le tour de Swing en un seul chapitre, c'est pourquoi ce chapitre s'intéresse seulement aux principes de base et à la construction d'une UI simple.

XIX-B. Différences entre Swing et AWT

Du côté de l'utilisateur, la différence est majeure : l'apparence des composants est totalement différente (bien que celle-ci soit paramétrable). Du côté du concepteur, Swing présente plus de composants qu'AWT, ces composants commencent par un J (ex : JButton, JLabel…), la gestion des événements est complètement différente. Les layouts, eux, restent les mêmes.

XIX-C. Composants

Comme dit précédemment, les composants sont presque les mêmes que ceux d'AWT. Pour une description des composants et plus d'informations, se reporter au chapitre sur AWT.

  • JButton ;
  • JLabel ;
  • JTextArea ;
  • JTextField ;
  • JRadioButton ;
  • JCheckBox ;
  • JPasswordField ;
  • JComboBox ;
  • JList ;
  • JScrollBar.

D'autres composants avancés seront traités dans les chapitres suivants concernant Swing.

XIX-D. Conteneurs

Les conteneurs sont les objets dans lesquels sont incorporés les composants de l'UI. Un cadre (JFrame) est un conteneur. On peut citer : JFrame, JDialog (c'est un peu différent…), JPanel, JScrollPane, JTabbedPane, JSplitPane

  • JFrame, JPanel : classiques, une JFrame est un JPanel dans un cadre spécifique à l'environnement (le cadre contenant par exemple la X pour fermer la fenêtre) ;
  • JDialog : boîte de dialogue qui surgit en plein milieu de l'écran (les utilisateurs de Windows connaissent sûrement celle de type Warning qui contient les habituelles Fatal Errors) ;
  • JScrollPane : barres de défilement. Ajouter un JScrollPane à votre JFrame, ajoutez ensuite un JTextArea (ou autre composant nécessitant des barres de défilement) l'intérieur de ce JScrollPane ;
  • JtabbedPane : cadre à onglets.

XIX-E. Gestion d'événements

Les gestionnaires d'événements permettent d'intercepter les actions des utilisateurs et d'assigner au programme un comportement adapté en réponse. Il existe de nombreuses manières de gérer les événements. Ce chapitre propose une manière classique, c'est celle qui est utilisée par défaut par JBuilder. Elle se met en œuvre en trois temps : création d'un « écouteur » d'actions qui attend et capte les actions de l'utilisateur, d'une méthode qui met en œuvre la réponse adaptée, de la classe qui définit cette méthode.

 
Sélectionnez
//  
// assigne un écouteur d'événements basique à un composant nommé composantX 
composantX.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
        // quand une action sera captée, on devra exécuter la méthode ci-dessous, implémentée dans la partie  
        composantX_actionPerformed(e); 
    } 
});
 
Sélectionnez
//  
void jButton1_actionPerformed(ActionEvent e) { 
    // code à insérer 
}
 
Sélectionnez
//  
class nomDeLaClasse implements java.awt.event.ActionListener { 
    NomDeLaClasseOuSeTrouveLeComposant adaptee; 

    nomDeLaClasse(NomDeLaClasseOuSeTrouveLeComposant adaptee) { 
        this.adaptee = adaptee; 
    } 

    public void actionPerformed(ActionEvent e) { 
        adaptee.jButton1_actionPerformed(e); 
    } 
}

Le code présenté ci-dessus est exactement celui créé par JBuilder, d'autres manières de capter les actions de l'utilisateur et d'appeler un code en réponse seront étudiées plus tard. Si vous possédez JBuilder, il suffit de double-cliquer sur un composant en mode Conception pour que soit automatiquement généré le code ci-dessus.

XIX-F. Construction d'une UI

Cette partie a pour fonction de créer une application à l'aide de Swing.

XIX-F-1. Comment sera le programme ? / Que fera t-il ?

Le programme sera une petite fenêtre avec un bouton et un label. Au clic sur le bouton, le texte « Hello World again ! » s'affichera dans le label. Pour cela, l'application sera composée de 2 classes : une définissant l'interface, une autre contenant la méthode main() et appelant l'autre classe.

XIX-F-2. Interface graphique

  • Créer la première classe en la définissant comme un cadre ;
 
Sélectionnez
public class Cadre1 extends JFrame { // définition du cadre 

    public Cadre1() { // méthode constructeur
    } 
}
  • Ajouter les composants ;
 
Sélectionnez
jLabel1.setText(""); // création du label
jButton1.setText("Cliquez ICI !"); // création du bouton
this.getContentPane().setLayout(flowLayout1); // mise en place d'un layout
this.getContentPane().add(jLabel1, null); // ajout du label du cadre
this.getContentPane().add(jButton1, null); // ajout du bouton au cadre
  • Créer le gestionnaire d'événement pour le bouton.
 
Sélectionnez
//  partie: "quand une action est effectuée sur le bouton, appeler la méthode 
// JButton1_actionPerformed()" 
jButton1.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
        jButton1_actionPerformed(e); 
    } 
});
 
Sélectionnez
//  partie: création de la méthode jButton1_actionPerformed() 
void jButton1_actionPerformed(ActionEvent e) { 
    jLabel1.setText("Hello World again !"); // afficher ce texte dans le label
}

XIX-F-3. Classe principale

 
Sélectionnez
public class Application { 
    //Construire l'application 
    public Application() { 
        Cadre1 frame = new Cadre1(); 
    } 

    //Méthode principale 
    public static void main(String[] args) { 
        new Application(); 
    }
}

XX. I/O : Les Flux : les Bases

Il est possible de télécharger les sources du programme.

XX-A. Introduction

Les flux permettent de travailler avec des données - des fichiers - provenant de l'extérieur. Toutes les commandes de type Ouvrir, Enregistrer, Enregistrer sous … des programmes classiques font appel aux flux. Les flux sont aussi appelés I/O : en anglais, Input/Output, entrées/sorties. Nous allons voir dans ce chapitre les flux de base, permettant de lire et d'écrire du texte (On différencie les caractères et le texte en général). Nous verrons également comment utiliser la mise en mémoire cache du contenu d'un flux (en fait des données qu'il transporte) pour accélérer ses performances (vitesse, fiabilité). Le programme final définira une petite interface Swing, un gros bouton qui, quand on le pressera, fera charger un fichier dans un JTextArea.

XX-B. Ligne de commande

Vous connaissez déjà un type de flux basique de ligne de commande : System.out. Sachez qu'il existe pour les entrées System.in et pour les erreurs System.err. Dans la mesure où les applications de ligne de commande uniquement se font très rares, nous n'étudierons pas ces méthodes.

XX-C. Flux d'entrée / flux de sortie

La création d'un flux de base se fait en 2 étapes : création d'un flux de support d'entrée ou de sortie, création d'un flux adapté à l'opération que l'on désire obtenir.

 
Sélectionnez
// flux de support (valable dans tous les cas) 
FileInputStream fis = new FileInputStream("fichier.extension") ; 
// flux particulier (exemple) 
*InputStream zis = new *InputStream(fis);

On crée un flux de support fis grâce à FileInputStream, ce flux (ici, d'entrée) travaille avec le fichier fichier.extension (exemple : Readme.txt), à ce flux, on associe un flux particulier. L'étoile représente tous les types de flux : ZipInputStream, DataInpuStream, GzipInputStream
Ici sont présentés des flux d'entrée, pour les flux de sortie, on remplace « Input » par « Output ».
Exemple concret :

 
Sélectionnez
FileOutputStream fos = new FileOutputStream("fichier.txt"); 
ZipOutputStream zout = new ZipOutputStream(fos);

XX-D. Classes de flux d'entrée/sortie

XX-D-1. Entrée

 
Sélectionnez
public int available() throws IOException

Permet de retourner le nombre d'octets que le flux peut lire. (rarement nécessaire)

 
Sélectionnez
public long skip(long n) throws IOException

Permet d'ignorer les n prochains caractères. (rarement nécessaire)

XX-D-2. Sortie

 
Sélectionnez
public void flush()

Vide immédiatement le contenu d'un flux (vide le tampon et distribue ce qu'il contient). (utile)

 
Sélectionnez
public void close() throws IOException

Permet de fermer un flux. Même si vous ne fermez pas un flux, aucune erreur ne sera (normalement) provoquée. Cependant, chaque flux devrait être fermé.

XX-E. Mise en mémoire tampon

La mise en mémoire tampon d'un flux permet d'accélérer les performances, voici la procédure à adopter :

 
Sélectionnez
// création du support 
FileInputStream fis = new FileInputStream("fichier.txt"); 
// création du flux de mise en tampon 
BufferedInputStream bis = new BufferedInputStream(fis); 
// on joint le BufferedInputStream à un flux particulier, par exemple: 
DataInputStream dis = new DataInputStream(bis);

XX-F. Readers/writers

Les readers et writers sont un sujet assez long à traiter. Il serait hors-sujet de les traiter dans leur intégralité dans ce chapitre présentant les concepts clés de I/O. Nous allons donc voir uniquement une partie basique.
Les readers et writers permettent de lire et d'écrire des données dans des fichiers. Ils sont très utiles pour travailler avec des fichiers de texte. Ils sont utilisés en remplacement des méthodes FileInputStream et FileOutputStream. Par exemple, pour utiliser un FileWriter et un FileReader :

 
Sélectionnez
// FileWriter: 
// déterminer le texte à écrire dans le fichier en le prenant, par exemple, dans un TextArea 
String texte = new String(jTextArea1.getText()); 
// ouvrir le FileWriter avec pour argument le nom du fichier de sortie 
FileWriter lu = new FileWriter("fichier.txt"); 
// procédure de mise en cache 
BufferedWriter out = new BufferedWriter(lu); 
// écrire dans le FileWriter les informations du String texte 
out.write(texte); 
// fermer le flux 
out.close(); 

// FileReader&#160;: 
//ouvre un FileReader 
FileReader fr = new FileReader("fichier.txt"); 
// procédure de lecture des caractères&#8230; 
while (true) { 
    // lire les caractères 
    int i = fr.read(); 
    // -1 représente le moment  il n'y a plus de caractères à lire, la boucle while doit alors s' 
    // arrêter 
    if (i == -1) break; 
}

XX-G. Projet : afficheur

Ce programme permet de capturer un texte d'une zone de texte et de l'écrire dans un fichier, de le lire d'un fichier pour l'écrire dans la zone de texte.
Il utilise 2 classes Swing, un FileWriter et un FileInputStream

1re classe :

 
Sélectionnez
package afficheur; 

import javax.swing.UIManager; 

public class Application { 

    boolean packFrame = false; 

    //Construire l'application
    public Application() { 
        // appel à la classe 'afficheur'
        afficheur frame = new afficheur(); 
        //Valider les cadres ayant des tailles prédéfinies
        //Compacter les cadres ayant des infos de taille préférées - ex. depuis leur disposition
        if(packFrame) { 
            frame.pack(); 
        } 
        else{ 
            frame.validate(); 
        } 
        frame.setVisible(true); 
    } 

    //Méthode principale
    public static void main(String[] args) { 
        try{ 
            // pour l'apparence 'Windows'
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
        } 
        catch(Exception e) { 
            e.printStackTrace(); 
        } 
        newApplication(); 
    } 
}

2de classe :

 
Sélectionnez
// le programme comprend 2 classes regroupées dans 1 package:
package afficheur; 

// importation de packages nécessaires
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import java.io.*; 

// début du programmes, la classe afficheur doit étendre (extends) de JFrame
// pour définir un cadre Swing à l'écran
public class afficheur extends JFrame { 

    // Conteneur
    JPanel contentPane; 
    // Layout
    BorderLayout borderLayout1 = new BorderLayout(); 
    // Composant 1&#160;: le bouton
    JButton jButton1 = new JButton(); 
    // barres de défilement pour le composant 2
    JScrollPane jScrollPane1 = new JScrollPane(); 
    // Composant 2&#160;: la zone de texte
    JTextArea jTextArea1 = new JTextArea(); 
    JButton jButton2 = new JButton(); 

    //Construire le cadre
    public afficheur() { 
        enableEvents(AWTEvent.WINDOW_EVENT_MASK); 
        try{ 
            // essayer d'exécuter la méthode jbInit()
            jbInit(); 
        } 
        catch(Exception e) { 
            e.printStackTrace(); 
        } 
    } 

    //Initialiser le composant
    private void jbInit() throwsException { 
        // texte du bouton
        jButton1.setText("Charger"); 
        // écouteur d'actions (fait partie du gestionnaire d'événements)
        jButton1.addActionListener(new afficheur_jButton1_actionAdapter(this)); 
        // définition du conteneur courant
        contentPane = (JPanel) this.getContentPane(); 
        // assignation à ce conteneur d'un layout précis
        contentPane.setLayout(borderLayout1); 
        // taille de la fenêtre
        this.setSize(newDimension(400, 300)); 
        // label de la fenêtre
        this.setTitle("Exemple pour les flux"); 
        // texte qui apparaît quand on laisse la souris immobile un certain temps
        // sur la zone de texte
        jTextArea1.setToolTipText("Exemple d'un chapitre de JGFL"); 
        // ajout des composants
        jButton2.setText("Enregistrer"); 
        jButton2.addActionListener(new afficheur_jButton2_actionAdapter(this)); 
        contentPane.add(jButton1, BorderLayout.SOUTH); 
        contentPane.add(jScrollPane1, BorderLayout.CENTER); 
        contentPane.add(jButton2, BorderLayout.NORTH); 
        jScrollPane1.getViewport().add(jTextArea1, null); 
    } 

    //Remplacé, ainsi nous pouvons sortir quand la fenêtre est fermée
    protected void processWindowEvent(WindowEvent e) { 
        super.processWindowEvent(e); 
        if(e.getID() == WindowEvent.WINDOW_CLOSING) { 
            // pour fermer 'proprement' la fenêtre au clic sur la croix (sous Win95)
            System.exit(0); 
        } 
    } 

    // gestionnaire d'événements, 2de partie
    void jButton1_actionPerformed(ActionEvent e) { 
        // appeler cette méthode
        charger(); 
    } 

    // méthode qui permet de prendre le texte dans la zone de texte et de le
    // transmettre au FileWriter
    public void enregistrer() { 
        try{ 
            String texte = new String(jTextArea1.getText()); 
            FileWriter lu = new FileWriter("fichier.txt"); 
            BufferedWriter out = new BufferedWriter(lu); 
            out.write(texte); 
            out.close(); 
        } catch(Exception err) {;} 
    } 

    // ma méthode qui permet de lire les informations du fichier 'fichier.txt'
    // et de les imprimer dans la zone de texte
    public void charger() { 
        // les exceptions doivent être interceptées ('catchées')
        try{ 
            // Flux d'entrée
            FileInputStream fis = new FileInputStream("fichier.txt"); 
            // nombre de caractères dans le fichier
            int n; 
            // tant que ce nombre de caractères est supérieur à 0&#8230;
            while((n = fis.available()) > 0) { 
                // chaque caractère associé à 1 byte
                byte[] b = new byte[n]; 
                int result = fis.read(b); 
                // fin du flux = plus rien à lire = sortie de la boucle
                if(result == -1) break; 
                String s = new String(b); 
                jTextArea1.setText(s); 
            } 
        } catch(IOException err) { 
            System.out.println("Erreur: " + err); 
        } 
    } 

    // classes pour la gestion d'événements.
    class afficheur_jButton1_actionAdapter implements java.awt.event.ActionListener { 
        afficheur adaptee; 

        afficheur_jButton1_actionAdapter(afficheur adaptee) { 
            this.adaptee = adaptee; 
        } 

        public void actionPerformed(ActionEvent e) { 
            adaptee.jButton1_actionPerformed(e); 
        } 
    } 

    void jButton2_actionPerformed(ActionEvent e) { 
        enregistrer(); 
    } 
} 

class afficheur_jButton2_actionAdapter implements java.awt.event.ActionListener { 
    afficheur adaptee; 

    afficheur_jButton2_actionAdapter(afficheur adaptee) { 
        this.adaptee = adaptee; 
    } 

    public voidactionPerformed(ActionEvent e) { 
        adaptee.jButton2_actionPerformed(e); 
    } 
}
Image non disponible

XXI. Note et remerciement du gabarisateur

Cet article a été mis au gabarit de developpez.com. Dans la mesure du possible, l'esprit d'origine de l'article a été conservé. Cependant, certaines adaptations ont été nécessaires. Voici les liens vers les documents PDF d'origine :

Le gabarisateur remercie Philippe DUVAL pour sa correction orthographique.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2002 Guillaume Florimond. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.