POO et Java TP JAVA 4 : INTRODUCTION AUX INTERFACES GRAPHIQUES Buts poursuivis par ce TP Il s’agit de mettre en place de petites applications qui n’ont d’autre but que de vous faire assimiler les mécanismes utilisés par les principaux objets de la bibliothèque AWT. Toutes les applications sont obtenues en dérivant la classe Frame. Les éléments qui devront être assimilés dans ce TP sont : La lecture des diagrammes de classe. Le mécanisme d’héritage de classe (un des concepts de la P.O.O). Le mécanisme d’héritage d’interface (contrat entre une classe et une interface) : un autre concept de la P.O.O. Les principaux concepts de P.O.O mis en œuvre dans la bibliothèque AWT. Le principe de la programmation événementielle (les différents types d’écouteurs et leur abonnement). Remarques : Lire le TP très attentivement. Les parties E1..E5 sont précédées d’un diagramme de classes de conception. 1. Projet TP4, classe E1. Couleur Bleue = Les développeurs de Java/Eclipse ont déjà fait le travail pour nous… donc nous n’avons qu’à comprendre et importer les « bons paquetages » ! Couleur Rouge = L’énoncé du TP nous demande de REFLECHIR et d’… ECRIRE « le BON CODE au BON ENDROIT » ! Object extends En Java, Object est la classe-mère de toutes les classes. Component extends Container extends Window + + public void addWindowListener(WindowListener l) public void setSize(int width,int height) a besoin extends Frame + + void setTitle(String title) void setVisible(boolean b) << interface >> WindowListener + + + + + + + void void void void void void void windowActivated (WindowEvent windowClosed (WindowEvent windowClosing (WindowEvent windowDeactivated(WindowEvent windowDeiconified(WindowEvent windowIconified (WindowEvent windowOpened (WindowEvent e) e) e) e) e) e) e) réalise spécialise (implements) (extends) écouté écouteur E1 + + + + + + + void void void void void void void windowActivated (WindowEvent windowClosed (WindowEvent windowClosing (WindowEvent windowDeactivated(WindowEvent windowDeiconified(WindowEvent windowIconified (WindowEvent windowOpened (WindowEvent e) e) e) e) e) e) e) E1 s’auto-écoute : L’exercice E1 illustre comment une classe E1 peut être son propre « écouteur de fenêtre ». Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 1/10 POO et Java Concepts à assimiler : Mettre en place un gestionnaire d’événements ou écouteur déclaré dans une interface. Objectif du TP : Afficher une fenêtre et mettre en place l'écouteur permettant de fermer la fenêtre. Travail demandé : Ajouter une classe E1 au projet TP4. Cette classe comporte une fonction main(). Dériver E1 de la classe Frame. Vous héritez maintenant de toute la hiérarchie de la classe Frame Dans le constructeur : Appeler la fonction setTitle (héritée de la classe Frame) pour donner le titre « Exercice E1 » à la fenêtre (pour trouver les fonctions accessibles dans l’objet courant, préciser this). Appeler la fonction setSize (héritée de la classe Frame) pour définir une taille de la fenêtre de 400 pixels de large et 200 pixels de haut. Dériver la classe E1 de l’interface WindowListener (voir cours comment dériver d'une interface). En dérivant WindowListener vous passez un contrat avec l’interface qui vous impose de définir (dans le jargon implémenter) toutes les fonctions déclarées dans cette interface. Nota : eclipse peut le faire pour vous (cliquer à la marge sur la croix rouge et choisir Add unimplemented methods). A l’aide de la méthode addWindowListener héritée de la classe Frame, abonner la fenêtre aux événements «window events» (voir cours). Dans le gestionnaire d’événements WindowClosing arrêter l’application avec System.exit(0); Dans main, instancier la classe E1 et afficher la fenêtre à l’aide de la fonction setVisible présente dans l’objet (hérité de la classe Frame). Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 2/10 POO et Java 2. Projet TP4, classe E2 << interface >> WindowListener Window + + public void addWindowListener(WindowListener l) public void setSize(int width,int height) a besoin extends + + + + + + + void void void void void void void windowActivated (WindowEvent windowClosed (WindowEvent windowClosing (WindowEvent windowDeactivated(WindowEvent windowDeiconified(WindowEvent windowIconified (WindowEvent windowOpened (WindowEvent e) e) e) e) e) e) e) Frame + void setTitle(String title) réalise spécialise (implements) (extends) << abstract >> WindowAdapter E2 écouté E2 possède un écouteur externe : L’exercice E2 illustre comment une classe autre que E2 (ici MyWindowClassAdapter) peut aussi être « écouteur de fenêtre » de la classe E2 en héritant d’un adaptateur » qui fait le travail « fastidieux » à notre place. + + + + + + + void void void void void void void windowActivated (WindowEvent windowClosed (WindowEvent windowClosing (WindowEvent windowDeactivated(WindowEvent windowDeiconified(WindowEvent windowIconified (WindowEvent windowOpened (WindowEvent e) e) e) e) e) e) e) spécialise écouteur (extends) MyWindowClassAdapter + void windowClosing (WindowEvent e) Concepts à assimiler : Redéfinir (traduction de overload) un gestionnaire d’événement ou écouteur défini dans une classe abstraite. Description et objectif du TP : Dans le TP précédent vous avez défini les nombreuses fonctions déclarées dans l’interface WindowListener. Sans l’aide d’eclipse, ce travail aurait été très fastidieux. Les concepteurs de la bibliothèque AWT ont prévu un mécanisme alternatif très astucieux consistant à faire hériter une classe abstraite (dans le cas présent WindowAdapter) de l’interface WindowListener. Cette classe définit toutes les fonctions de l’interface par des fonctions vides (comme la plupart des gestionnaires définis dans l’exercice E1). La classe WindowAdapter est rendue abstraite (par le préfixe abstract) pour interdire toute instanciation directe de la classe, instanciation ne présentant aucun intérêt (la classe ne comporte que des fonctions vides). Par contre en héritant de cette classe vous n’aurez besoin que de redéfinir la ou les fonctions qui vous intéressent. Voici le code de la bibliothèque Java illustrant ce mécanisme : interface WindowListener { void windowActivated(WindowEvent e); void windowClosing (WindowEvent e); // ... } abstract class WindowAdapter implements WindowListener { public void windowActivated(WindowEvent e) { } public void windowClosing (WindowEvent e) { } // ... } Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 3/10 POO et Java // Il ne reste plus qu’à définir son propre écouteur venant en remplacement de celui situé dans WindowAdapter. // Attention l’écouteur doit avoir la même signature que la fonction équivalente définie dans WindowAdapter class MyWindowClassAdapter extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } Travail demandé : Ajouter une classe publique E2 au projet TP4. Cette classe comporte une fonction main(). Dériver E2 de la classe Frame. Dans un fichier séparé définir une classe publique MyWindowClassAdapter héritant de la classe abstraite WindowAdapter. Dans la classe MyWindowClassAdapter définir la fonction windowClosing. Cette fonction doit redéfinir la fonction windowClosing définie dans la classe héritée. Attention il faut la même signature (se reporter à la documentation du JDK et chercher WindowAdapter). Dans windowClosing appeler System.exit(0). Dans le constructeur de la classe E2 : Donner le titre «Exercice E2» à la fenêtre. Définir une taille de la fenêtre de 400 pixels de large et 200 pixels de haut. A l’aide de la fonction addWindowListener hérité de la classe Frame, abonner la fenêtre (c'està-dire l’objet courant de la classe E2) aux événements liés à la fenêtre. Cet abonnement est réalisé en instanciant la classe MyWindowClassAdapter dans le paramètre de la fonction (voir cours). Dans main instancier la classe E2 et afficher la fenêtre à l’aide de la fonction setVisible. Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 4/10 POO et Java 3. Projet TP4, classe E3 Container + void setLayout(LayoutManager mgr) + Component add(Component comp) spécialise (extends) MyWindowClassAdapter Window + + + void windowClosing public void addWindowListener(WindowListener l) public void setSize(int width,int height) (WindowEvent e) écouteur spécialise (extends) Frame + Label void setTitle(String title) void setText(String text) label1 spécialise (extends) écouté affiche le compteur dans E3 + int compteur - Label addLabel (String text) Button addButton(String text) + void actionPerformed(ActionEvent e) écouteur réalise (implements) button écouté Button void addActionListener(ActionListener l) << interface >> ActionListener void actionPerformed(ActionEvent e) a besoin E3 écoute son bouton : L’exercice E3 illustre le cas où la fenêtre E3 écoute son composant de type Button. E3 ajoute 2 composants label1:Label et button:Button à une fenêtre E3 qui joue le rôle d’« écouteur d’action » pour button, en réalisant l’interface « ActionListener » puis en s’abonnant auprès du bouton. Objectif principal : Mettre en place plusieurs contrôles et définir un gestionnaire d’événement par héritage d'interface. Regrouper dans une fonction (comme le fait WindowBuilder) l’essentiel de la glue associée à un contrôle. Rappel : Pour être accessible depuis plusieurs fonctions membres d’une classe, un objet ou une variable doit être déclarée en tant qu’attribut d’instance (portée private si l’accès est limité aux fonctions membres de la classe). Description et objectif du TP : Dans le TP précédent vous avez défini une classe dans laquelle vous avez mis en place un gestionnaire d’événement. Dans l’exercice présent vous allez apprendre : A mettre en place deux contrôles : un label et un bouton. A agencer dans une fenêtre des contrôles disposés suivant l’ordre d’ajout (FlowLayout). Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 5/10 POO et Java A associer à la fenêtre le gestionnaire d’événement du bouton (l'écouteur) de façon à faire réagir votre interface graphique aux actions du bouton. Le procédé utilisé pour définir le gestionnaire d’événements est le même que celui utilisé dans l’exercice E1, c'est-à-dire hériter d'une interface. Le bouton ne générant qu’un seul événement, les concepteurs de la bibliothèque AWT n'ont pas jugé utile de mettre en place un adaptateur similaire à celui utilisé dans l’exercice E2. Travail demandé : Ajouter une classe publique E3 au projet TP4. Cette classe comporte une fonction main(). Dériver E3 de la classe Frame. Dans cette classe : Définir une variable d’instance (par exemple compteur) de type entier et l'initialiser à 0. Cette variable sera incrémentée à chaque appui sur le bouton. Définir une référence d’instance label1 de type Label et l’initialiser null. Dans le constructeur de la classe E3: Donner le titre « Exercice E3 » à la fenêtre. Définir une taille de la fenêtre de 400 pixels de large et 200 pixels de haut. Spécifier le mode d’agencement FlowLayout des contrôles à l’intérieur de la fenêtre (voir cours), mettre en place le mécanisme de fermeture de la fenêtre (réutiliser la classe vue dans E2). Dans la classe E3, ajouter une fonction membre Label addLabel(String text). Dans cette fonction : Instancier un objet de classe Label local à la fonction étiqueté avec le texte spécifié par le paramètre formel. Ajouter la référence du label à la fenêtre et retourner cette référence. Dans le constructeur de la classe E3: Effectuer l’appel à addLabel en lui spécifiant dans le paramètre formel le texte « compteur ». Mémoriser la référence retournée dans l’attribut label1. Dans la classe E3, ajouter une fonction membre Button addButton(String text). Dans cette fonction qui sera complétée par la suite : Instancier un objet local button de classe Button étiqueté avec le texte spécifié par le paramètre formel, ajouter le bouton à la fenêtre et retourner la référence du bouton. Dans le constructeur de la classe E3: Effectuer l’appel à addButton en lui spécifiant dans le paramètre effectif « Appuyer moi ! ». Mise en place de l'abonnement de l'écouteur du bouton dans la fonction addButton. Le bouton peut être enfoncé soit par la souris ou par le clavier. Tous ces événements sont réunis dans une fonction déclarée dans l’interface ActionListener. Dériver la classe E3 de l’interface ActionListener. Dans la classe E3 Définir le gestionnaire d’événements (écouteur) déclarée dans l’interface ActionListener. Nota : eclipse peut le faire pour vous. Dans la fonction addButton, abonner votre fenêtre à l’événement lié au bouton (pour la formation du nom de la fonction et la syntaxe voir cours). Dans le gestionnaire d’événements (écouteur) lié au bouton, incrémenter la variable d’instance compteur et afficher sa valeur sur le label label1 à l’aide de la fonction setText de l’objet label1. Dans main instancier la classe E3 et afficher la fenêtre à l’aide de la fonction setVisible. Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 6/10 POO et Java 4. Projet TP4 classe E4 Frame + + void setTitle(String title) void setVisible(boolean b) spécialise Label (extends) label1 E4 saisie - Label addLabel (String text) TextField addTextField(int taille) void setText(String text) + + void addKeyListener(KeyListener l) String getText() écouté « anonyme » écoute TextField : L’exercice E4 ajoute label1:Label et saisi:TextField à la fenêtre E4 puis crée et abonne un objet anonyme instancié d’une classe anonyme spécialisant la classe « KeyAdapter ». Seule la méthode « keyReleased() » est redéfinie et elle provoque la recopie du texte écrit dans saisie dans label1. void keyTyped (KeyEvent e) void keyPressed (KeyEvent e) void keyReleased(KeyEvent e) lit le texte saisi crée écouteur déclencheur << anonyme >> + void keyReleased(KeyEvent e) spécialise (extends) << interface >> KeyListener + + + écrit texte TextField << abstract >> KeyAdapter réalise (implements) + + + void keyTyped (KeyEvent e) void keyPressed (KeyEvent e) void keyReleased(KeyEvent e) Objectif principal : Mettre en place un gestionnaire d’événements (écouteur) défini dans une classe anonyme. Nota : ce mécanisme est celui utilisé par WindowsBuilder. Travail demandé : Ajouter une classe publique E4 au projet TP4. Cette classe comporte une fonction main. Dans le constructeur : Donner le titre « Exercice E4 » à la fenêtre. Définir une taille de la fenêtre de 400 pixels de large et 200 pixels de haut. Spécifier le mode d’agencement FlowLayout des contrôles à l’intérieur de la fenêtre. Dans la classe E4 : Ajouter un attribut d’instance privé label1 de classe Label. Ajouter une fonction membre Label addLabel(String text) (voir classe E3). Ajouter une fonction membre TextField addTextField(int taille). Dans cette fonction : Instancier un objet local de classe TextField (par exemple saisie). La taille de la zone est spécifiée dans le paramètre formel taille (voir documentation du JDK). Abonner saisie aux événements générés le contrôle TextField. Note : une zone de saisie peut générer plusieurs événements (textValueChanged, actionPerformed, ...). Si on désire gérer une saisie au plus bas niveau (par exemple pour un jeu) il faut utiliser l’événement Key. Celui-ci permet de gérer l’appui ou le relâchement d’une touche. Dans cet exercice on mettra en œuvre l’événement Key. Mise en place du gestionnaire d’événement Key : 1) Dans la fonction addTextField appeler la fonction membre addKeyListener de l’objet saisie. Dans le paramètre de la fonction : Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 7/10 POO et Java 2) Instancier une classe anonyme dérivée de la classe abstraite KeyAdapter. Comment définir une classe anonyme (voir cours pour plus de détails) ? La définition de ce type de classe est similaire à celle d’une classe « normale ». Exemple : classe « normale » dérivant de la classe Y et définissant une fonction de portée public qui ne fait rien : class X extends Y { public void uneFonctionQuiNeFaitRien() { } } Une classe anonyme dérivant de la classe Y et définissant une fonction de portée public qui ne fait rien s’écrit : extends Y { public void uneFonctionQuiNeFaitRien() { } } Instancier cette classe anonyme s’écrit : new Y() { public void uneFonctionQuiNeFaitRien() { } } 3) Redéfinir la fonction keyReleased dans la classe anonyme. Attention respecter la signature de keyReleased (voir la documentation du JDK, classe KeyAdapter). Dans keyReleased recopier le contenu texte du champ TextField dans la zone texte de l’objet label1. Nota pour être accessible dans la classe interne la référence saisie doit être déclarée avec l’attribut final. 4) Toujours dans la fonction addTextField, ajouter la référence du textField à la fenêtre et retourner cette dernière. Dans le constructeur de la classe E4: Effectuer l’appel à addLabel en spécifiant dans le paramètre formel un texte comportant environ 20 caractères espace. Mémoriser la référence retournée dans l’attribut label1. Effectuer l’appel à AddTextField en précisant dans le paramètre formel une taille de 20 caractères. Dans main instancier la classe E4 et afficher la fenêtre à l’aide de la fonction setVisible. Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 8/10 POO et Java 5. Projet TP4 classe E5 Frame + + void setTitle(String title) void setVisible(boolean b) spécialise Label (extends) label1 E5 void setText(String text) choice1 - Label addLabel (String text) Choice addCombo(int x, int y) écrit texte Choice + + void addItemListener(ItemListener l) String getSelectedItem() écouté lit le texte de l’item sélectionné crée L’exercice E5 réalise la synthèse des exercices précédents. Ajout de label1:Label et choice1:Choice à la fenêtre E5 puis création et abonnement d’un objet anonyme instancié d’une classe anonyme réalisant l’interface « ItemListener ». L’unique méthode « itemStateChanged() » est redéfinie. Elle provoque la recopie du texte associé à l’item sélectionné dans saisie dans la zone de texte de label1. écouteur déclencheur << anonyme >> + void itemStateChanged(ItemEvent e) réalise (implements) << interface >> ItemListener + void itemStateChanged(ItemEvent e) Objectif principal : Consolider les connaissances acquises lors des exercices précédents. Le diagramme de classe de conception illustre votre code à réaliser. Travail demandé : Ajouter une classe publique E5 au projet TP4. Cette classe comporte une fonction main. Dans la classe E5 : Définir un attribut privé label1 de classe Label; Définir un attribut privé choice1 de classe Choice; Définir une fonction Label addLabel(String text) (voir classe E3). Dans le constructeur : Donner le titre «Exercice E5» à la fenêtre. Définir une taille de la fenêtre de 400 pixels de large et 200 pixels de haut. Spécifier le mode d’agencement FlowLayout pour les contrôles. Appeler la fonction addLabel et mémoriser la référence retournée dans label1. Dans la classe E5 : Définir une fonction Choice addCombo(int x, int y). Dans cette fonction : a. Instancier une boite combo (classe Choice). Définir une taille de combo égale à x, y. Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 9/10 POO et Java b. Ajouter le contrôle à la fenêtre c. Abonner le contrôle Choice et définir l’écouteur dans une classe anonyme de façon similaire à l’exercice 4. Pour ce faire : Définir le gestionnaire d’événements dans une classe anonyme dérivant l’interface ItemListener. Nota : cette interface ne définit qu’une seule méthode itemStateChanged (voir la signature de la méthode dans la documentation du JDK). Dans l’écouteur gérer l’événement itemStateChanged en recopiant l’item sélectionné à l’aide du combo dans la zone texte du label1. d. Retourner la référence du contrôle. Dans le constructeur : Appeler la fonction addCombo en précisant dans les paramètres effectifs une taille de combo de 100x100, mémoriser la référence retournée dans l’attribut choice1. A l’aide de l’objet choice1 ajouter au combo les éléments String suivants : -Item 1-Item 2-Item 3-Item 4- Dans main instancier la classe E5 et afficher la fenêtre à l’aide de la fonction setVisible. Quel que soit l'avancement du TP, archiver vous projets à la fin de la séance et copier les dans le répertoire qui vous est destiné (U:\JAVA\2A\TP_ETUDIANTS). Vous disposez d'une semaine pour compléter votre TP. Daniel Tschirhart & Pierre Sosinski - TP4 POO et Java Introduction aux interfaces graphiques 10/10