Graphical User Interface Construire une interface graphique en Java Cours de P. Genoud
Avertissement L ’objectif de ce cours est de présenter les différentes techniques concernant la construction d ’une interface graphique en JAVA. La conception d ’interfaces graphique étant loin d ’être triviale, et les packages proposés pour cela par le JDK étant parmi les plus « complexes » nous n ’avons pas la prétention d ’être exhaustif. Il s’agit de donner les éléments de bases qui vous permettront ensuite d ’aller plus loin dans la création d ’interfaces utilisateur. Une partie de ce cours est basée sur un exemple tiré du chapitre 4 du livre « Java La Synthèse , 2ème edition » de G. Clavel, N. Mirouze, S. Moucherot, E. Pichon et M. Soukal (InterEditions). Certains éléments concernant la gestion des événements sont directement inspirés du cours « Swing Crash course » de Matthias Hauswirth que vous trouverez dans les compléments du cours. On pourra également se référer au chapitre 7 du livre « JAVA in a Nutshell » de David Flanagan, Ed. O'Reilly 1997. Le « Java tutorial » est aussi un outil indispensable http://java.sun.com/tutorial La partie du tutorial concernant Swing est placée aussi dans les compléments du cours.
Fenêtre d’application Toute fenêtre d’application est représentée par une classe dérivant ou utilisant la classe Frame du package java.awt import java.awt.*; public class MyFrame extends Frame { final static int HAUTEUR = 200; final static int LARGEUR = 300; public MyFrame() { setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); show(); } public static void main(String[] args) { new MyFrame(); System.out.println("Coucou, après le show"); se comporte comme toute fenêtre du système d ’exploitation : peut être redimensionnée, déplacée, … mais ne peut être pour l’instant fermée (ce comportement devra être programmé par le concepteur de la fenêtre) affiche la fenêtre à l’écran lance un « thread » d ’exécution pour gérer interactions sur cette fenêtre l ’exécution du programme principal se termine que lorsque le « thread » lié à la fenêtre se termine lui aussi
Création d’un menu Ajouter à l ’application éditeur graphique un menu rudimentaire Classes utilisées : MenuBar : représente la barre de menu d’une fenêtre Menu : options visibles dans la barre de menu Fichier Nouveau Quitter Aide A propos MenuItem :Items qui déclencheront par leur sélection des actions définies par le programmeur
Création d’un menu Classes utilisées : MenuBar : représente la barre de menu d’une fenêtre import java.awt.*; public class MenuEditeur extends MenuBar { MenuItem quitter, nouveau, aPropos; public MenuEditeur() { Menu menuFichier = new Menu("Fichier"); nouveau = new MenuItem("Nouveau"); quitter = new MenuItem("Quitter"); menuFichier.add(nouveau); menuFichier.addSeparator(); menuFichier.add(quitter); Menu menuAide = new Menu("Aide"); aPropos = new MenuItem("A propos"); menuAide.add(aPropos); this.add(menuFichier); this.add(menuAide); } } // MenuEditeur Menu : options visibles dans la barre de menu MenuItem :Items qui déclencheront par leur sélection des actions définies par le programmeur Fichier Nouveau Quitter 1) création des éléments du menu Fichier Nouveau Quitter 2) association des objets MenuItem dans un objet Menu 3) ajout des objets Menu dans l’objet MenuBar (this) Fichier Nouveau Quitter Aide A propos
Insertion du menu dans la fenêtre Seule une instance de la classe Frame peut héberger un menu import java.awt.*; public class MyFrame extends Frame { final static int HAUTEUR = 200; final static int LARGEUR = 300; public MyFrame() { setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); show(); } public static void main(String[] args) { new MyFrame(); setMenuBar(new MenuEditeur()); setMenuBar prend en paramètre une instance de la classe MenuBar : soit une instance directe de MenuBar qui aura été modifiée grâce au méthodes add(…) soit une instance d ’une classe dérivée de MenuBar comme dans le cas présent
Structure de l’interface graphique Création de l ’interface graphique passe forcément par une instance de la classe Frame Du point de vue du système d ’exploitation cette fenêtre représente l ’application La fenêtre joue le rôle de « conteneur » dans lequel vont être disposés les différents éléments constitutifs (composants) de l ’interface graphique de l ’application (boutons, listes déroulantes, zône de saisie…) ces éléments désignés sous les termes de contrôles (IHM) composants (component en JAVA) widgets (Xwindow-Motif)
Composants graphiques de AWT Hiérarchie de classes couvrant les composants de awt Label Button CheckBox Choice Canvas List TextComponent ScrollBar TextField TextArea Checkbox Component Classe abstraite décrit caractéristiques communes à tous les composants Object Container Classe abstraite composants pouvant contenir d’autres composants Window Panel Frame Dialog FileDialog ScrollPane
Composants graphiques de AWT awt = Abstract Window Toolkit conçu dans un souci de portabilité d ’une plateforme à l’autre conception pas toujours très judicieuse d’ailleurs (cf les évolutions de awt entre version 1.0 et 1.1 de Java) intersection des possibilités des différentes plateformes seuls les composants standard existants dans tous les systèmes d ’exploitation peuvent être présent dans awt palette de composants fournies par awt ne contient que des composants simples en 1997 Sun annonce les Java Fundation Classes (JFC) pour la création d ’interface graphiques plus élaborées multiplication des composants plus riches en fonctionnalités (listes arborescentes, grilles….) ajout à JDK 1.1 en tant que package externe intégré à Java 2 (JDK 1.2)
Java Fundation Classes JFC : Java Fundation Classes JFC = Swing + Java 2D API + copier coller inter-applications Swing Composants légers (lightweight) 100% java Prennent en charge leur affichage sans passer par des objets « Peers » gérés par le système -> pas de code natif aspect de l ’IHM : Motif, Windows, Métal, Mac modèle MVC (Model View Controler) Alors quel package utiliser : AWT ou Swings ??? « Swing provides many benefits to programmers and end users. Unless you have a good reason not to convert (and use AWT), we urge you to convert to Swing as soon as possible. » M. Campione - K. Walrath « the Java Tutorial » Puisqu ’elles le disent, allons-y…
Conversion de awt vers Swing La bibliothèque Swing a été conçue pour permettre une conversion « relativement » aisé des applications écrites à l’aide d’awt (1.1) import java.awt.*; public class MyFrame extends Frame { final static int HAUTEUR = 200; final static int LARGEUR = 300; public MyFrame() { setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); setMenuBar (new MenuEditeur()); show(); } public static void main(String[] args) { new MyFrame(); public class MenuEditeur extends MenuBar { MenuItem quitter, nouveau, aPropos; public MenuEditeur() { Menu menuFichier = new Menu("Fichier"); nouveau = new MenuItem("Nouveau"); quitter = new MenuItem("Quitter"); menuFichier.add(nouveau); menuFichier.addSeparator(); menuFichier.add(quitter); Menu menuAide = new Menu("Aide"); aPropos = new MenuItem("A propos"); menuAide.add(aPropos); this.add(menuFichier); this.add(menuAide); } // MenuEditeur Dans bien des cas il suffit d ’ajouter un ‘ J ’ au nom des classes des composants awt import javax.swing.*; J setJMenuBar
Ajout d’un composant à une fenêtre Avec AWT Avec les Swings import java.awt.*; public class MyFrame extends Frame { final static int HAUTEUR = 200; final static int LARGEUR = 300; public MyFrame() { setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); setMenuBar(new MenuEditeur()); show(); } import javax.swing.*; public class MyFrame extends JFrame { final static int HAUTEUR = 200; final static int LARGEUR = 300; public MyFrame() { setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); setMenuBar(new MenuEditeur()); JButton b = new JButton("Mon 1er composant"); this.getContentPane().add(b); show(); } 1) Création du composant 2) ajout au « conteneur » Button b = new Button("Mon 1er composant"); add(b); Un composant ne peut être directement inséré dans une JFrame, mais à son « content pane » qui doit être récupéré au préalable
Composants graphiques Swings Hiérarchie très partielle des classes couvrant les composants des swings Object Container Component Window Panel Frame Dialog Button ... awt Classe abstraite décrit caractéristiques communes à tous les contrôles Swings JComponent AbstractButton Box JButton JMenuItem JToggleButton JColorChooser JLabel JPanel JRadioButton JCheckBox ... JMenu JFrame JWindow JDialog
Imbrication des composants Pour structurer l’interface graphique utilisation de Jpanels exemple : ajout d ’une barre d’outils à l’éditeur graphique import java.awt.*; import javax.swing.*; public class BarreOutils extends JPanel { public BarreOutils() { String[] libelleCouleurs = {"Bleue", "Rouge", "Jaune", "Vert"}; Color[] couleurs = { Color.blue, Color.red, Color.yellow, Color.green }; this.setBackground(Color.lightGray); JComboBox listeCouleurs = new JComboBox(); for (int i = 0; i < libelleCouleurs.length; i++) listeCouleurs.addItem(libelleCouleurs[i]); this.add(listeCouleurs); this.add(new JButton("Défaire")); this.add(new JButton("Tout effacer")); this.add(new JButton("Quitter")); } } // BarreOutils JCButton JPanel JComboBox import javax.swing.*; public class MyFrame extends JFrame { final static int HAUTEUR = 200; final static int LARGEUR = 300; public MyFrame() { setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); setJMenuBar(new MenuEditeur()); Container content =this.getContentPane(); content.add(new BarreOutils()); show(); }
Placement des composants Dans les exemples précédents les composants se sont placés automatiquement Pour la barre d’outils au centre du JPanel Mécanismes par défaut Possibilité de les adapter aux besoins particulier de l’application LayoutManager objet associé à un Container se charge de gérer la disposition des composant appartenant à celui-ci Par exemple Layout par défaut pour les Jpanels composants placés les uns après les autres dans leur ordre d’ajout le tout doit être centré réordonnancement automatique des composants lorsque la fenêtre est redimensionnée
Placement des composants 5 gestionnaires de mise en forme implémentant l ’interface LayoutManager sont prédéfinis dans awt : BorderLayout FlowLayout GridLayout CardLayout GridBagLayout North South West East Center java.awt.BorderLayout add(Component,String) three one two four five java.awt.FlowLayout add(Component) one two four five three six java.awt.GridLayout add(Component, index) D’autres sont définis dans les swings (BoxLayout, ….) Il est aussi possible de définir ses propres gestionnaires
Associe un GridLayout en spécifiant le nombre de lignes et colonnes Définition de la barre d ’état de l ’application import javax.swing.*; import java.awt.*; public class BarreEtat extends JPanel { private JLabel coord, info; public BarreEtat() { this.setBackground(Color.darkGray); this.setLayout(new GridLayout(1,2)); this.add(info = new JLabel()); this.add(coord = new JLabel()); } public void afficheCoord(int x, int y) { coord.setText("x : " + x + " y : " + y); public void afficheInfo(String message) info.setText(message); Associe un GridLayout en spécifiant le nombre de lignes et colonnes Ajout des composants dans les différentes cellules définies par le layout
Associe un BorderLayout en spécifiant espacement entre les composants Ajout d ’une zone de dessin et d ’une barre d ’état à la fenêtre de l’application ContentPane BorderLayout BarreOutils « North » FlowLayout (par défaut) Zone dessin « Center » GridLayout (1 ligne, 2 colonnes) BarreEtat « South» public MyFrame () { BarreEtat barreEtat; setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); setJMenuBar(new MenuEditeur()); this.getContentPane().setLayout(new BorderLayout(2,2)); this.getContentPane().add(new BarreOutils(),"North"); this.getContentPane().add(new ZoneGraphique(),"Center"); this.getContentPane().add(barreEtat = new BarreEtat(),"South"); barreEtat.afficheCoord(0,0); barreEtat.afficheInfo("coordonnées du cruseur"); show(); } Associe un BorderLayout en spécifiant espacement entre les composants Ajout des composants dans les différentes régions définies par le layout
Comment dimensionner les composants ? Jusqu ’à présent nous ne nous sommes pas préoccupés de la taille des composants Dans la barre d’outils les boutons n’ont pas tous la même taille (fixée automatiquement par le layout manager). Possibilité d ’indiquer une taille avec les méthodes setPreferredSize, setMinimumSize. public BarreOutils() { JComboBox listeCouleurs; String[] libelleCouleurs = {"Bleue", "Rouge", "Jaune", "Vert"}; Color[] couleurs = { Color.blue, Color.red, Color.yellow, Color.green }; this.setBackground(Color.lightGray); listeCouleurs = new JComboBox(); for (int i = 0; i < libelleCouleurs.length; i++) listeCouleurs.addItem(libelleCouleurs[i]); this.add(listeCouleurs); JButton b; this.add(b= new JButton("Défaire")); b.setPreferredSize(new Dimension(130,25)); this.add(b = new JButton("Tout effacer")); this.add(b = new JButton("Quitter")); } Indique les dimensions souhaitées, elles ne pourront pas toujours être respectées selon les contraintes et la politique de placement du LayoutManager
Comment dimensionner les composants ? Prise en compte des dimensions souhaitées selon le layout Layout FlowLayout BorderLayout (East, West) BorderLayout (North, South) BorderLayout(Center) GridLayout Hauteur oui non Largeur oui non Possibilité de se passer des services des LayoutManager et de placer les composants « à la main » en indiquant des positions et dimensions exprimées en pixels (setBounds, setSize) plus de souplesse mais attention lorsque redimensionnement des conteneurs (attention à la portabilité de l’interface graphique)
Gérer les événements Pour le moment les interactions de l ’utilisateur avec les différents composants de l ’interface graphique ne provoquent aucune action Les applications comportant une interface graphique sont dirigées par les événements (event-driven) elles ne font rien jusqu'à ce que l'utilisateur bouge la souris, clique un bouton ou appuye sur une touche… Le coeur de toute application comportant une interface graphique est le code de traitement des événements. un programme dirigé par les événements est structuré autours d'un modèle de traitement des événements. Bien comprendre ce modèle est important pour une bonne programmation. dans JAVA , malheureusement le modèle de gestion des événements a radicalement (et heureusement) changé entre la version 1.0 et la version 1.1 (nous n ’aborderons ici pas le modèle du JDK 1.0, on se réferrera aux notes de cours complémentaires)
Modèle événementiel du JDK 1.1 Objectifs de conception simple et facile à apprendre séparation nette entre application et code de l'interface utilisateur faciliter l'écriture de code de gestion des événements qui soit robuste ("strong compile time checking") suffisament flexible pour autoriser selon les applications des modèles différents pour le flot et la propagation des événements pour les concepteurs d'outils visuels permettre de découvrir à l'exécution les événements qu'un composant peut générer les événements qu'il peut observer supporter une compatibilité binaire avec l'ancien modèle Ce nouveau modèle est utilisé par AWT, les Swings et sert également aux JAVA BEANS
Modèle événementiel du JDK 1.1 le modèle événementiel de JDK 1.1 se compose : d'objets sources d'événements d'objets événements d'objets récepteurs d'événements Ces objets interagissent de façon standard en invoquant des méthodes pour permettre le déclanchement et la gestion des événements unObjet 2 actionPerformed(unEvnt ) Récepteur d ’évenéments Activer JButton MonBouton Source d ’évenéments 3 getSource() ActionEvent unEvnt 1 new ActionEvent( )
EventObject(Object source) Objets Evénement Un objet événement encapsule une information spécifique à une instance d'événement exemple : un événement représentant un clic souris contient la position du pointeur souris Les différents types d'événements sont représentés par des classes différentes ActionEvent, MouseEvent Toute classe d'événement est sous classe de la classe java.util.EventObject Object EventObject EventObject(Object source) Object getSource( ) les différents types d'événements liés à AWT héritent de AWTEvent sont rangés dans le package java.awt.event AWTEvent int id MouseEvent int getX(), int getY() ActionEvent String getCommand() ... Permet d ’identifier plusieurs types d ’événements dans une même classe Définit 7 types d’évenéments MOUSE_CLICKED, MOUSE_DRAGGED MOUSE_ENTERED, MOUSE_EXITED, MOUSE_MOVED, MOUSE_PRESSED, MOUSE_RELEASED
Récepteurs d’événements un récepteur d'événements est un objet qui doit être prévenu (notified) par la source lorsque certains événements se produisent les notifications d'événements se font en invoquant des méthodes de l'objet à l'écoute, l'objet événement étant transmis en paramètre la source d'événements doit savoir quelle méthode du récepteur doit être appelée pour chaque classe d'événements une interface spécifique définit les méthodes à appeler pour notifier les événements de cette classe exemple : interface ActionListener pour les ActionEvents toute classe désirant recevoir des notifications d'un événement donné devra implémenter cette interface un recepteur d ’ActionEvent doit implémenter la méthode public void actionPerformed(ActionEvent e) définie par l ’interface ActionListener
Interfaces d ’écoute d ’événements toutes les interfaces d ’écoute d'événements héritent de java.util.EventListener par convention toutes les interfaces des récepteurs d'événements ont des noms de la forme <EventType>Listener exemple : les événements de AWT et les interfaces correspondantes pour les récepteurs Classe d ’événement ActionListener AdjustmentListener ComponentListener ContainerListener FocusListener ItemListener KeyListener MouseListener MouseMotionListener TextListener WindowListener Interface d ’écoute ActionEvent AdjustmentEvent ComponentEvent ContainerEvent FocusEvent ItemEvent KeyEvent MouseEvent TextEvent WindowEvent
Interfaces d’écoute d ’événements Une interface d ’écoute d'événements peut contenir un nombre quelconque de méthodes, chacune correspondant à un événement différent < interface > MouseListener void mouseClicked(MouseEvent) void mouseEntered(MouseEvent) void mouseExited(MouseEvent) void mousePressed(MouseEvent) void mouseReleased(MouseEvent) MouseEvent définit 7 types d’événements MOUSE_CLICKED MOUSE_ENTERED MOUSE_EXITED MOUSE_PRESSED MOUSE_RELEASED MOUSE_DRAGGED MOUSE_MOVED < interface > MouseMotionListener void mouseMoved(MouseEvent) void mouseDragged(MouseEvent) Les méthodes définies dans les interfaces d’écoute doivent se conformer au schéma standard : void <eventOccurenceMethodName>(<EventObjectType> evt); où eventOccurenceMethodName décrit clairement l'événement qui sera déclanché EventObjectType est le type de l'événement déclenché et dérive obligatoirement de java.util.EventObject
Sources d’événements événements générés par des sources d'événements (event sources) source d'événements, un objet capable de: déterminer quand un événement "intéressant" s'est produit d'avertir (notify) des objets récepteurs (event listeners) de l'occurrence de cet événement pour être averti des événements produits par une source un récepteur doit se faire enregistrer auprès de la source addActionListener(unObjet) 1 Activer JButton MonBouton Source d ’évenéments unObjet Récepteur d ’évenéments 2 actionPerformed(unEvnt ) ... 3 actionPerformed(unEvnt ) removeActionListener(unObjet) 4
Sources d ’événements Plusieurs récepteurs peuvent être à l’écoute d ’une même source d’événements addActionListener(unObjet) 1 Activer JButton MonBouton Source d ’évenéments unObjet Récepteur d ’évenéments 2 actionPerformed(unEvnt ) 4 actionPerformed(unEvnt ) 3 addActionListener(unAutreObjet) 5 actionPerformed(unEvnt ) unAutreObjet Récepteur d ’évenéments lorsqu'un événement se produit il se déclenche vers tous les récepteurs d'événements (multicast)
actionPerformed(unEvnt ) actionPerformed(unEvnt ) Sources d’événements Un récepteur peut être à l ’écoute de plusieurs sources différentes ActionEvent unEvnt new ActionEvent( ) 4 Activer JButton bouton1 Source d ’évenéments DesActiver bouton2 unObjet Récepteur d ’évenéments 6 getSource() 5 actionPerformed(unEvnt ) 2 actionPerformed(unEvnt ) getSource() 3 ActionEvent unEvnt 1 new ActionEvent( )
Sources d’événements Une source d'événements pour une interface d’écoute d'événements propose une méthode d'enregistrement dont la signature a la forme suivante : public void add<ListenerType>(<ListenerType> listener) A tout moment un objet récepteur d'événements peut annuler sa demande de notification Une source d'événements pour une interface réceptrice d'événements propose une méthode d'annulation de notification dont la signature a la forme suivante : public void remove<ListenerType>(<ListenerType> listener)
Exemple de gestion des événements Afficher les coordonnées de la souris lorsqu’elle se déplace sur la zône de dessin. Type d ’événements : MouseEvent (MOUSE_MOVED, MOUSE_DRAGGED) Source d ’événements : la zône de dessin Interface d’écoute : MouseMotionListener Recepteur d ’événements ? Devra modifier l ’affichage de la barre d ’état Plusieurs solutions sont possibles. Prenons le cas où le recpeteur est la zône graphique elle même elle devra s’enregistrer auprès d’elle même pour être à l ’écoute des MouseMotionEvent générés sur elle elle devra avoir connaissance de l ’objet gérant la barre d ’état (la référence de celui-ci sera passée en paramètre du constructeur de la zône graphique)
Exemple de gestion des événements Code de la classe représentant la zone graphique import java.awt.*; import javax.swing.*; import java.awt.event.*; public class ZoneGraphique extends JPanel implements MouseMotionListener { private BarreEtat be; public ZoneGraphique(BarreEtat be) { setBackground(Color.white); setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); this.be = be; addMouseMotionListener(this); } public void mouseMoved(MouseEvent e) { be.afficheCoord(e.getX(),e.getY()); public void mouseDragged(MouseEvent e) { } // ZoneGraphique L ’objet zone graphique va être à l ’écoute des événements MouseEvent de type MouseMotion 1 L ’objet zone graphique s ’enregistre lui même comme récepteur des événements MouseEvent de type MouseMotion qu ’il est susceptible de générer 3 L ’objet zone graphique utilise les informations contenues dans l ’objet MouseEvent qui lui est transmis pour mettre à jour la barre d’état. 2
Exemple de gestion des événements Code de la classe lançant l ’application import javax.swing.*; public class EditeurGraphique extends JFrame { final static int HAUTEUR = 450; final static int LARGEUR = 750; public MyFrame7() { BarreEtat barreEtat = new BarreEtat(); setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); setJMenuBar(new MenuEditeur()); this.getContentPane().add(new BarreOutils(),"North"); this.getContentPane().add(new ZoneGraphique(barreEtat),"Center"); this.getContentPane().add(barreEtat,"South"); barreEtat.afficheInfo("coordonnées du curseur"); show(); } public static void main(String[] args) { new MyFrame7(); } // MyFrame L ’objet zone graphique a connaissance de l ’objet barre d ’état pour pouvoir agir sur lui lors de la réception des MouseEvent
Pour conclure (momentanément) Pour gérer les événements il faut : identifier l ’objet à l ’origine des événements (souvent un composant) identifier le type de l ’événement que l ’on veut intercepter. Pour découvrir les types d ’événements qu ’est capable d émettre un composant lister dans sa classe toutes les méthodes de type addXXXListener créer une classe qui implémente l ’interface associée à l ’événement que l ’on veut gérer le choix de cette classe n ’est pas neutre celle du composant à l ’origine de l ’événement (facilté d ’implémentation) une classe indépendante qui détermine la frontière entre l ’interface graphique (émission des événements) et ce qui représente la logique de l ’application (traitement des événements). Une bonne séparation permet de facilté l ’évolution du logiciel. Implémenter dans cette classe la (les) méthode(s) associées à l ’événement. L ’événement passé en paramètre contient des informations qui peuvent être utiles (position du curseur, état du clavier, objet source de l ’événement).
Construction de l’interface graphique rappel JFrame Construction de l’interface graphique EditeurGraphique BarreOutils JPanel ZoneDessin 2 Source : la zone de dessin 3 Récepteur : la zone de dessin également BarreEtat Type d ’événement : MouseEvent (MOUSE_MOVED, MOUSE_DRAGGED) MouseEvent 1 Gestion de l ’interaction Déplacement de la souris sur la zone de dessin doit mettre à jour les coordonnées du curseur dans la barre d’état
rappel Code de la classe lançant l ’application import javax.swing.*; public class EditeurGraphique extends JFrame { final static int HAUTEUR = 450; final static int LARGEUR = 750; public EditeurGraphique { BarreEtat barreEtat = new BarreEtat(); setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); setJMenuBar(new MenuEditeur()); this.getContentPane().add(new BarreOutils(),"North"); this.getContentPane().add(new ZoneGraphique(barreEtat),"Center"); this.getContentPane().add(barreEtat,"South"); barreEtat.afficheInfo("coordonnées du cruseur"); show(); } public static void main(String[] args) { new EditeurGraphique(); } // MyFrame L ’objet zone graphique a connaissance de l ’objet barre d ’état pour pouvoir agir sur lui lors de la réception des MouseEvent
rappel Code de la classe représentant la zone graphique 1 3 2 import java.awt.*; import javax.swing.*; import java.awt.event.*; public class ZoneGraphique extends JPanel implements MouseMotionListener { private BarreEtat be; public ZoneGraphique(BarreEtat be) { setBackground(Color.white); setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); this.be = be; addMouseMotionListener(this); } public void mouseMoved(MouseEvent e) { be.afficheCoord(e.getX(),e.getY()); public void mouseDragged(MouseEvent e) { } // ZoneGraphique L ’objet zone graphique va être à l ’écoute des événements MouseEvent de type MouseMotion 1 L ’objet zone graphique s ’enregistre lui même comme récepteur des événements MouseEvent de type MouseMotion qu ’il est susceptible de générer 3 L ’objet zone graphique utilise les informations contenues dans l ’objet MouseEvent qui lui est transmis pour mettre à jour la barre d’état. 2
Adaptateurs d’événements Fermeture de la fenêtre Clic doit provoquer arrêt de l ’application EditeurGraphique JFrame 2 Source : l ’éditeur graphique (JFrame) Type d ’événement : WindowEvent (WINDOW_CLOSING) WindowEvent 1 3 Récepteur : l ’éditeur graphique
Adaptateurs d’événements Fermeture de la fenêtre Code de l ’Editeur Graphique import javax.swing.*; public class EditeurGraphique extends Jframe { final static int HAUTEUR = 450; final static int LARGEUR = 750; public EditeurGraphique { BarreEtat barreEtat = new BarreEtat(); setTitle("Ma première Fenêtre"); setSize(LARGEUR,HAUTEUR); setJMenuBar(new MenuEditeur()); this.getContentPane().add(new BarreOutils(),"North"); this.getContentPane().add(new ZoneGraphique(barreEtat),"Center"); this.getContentPane().add(barreEtat,"South"); barreEtat.afficheInfo("coordonnées du cruseur"); show(); } public static void main(String[] args) { new EditeurGraphique(); } // MyFrame import java.awt.event.*; L ’objet éditeur graphique va être à l ’écoute des événements WindowEvent 1 implements WindowListener { this.addWindowListener(this) L ’objet éditeur graphique s ’enregistre lui même comme récepteur des WindowEvent qu’il est susceptible de générer 2 Mais maintenant il faut aussi implémenter les méthodes de l ’interface WindowListener
Adaptateurs d’événements Fermeture de la fenêtre WindowEvent définit plusieurs sous types d’événements windowActivated(WindowEvent) Invoked when a window is activated windowClosed(WindowEvent) Invoked when a window has been closed. windowClosing(WindowEvent) Invoked when a window is in the process of being closed. windowDeactivated(WindowEvent) Invoked when a window is de-activated. windowDeiconified(WindowEvent) Invoked when a window is de-iconified. windowIconified(WindowEvent) Invoked when a window is iconified. windowOpened(WindowEvent) Invoked when a window has been opened. WindowListener définit plusieurs méthodes, une pour chacun de ces types WINDOW_ACTIVATED WINDOW_CLOSED WINDOW_CLOSING WINDOW_DEACTIVATED WINDOW_DEICONIFIED WINDOW_ICONIFIED WINDOW_OPENED public class EditeurGraphique implements WindowListener { public EditeurGraphique() { … this.addWindowListener(this); this.show(); } public static void main(String[] args) { new EditeurGraphique(); Dans le cas présent seuls les événements WINDOW_CLOSING nous intéressent Mais quand on implémente une interface il faut implémenter toutes les méthodes qu’elle définit public void windowClosing(WindowEvent e){ System.exit(0); } public void windowActivated(WindowEvent e){;} public void windowOpened(WindowEvent e){;} ... corps vide
Adaptateurs d’événements Fermeture de la fenêtre Adaptateur d’événements WindowAdapter dans package java.awt.event public class ClosingAdapter extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } Etendre la classe WindowAdapter n'implémenter que la méthode qui nous concerne public class EditeurGraphique implements WindowListener { public EditeurGraphique() { … this.addWindowListener(new ClosingAdapter()); this.show(); } public static void main(String[] args) { new EditeurGraphique();
Adaptateurs d’événements Dessin des segments de droite Gestion des événements souris Déplacement de la souris sur la zone de dessin met à jour les coordonnées du curseur dans la barre d’état MOUSE_MOVED, MOUSE_DRAGGED type d ’événement MouseEvent source : zone de dessin interface d ’écoute : MouseListener récepteur : zone de dessin Appuyer sur un bouton de la souris (MOUSE_PRESSED) définit le début d ’une droite Relacher le bouton de la souris (MOUSE_RELEASED) définit la fin de la droite < interface > MouseListener void mouseClicked(MouseEvent) void mouseEntered(MouseEvent) void mouseExited(MouseEvent) void mousePressed(MouseEvent) void mouseReleased(MouseEvent) Comme pour la fermeture de la fenêtre seule deux des méthodes de l ’interface nous intéressent
Adaptateurs d’événements Dessin des segments de droite import java.awt.*; import javax.swing.*; import java.awt.event.*; public class ZoneGraphique extends JPanel implements MouseMotionListener { private BarreEtat be; public ZoneGraphique(BarreEtat be) { setBackground(Color.white); setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); this.be = be; addMouseMotionListener(this); } public void mouseMoved(MouseEvent e) { be.afficheCoord(e.getX(),e.getY()); public void mouseDragged(MouseEvent e) { } // ZoneGraphique Pour ne pas avoir à définir des méthodes inutiles possibilité d ’utiliser un adaptateur d ’événements : MouseAdapter import java.awt.event.*; public class GestionnaireClic extends MouseAdapter { ZoneGraphique zone; public GestionnaireClic(ZoneGraphique z) { zone = z; } public void mousePressed(MouseEvent e) zone.initieDroite(e.getX(),e.getY()); public void mouseReleased(MouseEvent e) zone.termineDroite(e.getX(),e.getY()); addMouseListener(new GestionnaireClic(this)); public void initieDroite(int x, int y) { be.afficheMessage(" Relacher pour dessiner la droite "); // on complétera ensuite } public void termineDroite(int x, int y) { be.afficheMessage(" Cliquer pour initier une droite ");
Des adaptateurs aux classes internes Gestion des boutons de la barre d’outil Annule le dernier tracé Efface toute la zone de dessin type d ’événement ActionEvent source les JButton interface d ’écoute ActionListener récepteur ? L’activation des boutons doit se traduire par un changement d’état de la zone de dessin. Il semble naturel que cela soit la zone dessin qui récupère les événements et réalise les traitement adéquats.
Des adaptateurs aux classes internes import java.awt.*; import javax.swing.*; import java.awt.event.*; public class ZoneGraphique extends JPanel implements MouseMotionListener { private BarreEtat be; public ZoneGraphique(BarreEtat be) { …. } public void mouseMoved(MouseEvent e) { ... } public void mouseDragged(MouseEvent e) { ... } public void initieDroite(int x, int y) { ... } public void termineDroite(int x, int y) { ... } } // ZoneGraphique , ActionListener { 2) la zone graphique reçoit les événe-ments issus des boutons public void actionPerformed(ActionEvent e) { selon l ’origine de l’événement efface() ou annule() } le code zone graphique dépend du code de la barre d ’outil. 1) C’est la zone graphique qui effectue les traitements déclenchés par les boutons efface et annule Quid si on supprime la barre d ’outil et que toutes les opérations s ’effectuent via la barre de menus ? Lourdeur du code : si beaucoup de boutons à écouter si plusieurs moyens de déclencher ces actions (boutons, menus…) public void efface() { ... } public void annule() { ... }