Copyright (c) Martin Lafaix, 1996. Tous droits réservés. ©
Home | NetRexx | Un exemple plus conséquent

NetRexx - Un exemple plus conséquent

Dans le premier article de cette série, nous nous étions contenté d'une approche globale de NetRexx, en employant des exemples simples. Cette fois, nous allons réaliser une petite application complète.

Le sujet de cet article étant NetRexx et pas la boîte à outils Java, celle-ci est censée être connue.

Ce que nous allons faire

La boîte à outils Java contient de nombreux composants (plaquettes, cases à cocher, etc.), mais pas d'objets permettant d'afficher une image. Nous allons remédier à ce manque, en réalisant une application qui affiche des images.

Les premières décisions... et le premier code

NetRexx permet de créer deux sortes d'applications : des programmes au sens traditionnel du terme, c'est à dire des applications autonomes, ou des appliquettes (« applets »), sorte de modules appelés par un client HTML.

Dans un premier temps, nous allons réaliser une application traditionnelle. Nous garderons cependant à l'esprit le fait que l'on puisse souhaiter modifier ce choix et nous nous efforcerons donc de créer une application modulaire, de sorte qu'elle puisse facilement être modifiée.

Un composant afficheur d'image

Nous pourrions simplement créer une application qui afficherait une seule image, mais cela ne présenterait guère d'intérêt. Nous allons plutôt nous attacher à créer un nouveau composant qui, lui, affichera une image. Cela nous permettra par exemple d'afficher plusieurs images dans une application.

En fait, l'idéal serait de créer un vrai Component, tel que définit dans la boîte à outils Java. C'est donc ce que nous allons faire.

Ces décisions prises, il nous faut maintenant implémenter notre composant afficheur d'image. Comme nous souhaitons créer un composant, il faut qu'il hérite des propriétés de Component. Et comme nous pouvons considérer que nos images seront rectangulaires sans nous restreindre trop, et que nous sommes partisan du moindre effort, nous allons en fait hériter de la classe Canvas qui est justement là pour permettre de créer facilement nos propres composants.

Il ne nous reste plus maintenant qu'à écrire les quelques méthodes nécessaires au bon fonctionnement de notre afficheur. Ces méthodes sont un constructeur, afin de pouvoir créer un afficheur, et celles afférentes à l'affichage. Cerise sur le gâteau, notre composant sera aussi à même de retourner une taille par défaut, qui sera celle de l'image à afficher.

Un exemple de code implémentant notre composant est le suivant :

class ViewerComponent extends Canvas

 -- Drawing and layout properties
 properties private
 image=Image   -- shadow image

 /* Construct the component */
 method ViewerComponent(s)
   image=Toolkit.getDefaultToolkit.getImage(s)

 /* update  -- called in reponse to repaint() */
 method update(g=Graphics)
   paint(g)

 /* paint  -- called when the window needs to be resized or redrawn */
 method paint(g=Graphics)
   g.drawImage(image, 0, 0, size.width, size.height, this) -- copy to screen

 method preferredSize returns Dimension
   return Dimension(image.getWidth(this), image.getHeight(this))

Ce code ne présente guère de difficulté de compréhension. Tout d'abord, nous définissons un attribut, image, qui contiendra l'image. Nous avons ensuite un constructeur, ViewerComponent()[1]. Il accepte un argument, qui est le nom du fichier contenant l'image. Viennent alors les méthodes relatives à l'affichage : update(), appelée lorsque le composant doit être tout ou en partie réaffiché, et paint(), appelée lorsque le composant doit être affiché pour la première fois, ou si sa taille ou sa position change. Dans un soucis de simplification, lors des mises à jour de l'affichage, nous redessinons entièrement l'affichage. La dernière méthode est preferredSize(), qui retourne la dimension souhaitée pour le composant. Dans notre cas, la taille réelle de l'image.

Note: Dans le corps des méthodes, la variable locale this réfère par défaut à l'objet lui-même (i.e., si elle n'est pas redéfinie dans la méthode).

Une application qui utilise l'afficheur d'image

Maintenant que nous avons réalisé notre nouveau composant afficheur d'image, créons une petite application qui en fasse usage.

Comme nous voulons faire un programme autonome, et que nous devons créer une fenêtre --- afin que notre image s'affiche :-) --- nous allons faire hériter notre application de la classe Frame.

Un exemple de code utilisant notre composant afficheur d'image est le suivant :

class Viewer extends Frame         -- a Frame window object

 /* The 'main' method is called when this class is started as an application */
 method main(s=String[]) static
   Viewer("Viewer")                          -- make a Viewer

 /* The constructor/initializer for Viewer */
 method Viewer(s)
   super(s)                                  -- pass title to Frame

   -- setup the logical structure of the frame
   setLayout(BorderLayout())                 -- we must have a layout

   add("Center",ViewerComponent('mfc.gif'))  -- add new viewer image
   this.pack                                 -- recalculate the frame

   -- position centre-screen
   sizex=128; sizey=128
   screen=Toolkit.getDefaultToolkit.getScreenSize
   reshape((screen.width-sizex)%2,(screen.height-sizey)%2, sizex, sizey)

   this.show                                 -- and make us visible

 /* Method for handling events */
 method handleEvent(e=Event) returns boolean

   if e.id=Event.WINDOW_DESTROY then exit    -- exit on close
   return super.handleEvent(e)               -- otherwise take default action

Là encore, le code est relativement simple. Par rapport au code de notre composant, nous définissons ici en plus une méthode main(), car ce programme est destiné à être appelé par l'utilisateur (directement ou indirectement). Cette méthode prend comme argument un ensemble de chaînes de caractères qui correspondent aux arguments passés lors de l'appel du programme. (Cet ensemble est transmis sous la forme d'un tableau de chaînes de caractère.) Son unique action est ici de créer une instance de notre application, en appelant le constructeur d'icelle.

Le constructeur de notre application, Viewer(), peut paraître un peu compliqué au premier abord, même si en fait il est relativement simple. Il prend en argument une chaîne de caractère qui est le titre qui sera affiché dans la fenêtre. Ensuite, un layout simple est associé à la fenêtre, et notre composant afficheur d'image y est placé au centre. Enfin, nous centrons la fenêtre au milieu de l'écran, et nous l'affichons.

La troisième et dernière méthode définie, handleEvent(), surcharge celle définie dans la classe Frame. Elle est nécessaire ici parce que nous souhaitons pouvoir terminer l'exécution de notre application en sélectant l'option Arrêt/Fermeture du menu système de la fenêtre (ou en sélectant le bouton de fermeture de la barre de titre avec OS/2 Warp Version 4). Par défaut, l'application n'est pas interrompue lorsque cette option est sélectée, d'où le besoin pour nous de redéfinir ce comportement. Lorsque l'événement à gérer correspond à une demande d'arrêt de la part de l'utilisateur, nous quittons le programme. Sinon, nous utilisons le comportement par défaut, en passant l'événement à la méthode par défaut définie dans la superclasse[2], Frame.

Utiliser notre superbe application

Pour exécuter notre superbe application, il faut au préalable la compiler. Pour cela, il faut bien sûr avoir installé le kit de développement Java et NetRexx[3].

Créez ensuite un fichier ViewerComponent.nrx[4] dans lequel vous copierez le code du premier fragment de code donné plus haut. Créez également un fichier Viewer.nrx[5] dans lequel vous placerez le code du second fragment.

Pour compiler ces deux fichiers, utilisez alors la commande nrc :

  nrc ViewerComponent.nrx
  nrc Viewer.nrx

Note: Respectez l'ordre des appels, Viewer ayant besoin de trouver la classe ViewerComponent lors de sa compilation.

Lorsque vous avez obtenu les fichiers ViewerComponent.class et Viewer.class, et s'ils se trouvent dans un répertoire référencé par la variable d'environnement CLASSPATH, alors vous pourrez appeler la méthode main() de Viewer en utilisant :

  java Viewer

Note: Un fichier nommé mfc.gif doit aussi se trouver dans le répertoire en cours, ou dans un répertoire référencé par la variable d'environnement DPATH.

nrx1.png

Ah ! que c'est beau :-) Si vous avez utilisé le fichier mfc.gif qui se trouve dans le répertoire principal de NetRexx, vous avez devant vos yeux ébahis la photo de Mike F. Cowlishaw, l'inventeur de REXX et de NetRexx.

Améliorer notre application

La petite application que nous venons de créer est vraiment rudimentaire. Il manque bien sûr toutes les vérifications et contrôle d'erreur d'usage, et elle est quelque peu figée. Cependant, elle montre les capacités de notre composant afficheur d'image, en permettant par exemple le redimensionnement de la fenêtre, qui entraîne la modification correspondante de l'image.

Le layout employé (BorderLayout) est également assez limité.

Vous trouverez ici le code d'une application un peu plus conséquente, que vous pourrez plus facilement étendre à votre guise, qui utilise un GridBagLayout.

nrx0.png

Conclusions

Nous venons de voir comment créer un nouveau composant, et comment l'utiliser dans nos applications.

En fait, nous pouvons également utiliser ce composant à partir d'un programme Java, comme s'il avait été écrit en Java lui aussi.

Nous avons aussi vu comment créer des applications autonomes, en les faisant dériver de la classe Frame, et comment modifier légèrement le comportement d'une méthode, sans avoir à la réécrire entièrement.

Même s'il reste encore de nombreux aspects de NetRexx à aborder, vous en savez suffisamment pour commencer à voler de vos propres ailes. Bon vol, et prenez garde aux chasseurs :-)


Notes:
[1] Les constructeurs sont par définition des méthodes qui portent le nom de la classe.
[2] La superclasse d'une classe, c'est la (ou les) classes dont dérive une classe. Lorsque l'on parle de « la » superclasse d'une classe, on entend en général la superclasse directe d'une classe (i.e., celle spécifiée après le mot clef extends).
[3] Référez-vous au précédent article de cette série. Notez également que de nouvelles versions du kit de développement et de NetRexx ont été rendues disponibles fin octobre 1996.
[4] Par convention, les fichiers .nrx portent le nom de la classe publique qu'ils définissent. Ce n'est pas obligatoire, mais cela facilite grandement la vie.
[5] Idem.

Martin Lafaix