Introduction à l'AWT

La bibliothèque de classes du langage de programmation Java fournit une boîte à outils d'interface utilisateur appelée Abstract Windowing Toolkit, ou AWT. L'AWT est à la fois puissant et flexible. Cependant, les nouveaux arrivants trouvent souvent que son pouvoir est voilé. Les descriptions de classes et de méthodes trouvées dans la documentation distribuée fournissent peu de conseils pour le nouveau programmeur. En outre, les exemples disponibles laissent souvent de nombreuses questions importantes sans réponse. Bien sûr, les nouveaux arrivants devraient s'attendre à des difficultés. Les interfaces utilisateur graphiques efficaces sont intrinsèquement difficiles à concevoir et à implémenter, et les interactions parfois compliquées entre les classes dans AWT ne font que rendre cette tâche plus complexe. Cependant, avec des conseils appropriés, la création d'une interface utilisateur graphique à l'aide de l'AWT est non seulement possible, mais relativement simple.

Cet article couvre une partie de la philosophie derrière l'AWT et aborde la question pratique de créer une interface utilisateur simple pour une applet ou une application.

Qu'est-ce qu'une interface utilisateur

L'interface utilisateur est la partie d'un programme qui interagit avec l'utilisateur du programme. Les interfaces utilisateur prennent de nombreuses formes. Ces formulaires varient en complexité, des simples interfaces de ligne de commande aux interfaces utilisateur graphiques pointer-cliquer fournies par de nombreuses applications modernes.

Au niveau le plus bas, le système d'exploitation transmet les informations de la souris et du clavier au programme en entrée et fournit des pixels pour la sortie du programme. L'AWT a été conçu pour que les programmeurs n'aient pas à se soucier des détails du suivi de la souris ou de la lecture du clavier, ni aux détails de l'écriture à l'écran. L'AWT fournit une interface orientée objet bien conçue à ces services et ressources de bas niveau.

Comme le langage de programmation Java est indépendant de la plate-forme, l'AWT doit également être indépendant de la plate-forme. L'AWT a été conçu pour fournir un ensemble commun d'outils pour la conception d'interfaces utilisateur graphiques qui fonctionnent sur une variété de plates-formes. Les éléments d'interface utilisateur fournis par l'AWT sont implémentés à l'aide de la boîte à outils GUI native de chaque plate-forme, préservant ainsi l'aspect et la convivialité de chaque plate-forme. C'est l'un des points forts de l'AWT. L'inconvénient d'une telle approche est le fait qu'une interface utilisateur graphique conçue sur une plate-forme peut sembler différente lorsqu'elle est affichée sur une autre plate-forme.

Composants et conteneurs

Une interface utilisateur graphique est constituée d'éléments graphiques appelés composants. Les composants typiques incluent des éléments tels que des boutons, des barres de défilement et des champs de texte. Les composants permettent à l'utilisateur d'interagir avec le programme et fournissent à l'utilisateur un retour visuel sur l'état du programme. Dans l'AWT, tous les composants de l'interface utilisateur sont des instances de la classe Component ou de l'un de ses sous-types.

Les composants ne sont pas autonomes, mais se trouvent plutôt dans des conteneurs. Les conteneurs contiennent et contrôlent la disposition des composants. Les conteneurs sont eux-mêmes des composants et peuvent ainsi être placés à l'intérieur d'autres conteneurs. Dans l'AWT, tous les conteneurs sont des instances de la classe Container ou de l'un de ses sous-types.

Spatialement, les composants doivent s'intégrer complètement dans le conteneur qui les contient. Cette imbrication de composants (y compris des conteneurs) dans des conteneurs crée une arborescence d'éléments, en commençant par le conteneur à la racine de l'arbre et en s'étendant jusqu'aux feuilles, qui sont des composants tels que des boutons.

L'illustration de la figure 1 représente une interface utilisateur graphique simple telle qu'elle apparaîtrait sous Windows 95. La figure 2 montre les composants d'interface de la figure 1 disposés sous forme d'arborescence.

Types de composants

La figure 3 montre la relation d'héritage entre les classes de composants d'interface utilisateur fournies par l'AWT. Le composant de classe définit l'interface à laquelle tous les composants doivent adhérer.

L'AWT fournit neuf classes de composants non-conteneurs de base à partir desquelles une interface utilisateur peut être construite. (Bien sûr, les nouvelles classes de composants peuvent être dérivées de l'un de ces éléments ou de la classe Component elle-même.) Ces neuf classes sont la classe Button, Canvas, Checkbox, Choice, Label, List, Scrollbar, TextArea et TextField. La figure 4 illustre une instance de chaque classe.

Vous avez besoin d'un navigateur compatible Java pour afficher cette applet.

Graphique 4.

Neuf composants d'interface utilisateur

La source de cet affichage se trouve ici.

Types de conteneurs

L'AWT fournit quatre classes de conteneurs. Il s'agit de la classe Window et de ses deux sous-types - la classe Frame et la classe Dialog - ainsi que la classe Panel. En plus des conteneurs fournis par l'AWT, la classe Applet est un conteneur - c'est un sous-type de la classe Panel et peut donc contenir des composants. Une brève description de chaque classe de conteneur fournie par l'AWT est fournie ci-dessous.

La fenêtre Une surface d'affichage de niveau supérieur (une fenêtre). Une instance de la classe Window n'est ni attachée ni incorporée dans un autre conteneur. Une instance de la classe Window n'a ni bordure ni titre.
Cadre Une surface d'affichage de niveau supérieur (une fenêtre) avec une bordure et un titre. Une instance de la classe Frame peut avoir une barre de menus. Cela ressemble beaucoup à une instance de la classe Window.
Dialogue Une surface d'affichage de niveau supérieur (une fenêtre) avec une bordure et un titre. Une instance de la classe Dialog ne peut pas exister sans une instance associée de la classe Frame.
Panneau

Un conteneur générique pour contenir des composants. Une instance de la classe Panel fournit un conteneur auquel ajouter des composants.

Créer un conteneur

Avant d'ajouter les composants qui composent une interface utilisateur, le programmeur doit créer un conteneur. Lors de la construction d'une application, le programmeur doit d'abord créer une instance de la classe Window ou de la classe Frame. Lors de la construction d'une applet, un cadre (la fenêtre du navigateur) existe déjà. Puisque la classe Applet est un sous-type de la classe Panel, le programmeur peut ajouter les composants à l'instance de la classe Applet elle-même.

Le code du listing 1 crée un cadre vide. Le titre du cadre ("Exemple 1") est défini dans l'appel au constructeur. Un cadre est initialement invisible et doit être rendu visible en invoquant sa show()méthode.

import java.awt. *;

classe publique Example1 {public static void main (String [] args) {Frame f = new Frame ("Example 1");

f.show (); }}

Liste 1.

Un cadre vide

Le code du Listing 2 étend le code du Listing 1 afin que la nouvelle classe hérite de la classe Panel. Dans la main()méthode, une instance de cette nouvelle classe est créée et ajoutée à l'objet Frame via un appel à la add()méthode. Le résultat est alors affiché. Les résultats des deux exemples doivent être identiques (c'est-à-dire qu'ils doivent paraître assez inintéressants).

import java.awt. *;

classe publique Example1a étend Panel {public static void main (String [] args) {Frame f = new Frame ("Example 1a");

Example1a ex = new Example1a ();

f.add ("Centre", ex);

f.pack (); f.show (); }}

Liste 2.

Un cadre avec un panneau vide

En dérivant la nouvelle classe de la classe Applet au lieu de la classe Panel, cet exemple peut désormais s'exécuter en tant qu'application autonome ou en tant qu'applet incorporé dans une page Web. Le code de cet exemple est fourni dans le Listing 3. L'applet résultant est affiché dans la figure 5 (et est encore assez inintéressant).

import java.awt. *;

classe publique Example1b étend java.applet.Applet {public static void main (String [] args) {Frame f = new Frame ("Example 1b");

Example1b ex = new Example1b ();

f.add ("Centre", ex);

f.pack (); f.show (); }}

Liste 3.

Un cadre avec une applet vide

Vous avez besoin d'un navigateur compatible Java pour afficher cette applet.

Figure 5.

Un cadre vide

Remarque: un objet Window, et dans certains cas même un objet Dialog, pourrait remplacer l'objet Frame. Ce sont tous des conteneurs valides et des composants sont ajoutés à chacun de la même manière.

Ajouter des composants à un conteneur

Pour être utile, une interface utilisateur doit comporter plus qu'un simple conteneur - elle doit contenir des composants. Les composants sont ajoutés aux conteneurs via la add()méthode d' un conteneur . Il existe trois formes de base de la add()méthode. La méthode à utiliser dépend du gestionnaire de disposition du conteneur (voir la section intitulée Disposition des composants ).

Le code du Listing 4 ajoute la création de deux boutons au code présenté dans le Listing 3. La création est effectuée dans la init()méthode car elle est automatiquement appelée lors de l'initialisation de l'applet. Par conséquent, quel que soit le mode de démarrage du programme, les boutons sont créés, car ils init()sont appelés soit par le navigateur, soit par la main()méthode. La figure 6 contient l'applet résultant.

import java.awt. *;

classe publique Example3 étend java.applet.Applet {public void init () {add (new Button ("One")); ajouter (nouveau bouton ("Deux")); }

public Dimension favoriteSize () {retourne une nouvelle dimension (200, 100); }

public static void main (String [] args) {Frame f = new Frame ("Exemple 3");

Exemple3 ex = nouveau Exemple3 ();

ex.init ();

f.add ("Centre", ex);

f.pack (); f.show (); }}

Liste 4.

Une applet avec deux boutons

Vous avez besoin d'un navigateur compatible Java pour afficher cette applet.

Graphique 6.

Une applet avec deux boutons

Disposition des composants

Jusqu'à présent, rien n'a été dit sur la disposition des composants qui ont été ajoutés à un conteneur. La mise en page n'est pas contrôlée par le conteneur, mais par un gestionnaire de mise en page associé au conteneur. Le gestionnaire de disposition prend toutes les décisions de placement des composants. Dans AWT, toutes les classes de gestionnaire de disposition implémentent l'interface LayoutManager.

L'AWT fournit cinq gestionnaires de disposition. Ils vont du très simple au très complexe. Cet article ne couvre que les deux classes de gestionnaire de disposition utilisées par les exemples ci-dessous: la classe FlowLayout et la classe BorderLayout.

La classe FlowLayout place les composants dans un conteneur de gauche à droite. Lorsque l'espace d'une ligne est épuisé, une autre ligne est démarrée. La version à argument unique de la add()méthode d'un conteneur est utilisée pour ajouter des composants.

La classe BorderLayout a cinq zones comme illustré dans la figure 7. Les zones sont nommées «Nord», «Sud», «Est», «Ouest» et «Centre». Un seul composant peut être placé dans chacune de ces cinq zones. Lorsque le conteneur englobant est redimensionné, chaque zone de bordure est redimensionnée juste assez pour contenir le composant placé à l'intérieur. Tout espace excédentaire est attribué à la zone centrale. La version à deux arguments de la add()méthode d'un conteneur est utilisée pour ajouter des composants. Le premier argument est un objet String qui nomme la zone dans laquelle placer le composant.

Chaque classe de conteneur a un gestionnaire de disposition par défaut. Le gestionnaire de disposition par défaut pour la classe Frame et la classe Dialog est le gestionnaire BorderLayout. Le gestionnaire de disposition par défaut pour la classe Panel (et la classe Applet) est le gestionnaire FlowLayout.

Le code du Listing 5 utilise les deux gestionnaires de mise en page et comprend quelques composants d'interface utilisateur supplémentaires. Le résultat est affiché sur la figure 8.

import java.awt. *;

classe publique Example4 étend java.applet.Applet {public void init () {Panel p;

setLayout (nouveau BorderLayout ());

p = nouveau panneau ();

p.add (nouveau TextArea ());

add ("Centre", p);

p = nouveau panneau ();

p.add (nouveau bouton ("One")); p.add (nouveau bouton ("Deux"));

Choix c = nouveau choix ();

c.addItem ("un"); c.addItem ("deux"); c.addItem ("trois");

p.add (c);

ajouter ("Sud", p); }

public static void main (String [] args) {Frame f = new Frame ("Exemple 4");

Exemple4 ex = nouveau Exemple4 ();

ex.init ();

f.add ("Centre", ex);

f.pack (); f.show (); }}

Liste 5.

Un exemple plus compliqué

Vous avez besoin d'un navigateur compatible Java pour afficher cette applet.

Figure 8.

Un exemple plus compliqué

Gestion des événements

Les exemples ci-dessus ne font rien de plus que d'afficher une interface utilisateur inerte. Il est, bien entendu, très important qu'une interface utilisateur agisse à la suite d'une entrée utilisateur. Il est cependant hors de la portée de cet article d'approfondir les mystères de la gestion des événements. Cela doit attendre un prochain article. Cependant, dans un souci d'exhaustivité, l'exemple de code du Listing 6 montre comment gérer un type d'événement qu'un programme peut recevoir. La nouvelle classe remplace la action()méthode fournie par la classe Component. La action()méthode répond aux événements d'action générés, par exemple, par la sélection d'un élément dans une liste contextuelle. leaction()nécessite que deux paramètres soient fournis, une instance Event et une instance Object. L'instance Event contient des informations sur l'événement, y compris la cible de l'événement (le composant qui a reçu l'événement en premier), les coordonnées x et y de l'événement et l'heure à laquelle l'événement s'est produit. L'instance Object contient une donnée spécifique à l'événement. Pour les objets Button, il contient le texte de l'étiquette du bouton.

import java.awt. *;

classe publique Example5 étend java.applet.Applet {TextArea ta = null;

public void init () {Panneau p;

setLayout (nouveau BorderLayout ());

p = nouveau panneau ();

ta = new TextArea ();

p.add (ta);

add ("Centre", p);

p = nouveau panneau ();

p.add (nouveau bouton ("One")); p.add (nouveau bouton ("Deux"));

Choix c = nouveau choix ();

c.addItem ("un"); c.addItem ("deux"); c.addItem ("trois");

p.add (c);

ajouter ("Sud", p); }

action publique booléenne (événement e, objet o) {chaîne str = (chaîne) o;

ta.appendText (str + "\ n");

retourner faux; }

public static void main (String [] args) {Frame f = new Frame ("Exemple 5");

Exemple5 ex = nouveau Exemple5 ();

ex.init ();

f.add ("Centre", ex);

f.pack (); f.show (); }}

Liste 6.

Un exemple avec la gestion des événements