IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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

  Chapitre 13 - Création de fenêtres & d'Applets

pages : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 

Tester les applets

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.

Exécuter des applets depuis la ligne de commande

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 :

//: c13:Applet1c.java
// Une application et une applet.
// <applet code=Applet1c width=100 height=50>
// </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;

public class Applet1c extends JApplet {
  public void init() {
  getContentPane().add(new JLabel("Applet!"));
}
  // Un main() pour l'application :
  public static void main(String[] args) {
  JApplet applet = new Applet1c();
  JFrame frame = new JFrame("Applet1c");
   // Pour fermer l'application :
  Console.setupClosing(frame);
  frame.getContentPane().add(applet);
  frame.setSize(100,50);
  applet.init();
  applet.start();
  frame.setVisible(true);
}
} ///:~

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 :

Console.setupClosing(frame);

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 :

frame.setVisible(true);

Sans elle, on ne verrait rien à l'écran.

Un squelette d'affichage

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 :

//: com:bruceeckel:swing:Console.java
// Outil pour exécuter des démos Swing depuis
// la console, aussi bien applets que JFrames.
package com.bruceeckel.swing;
import javax.swing.*;
import java.awt.event.*;

public class Console {
  // Crée une chaîne de titre à partir du nom de la classe :
  public static String title(Object o) {
  String t = o.getClass().toString();
   // Enlever le mot "class":
   if(t.indexOf("class") != -1)
    t = t.substring(6);
   return t;
}
  public static void setupClosing(JFrame frame) {
   // La solution JDK 1.2 Solution avec une
   // classe interne anonyme :
  frame.addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
      System.exit(0);
    }
  });
   // La solution amelioree en JDK 1.3 :
   // frame.setDefaultCloseOperation(
   //     EXIT_ON_CLOSE);
}
  public static void
run(JFrame frame, int width, int height) {
  setupClosing(frame);
  frame.setSize(width, height);
  frame.setVisible(true);
}
  public static void
run(JApplet applet, int width, int height) {
  JFrame frame = new JFrame(title(applet));
  setupClosing(frame);
  frame.getContentPane().add(applet);
  frame.setSize(width, height);
  applet.init();
  applet.start();
  frame.setVisible(true);
}
  public static void
run(JPanel panel, int width, int height) {
  JFrame frame = new >JFrame(title(panel));
  setupClosing(frame);
  frame.getContentPane().add(panel);
  frame.setSize(width, height);
  frame.setVisible(true);
}
} ///:~

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 :

Console.run(new MyClass(), 500, 300);

dans laquelle les deux derniers arguments sont la largeur et la hauteur de l'affichage. Voici Applet1c.java modifié pour utiliser Console :

//: c13:Applet1d.java
// Console exécute des applets depuis la ligne de commande.
// <applet code=Applet1d width=100 height=50>
// </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;

public class Applet1d extends JApplet {
  public void init() {
  getContentPane().add(new JLabel("Applet!"));
}
  public static void main(String[] args) {
  Console.run(new Applet1d(), 100, 50);
}
} ///:~

Ceci permet l'élimination de code répétitif tout en fournissant la plus grande flexibilité pour lancer les exemples.

Utilisation de l'Explorateur Windows

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) :

//:! c13:RunJava.bat
@rem = '--*-Perl-*--
@echo off
perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
goto endofperl
@rem ';
#!perl
$file = $ARGV[0];
$file =~ s/(.*)\..*/\1/;
$file =~ s/(.*\\)*(.*)/$+/;
´java $file´;
__END__
:endofperl
///:~

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 :

"c:\aaa\Perl\RunJava.bat" "%L"

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().

Création d'un bouton

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() :

//: c13:Button1.java
// Placement de boutons sur une applet.
// <applet code=Button1 width=200 height=50>
// </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;

public class Button1 extends JApplet {
JButton
b1 = new JButton("Button 1"),
b2 = new JButton("Button 2");
  public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(b1);
cp.add(b2);
}
  public static void main(String[] args) {
Console.run(new Button1(), 200, 50);
}
} ///:~

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.

Capture d'un événement

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 :

//: c13:Button2.java
// Réponse aux appuis sur un bouton.
// <applet code=Button2 width=200 height=75>
// </applet>
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import com.bruceeckel.swing.*;

public class Button2 extends JApplet {
JButton
  b1 = new JButton("Button 1"),
  b2 = new JButton("Button 2");
JTextField txt = new JTextField(10);
  class BL implements ActionListener {
   public void actionPerformed(ActionEvent e){
    String name =
      ((JButton)e.getSource()).getText();
    txt.setText(name);
  }
}
BL al = new BL();
  public void init() {
  b1.addActionListener(al);
  b2.addActionListener(al);
  Container cp = getContentPane();
  cp.setLayout(new FlowLayout());
  cp.add(b1);
  cp.add(b2);
  cp.add(txt);
}
  public static void main(String[] args) {
  Console.run(new Button2(), 200, 75);
}
} ///:~

Ce livre a été écrit par Bruce Eckel ( télécharger la version anglaise : Thinking in java )
Ce chapitre a été traduit par P. Boite ( groupe de traduction )
télécharger la version francaise (PDF) | Commandez le livre en version anglaise (amazon) | télécharger la version anglaise
pages : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 
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