Penser en Java 2nde édition | - | Sommaire | Préface | Avant-propos | Chapitre : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Annexe : A B C D | Tables des matières | - | Thinking in Java |
On peut exécuter un test simple sans aucune connexion réseau en lançant son navigateur Web et en ouvrant le fichier HTML contenant le tag applet. Au chargement du fichier HTML, le navigateur découvre le tag applet et part à la recherche du fichier .class spécifié par le contenu de code. Bien sûr, il utilise le CLASSPATH pour savoir où chercher, et si le fichier .class n'est pas dans le CLASSPATH, il émettra un message d'erreur dans sa ligne de status pour signaler qu'il n'a pas pu trouver le fichier .class.
Quand on veut essayer ceci sur son site Web les choses sont un peu plus compliquées. Tout d'abord il faut avoir un site Web, ce qui pour la plupart des gens signifie avoir un Fournisseur d'Accès à Internet (FAI) [Internet Service Provider (ISP)]. Comme l'applet est simplement un fichier ou un ensemble de fichiers, le FAI n'a pas besoin de fournir un support particulier pour Java. Il faut disposer d'un moyen pour copier les fichiers HTML et les fichiers .class depuis chez vous vers le bon répertoire sur la machine du FAI. Ceci est normalement fait avec un programme de File Transfer Protocol (FTP), dont il existe beaucoup d'exemples disponibles gratuitement ou comme sharewares. Il semblerait donc que tout ce qu'il y a à faire est d'envoyer les fichiers sur la machine du FAI à l'aide de FTP, et ensuite de se connecter au site et au fichier HTML en utilisant son navigateur ; si l'applet se charge et fonctionne, alors tout va bien, n'est-ce pas ?
C'est là qu'on peut se faire avoir. Si le navigateur de la machine client ne peut pas localiser le fichier .class sur le serveur, il va le rechercher à l'aide du CLASSPATH sur la machine locale. De ce fait l'applet pourrait bien ne pas se charger correctement depuis le serveur, mais tout paraît correct lors du test parce que le navigateur le trouve sur la machine locale. Cependant, lorsque quelqu'un d'autre se connecte, son navigateur ne la trouvera pas. Donc lorsque vous testez, assurez vous d'effacer les fichiers .class (ou .jar) de votre machine locale pour vérifier qu'ils existent au bon endroit sur le serveur.
Un des cas les plus insidieux qui me soit arrivé s'est produit lorsque j'ai innocemment placé une applet dans un package. Après avoir téléchargé sur le serveur le fichier HTML et l'applet, le serveur fut trompé sur le chemin d'accès à l'applet à cause du nom du package. Cependant, mon navigateur l'avait trouvé dans le CLASSPATH local. J'étais donc le seul à pouvoir charger correctement l'applet. J'ai mis un certain temps à découvrir que l'instruction package était la coupable. En général il vaut mieux ne pas utiliser l'instruction package dans une applet.
Parfois on voudrait qu'un programme fenêtré fasse autre chose que se trouver dans une page Web. Peut-être voudrait-on aussi faire certaines des choses qu'une application « normale » peut faire, mais en gardant la glorieuse portabilité instantanée fournie par Java. Dans les chapitres précédents de ce livre, nous avons fait des applications de ligne de commande, mais dans certains environnements (le Macintosh par exemple) il n'y a pas de ligne de commande. Voilà un certain nombre de raisons pour vouloir construire un programme fenêtré n'étant pas une applet. C'est certainement un désir légitime.
La bibliothèque Swing nous permet de construire une application qui conserve le « look and feel » du système d'exploitation sous-jacent. Si vous voulez faire des applications fenêtrées, cela n'a de sens [65] que si vous pouvez utiliser la dernière version de Java et ses outils associés, afin de pouvoir fournir des applications qui ne perturberont pas vos utilisateurs. Si pour une raison ou une autre vous devez utiliser une ancienne version de Java, réfléchissez-y bien avant de vous lancer dans la construction d'une application fenêtrée importante.
On a souvent besoin de créer une classe qui peut être appelée aussi bien comme une fenêtre que comme une applet. C'est particulièrement utile lorsqu'on teste des applets, car il est souvent plus facile et plus simple de lancer l'applet-application depuis la ligne de commande que de lancer un navigateur Web ou l'Appletviewer.
Pour créer une applet qui peut être exécutée depuis la ligne de commande, il suffit d'ajouter un main() à l'applet, dans lequel on construit une instance de l'applet dans un JFrame [66]. En tant qu'exemple simple, observons Applet1b.java modifié pour fonctionner aussi bien en tant qu'application qu'en tant qu'applet :
main() est le seul élément ajouté à l'applet, et le reste de l'applet n'est pas modifié. L'applet est créée et ajoutée à un JFrame pour pouvoir être affichée.
La ligne :
permet la fermeture propre de la fenêtre. Console vient de com.bruceeckel.swing et sera expliqué un peu plus tard.
On peut voir que dans main(), l'applet est explicitement initialisée et démarrée, car dans ce cas le navigateur n'est pas là pour le faire. Bien sûr, ceci ne fournit pas le comportement complet du navigateur, qui appelle aussi stop() et destroy(), mais dans la plupart des cas c'est acceptable. Si cela pose un problème, on peut forcer les appels soi-même href="#fn67">[67].
Notez la dernière ligne :
Sans elle, on ne verrait rien à l'écran.
Bien que le code qui transforme des programmes en applets et applications produise des résultats corrects, il devient perturbant et gaspille du papier s'il est utilisé partout. Au lieu de cela, le squelette d'affichage ci-après sera utilisé pour les exemples Swing du reste de ce livre :
Comme c'est un outil que vous pouvez utiliser vous-mêmes, il est placé dans la bibliothèque com.bruceeckel.swing. La classe Console contient uniquement des méthodes static. La première est utilisée pour extraire le nom de la classe (en utilisant RTTI) depuis n'importe quel objet, et pour enlever le mot « class », qui est ajouté normalement au début du nom par getClass(). On utilise les méthodes de String : indexOf() pour déterminer si le mot « class » est présent, et substring() pour générer la nouvelle chaîne sans « class » ou le blanc de fin. Ce nom est utilisé pour étiqueter la fenêtre qui est affichée par les méthodes run().
setupClosing() est utilisé pour cacher le code qui provoque la sortie du programme lorsque la JFrame est fermée. Le comportement par défaut est de ne rien faire, donc si on n'appelle passetupClosing() ou un code équivalent pour le JFrame, l'application ne se ferme pas. Une des raisons pour laquelle ce code est caché plutôt que d'être placé directement dans les méthodes run() est que cela nous permet d'utiliser la méthode en elle-même lorsque ce qu'on veut faire est plus complexe que ce que fournit run() . Mais il isole aussi un facteur de changement : Java 2 possède deux manières de provoquer la fermeture de certains types de fenêtres. En JDK 1.2, la solution est de créer une nouvelle classe WindowAdapteret d'implémenter windowClosing(), comme vu plus haut (la signification de ceci sera expliquée en détails plus tard dans ce chapitre). Cependant lors de la création du JDK 1.3, les concepteurs de la librairie ont observé qu'on a normalement besoin de fermer des fenêtres chaque fois qu'on crée un programme qui n'est pas une applet, et ils ont ajoutésetDefaultCloseOperation()à JFrame et JDialog. Du point de vue de l'écriture du code, la nouvelle méthode est plus agréable à utiliser, mais ce livre a été écrit alors qu'il n'y avait pas de JDK 1.3 implémenté sur Linux et d'autres plateformes, et donc dans l'intérêt de la portabilité toutes versions, la modification a été isolée dans setupClosing().
La méthode run() est surchargée pour fonctionner avec les JApplets, les JPanels, et les JFrames. Remarquez que init() et start() ne sont appelées que s'il s'agit d'une JApplet.
Maintenant toute applet peut être lancée de la console en créant un main() contenant une ligne comme celle-ci :
dans laquelle les deux derniers arguments sont la largeur et la hauteur de l'affichage. Voici Applet1c.java modifié pour utiliser Console :
Ceci permet l'élimination de code répétitif tout en fournissant la plus grande flexibilité pour lancer les exemples.
Si vous utilisez Windows, vous pouvez simplifier le lancement d'un programme Java en ligne de commande en configurant l'explorateur Windows (le navigateur de fichiers de Windows, pas Internet Explorer) de façon à pouvoir double-cliquer sur un fichier .class pour l'exécuter. Il y a plusieurs étapes à effectuer.
D'abord, téléchargez et installez le langage de programmation Perl depuis www.Perl.org. Vous trouverez sur ce site les instructions et la documentation sur ce langage.
Ensuite, créez le script suivant sans la première et la dernière lignes (ce script fait partie du package de sources de ce livre) :
Maintenant, ouvrez l'explorateur Windows, sélectionnez Affichage, Options des dossiers, et cliquez sur l'onglet "Types de fichiers". Cliquez sur le bouton "Nouveau type...". Comme "Description du type", entrez "fichier classe Java". Comme "Extension associée", entrez class. Sous "Actions", cliquez sur le bouton "Nouveau...". Comme "Action" entrez "open", et pour "Application utilisée pour effectuer l'action" entrez une ligne telle que celle-ci :
en personnalisant le chemin devant RunJava.bat en fonction de l'endroit où vous avez placé le fichier batch.
Une fois cette installation effectuée, vous pouvez exécuter tout programme Java simplement en double-cliquant sur le fichier .class qui contient un main().
La création d'un bouton est assez simple: il suffit d'appeler le constructeur JButton avec le label désiré sur le bouton. On verra plus tard qu'on peut faire des choses encore plus jolies, comme par exemple y mettre des images graphiques.
En général on créera une variable pour le bouton dans la classe courante, afin de pouvoir s'y référer plus tard.
Le JButton est un composant possédant sa propre petite fenêtre qui sera automatiquement repeinte lors d'une mise à jour. Ceci signifie qu'on ne peint pas explicitement un bouton ni d'ailleurs les autres types de contrôles; on les place simplement sur le formulaire et on les laisse se repeindre automatiquement. Le placement d'un bouton sur un formulaire se fait dans init() :
On a ajouté ici quelque chose de nouveau : avant d'ajouter un quelconque élément sur la "surface de contenu"[content pane], on lui attribue un nouveau gestionnaire de disposition [layout manager], de type FlowLayout. Le layout manager définit la façon dont la surface décide implicitement de l'emplacement du contrôle dans le formulaire. Le comportement d'une applet est d'utiliser le BorderLayout, mais cela ne marchera pas ici car (comme on l'apprendra plus tard dans ce chapitre lorsqu'on verra avec plus de détails le contrôle de l'organisation d'un formulaire) son comportement par défaut est de couvrir entièrement chaque contrôle par tout nouveau contrôle ajouté. Cependant, FlowLayout provoque l'alignement des contrôles uniformément dans le formulaire, de gauche à droite et de haut en bas.
Vous remarquerez que si vous compilez et exécutez l'applet ci-dessus, rien ne se passe lorsqu'on appuie sur le bouton. C'est à vous de jouer et d'écrire le code qui définira ce qui va se passer. La base de la programmation par événements, qui est très importante dans les interfaces utilisateurs graphiques, est de lier les événements au code qui répond à ces événements.
Ceci est effectué dans Swing par une séparation claire de l'interface (les composants graphiques) et l'implémentation (le code que vous voulez exécuter quand un événement arrive sur un composant). Chaque composant Swing peut répercuter tous les événements qui peuvent lui arriver, et il peut répercuter chaque type d'événement individuellement. Donc si par exemple on n'est pas intéressé par le fait que la souris est déplacée par-dessus le bouton, on n'enregistre pas son intérêt pour cet événement. C'est une façon très directe et élégante de gérer la programmation par événements, et une fois qu'on a compris les concepts de base on peut facilement utiliser les composants Swing qu'on n'a jamais vus auparavant. En fait, ce modèle s'étend à tout ce qui peut être classé comme un JavaBean (que nous verrons plus tard dans ce chapitre).
Au début, on s'intéressera uniquement à l'événement le plus important pour les composants utilisés. Dans le cas d'un JButton, l'événement intéressant est le fait qu'on appuie sur le bouton. Pour enregistrer son intérêt à l'appui sur un bouton, on appelle la méthode addActionListener() de JButton. Cette méthode attend un argument qui est un objet qui implémente l'interface ActionListener, qui contient une seule méthode appelée actionPerformed(). Donc tout ce qu'il faut faire pour attacher du code à un JButton est d'implémenter l'interface ActionListener dans une classe et d'enregistrer un objet de cette classe avec le JButton à l'aide de addActionListener(). La méthode sera appelée lorsque le bouton sera enfoncé (ceci est en général appelé un callback).
Mais que doit être le résultat de l'appui sur ce bouton ? On aimerait voir quelque chose changer à l'écran; pour cela on va introduire un nouveau composant Swing : le JTextField. C'est un endroit où du texte peut être tapé, ou dans notre cas modifié par le programme. Bien qu'il y ait plusieurs façons de façons de créer un JTextField, la plus simple est d'indiquer au constructeur uniquement quelle largeur on désire pour ce champ. Une fois le JTextField placé sur le formulaire, on peut modifier son contenu en utilisant la méthode setText() (il y a beaucoup d'autres méthodes dans JTextField, que vous pouvez découvrir dans la documentation HTML pour le JDK depuis java.sun.com). Voilà à quoi ça ressemble :