Walid BOUDHIAFI FSEG Les bases de la programmation graphique I. Première fenêtre a) La classe JFrame Pour créer une fenêtre graphique, on dispose, dans le paquetage nommé javax.swing , d’une classe standard nommée JFrame , possédant un constructeur sans arguments. Par exemple, avec : JFrame fen = new JFrame() ; On crée un objet de type JFrame et on place sa référence dans fen . Mais si on se limite à cela, rien n’apparaîtra à l’écran. Il est en effet nécessaire de demander l’affichage de la fenêtre en appelant la méthode setVisible fen.setVisible (true) ; // rend visible la fenetre de reference fen Comme par défaut, une telle fenêtre est créée avec une taille nulle, il est nécessaire d’en définir les dimensions auparavant ; par exemple : fen.setSize (300, 150) ; // donne a la fenetre une hauteur de 150 pixels // et une largeur de 300 pixels En général, on choisira d’afficher un texte précis dans la barre de titre. Pour ce faire, on utilisera la méthode setTitle , par exemple : fen.setTitle ("Ma premiere fenetre") ; Voici un programme très simple de création d’une fenêtre graphique : import javax.swing.* ; public class Premfen0 { public static void main (String args[]) { JFrame fen = new JFrame() ; fen.setSize (300, 150) ; fen.setTitle ("Ma premiere fenetre") ; fen.setVisible (true) ; } } Bien que vous n’ayez rien prévu de particulier, l’utilisateur peut manipuler cette fenêtre Comme n’importe quelle fenêtre graphique d’un logiciel du commerce, et en particulier : la retailler, la déplacer (ici, elle s’est affichée dans le coin haut gauche de l’écran), la réduire à une icône. Ces fonctionnalités, communes à toutes les fenêtres, sont prises en charge par la classe JFrame elle-même. Vous n’avez donc pas à vous soucier de la gestion des événements correspondants tels que le clic sur une de ses cases, le glissé ( drag ) d’une bordure... b) Création d’une classe fenêtre personnalisée Dans l’exemple précédent, nous avons simplement créé un objet de type JFrame et nous avons utilisé les fonctionnalités présentes dans cette classe. Mais pour que notre programme présente un intérêt, il va de soi qu’il faut lui associer des fonctionnalités ou des champs supplémentaires ; de fait, la fenêtre devra pouvoir réagir à certains événements. Pour cela, il nous faudra généralement définir notre propre classe dérivée de JFrame et créer un objet de ce nouveau type. Voici comment nous pourrions transformer dans ce sens le précédent programme (pour l’instant, cette transformation est artificielle puisque le nouveau programme ne fait rien de plus que l’ancien) : import javax.swing.* ; class MaFenetre extends JFrame public class Premfen1 { public MaFenetre () // constructeur { public static void main (String args[]) { setTitle ("Ma premiere fenetre") ; { JFrame fen = new MaFenetre() ; setSize (300, 150) ; fen.setVisible (true) ; }} } 1 Walid BOUDHIAFI FSEG c) Action sur les caractéristiques d’une fenêtre Ici, le titre et les dimensions de la fenêtre sont fixés une fois pour toutes avant son affichage dans le constructeur de la classe MaFenetre . Ils pourraient aussi l’être depuis la méthode main , et même modifiés au fil de l’exécution du programme. D’une manière générale, nous aurons l’occasion de voir comment agir sur certains paramètres d’une fenêtre, comme d’ailleurs des autres composants. Pour l’instant, sachez que vous pouvez fixer non seulement les dimensions, mais aussi la position de la fenêtre à l’écran, en utilisant la méthode : setBounds : fen.setBounds (10, 40, 300, 200) ; // le coin supérieur gauche de la fenêtre est place au pixel de coordonnées 10, 40 et ses dimensions seront de 300 * 200 pixels .Notez que l’origine des coordonnées coïncide avec le coin supérieur gauche de l’écran. L’axe des abscisses est orienté vers la droite, celui des ordonnées vers le bas (on n’a pas affaire à un système orthonormé usuel).Par la suite, nous aurons l’occasion d’utiliser des méthodes comme setBackground (modification de la couleur de fond ou encore getSize (obtention de la taille courante). Pour l’heure, voici un petit programme d’école qui vous permet de modifier quelques caractéristiques de la fenêtre graphique à partir d’informations entrées dans la fenêtre console. Son expérimentation (voire quelques tentatives de modifications) pourra constituer un bon prétexte pour vous familiariser avec ces nouvelles techniques de programmation graphique. import javax.swing.* ; class MaFenetre extends JFrame { public MaFenetre () // constructeur { setTitle ("Ma premiere fenetre") ; setBounds (50, 100, 300, 150) ; } } public class Premfen2 { public static void main (String args[]) { JFrame fen = new MaFenetre() ; fen.setVisible (true) ; while (true) // fin sur longueur titre nulle { System.out.print ("nouvelle largeur : ") ; int larg = Clavier.lireInt() ; System.out.print ("nouvelle hauteur : ") ; int haut = Clavier.lireInt() ; System.out.print ("nouveau titre : (vide pour finir) "); String tit = Clavier.lireString() ; if (tit.length() == 0) break ; fen.setSize (larg, haut) ; fen.setTitle(tit) ; } } } II. Gestion d’un clic dans la fenêtre Comme nous l’avons déjà dit, la programmation événementielle constitue la caractéristique essentielle d’une interface graphique. La plupart des événements sont créés par des composants qu’on aura introduits dans la fenêtre (menus, boutons, boîtes de dialogue...). Mais avant d’apprendre à créer ces composants, nous allons voir comment traiter les événements qu’ils génèrent. Nous nous fonderons pour cela sur un événement qui a le mérite de ne pas nécessiter la création d’un nouvel objet : un clic dans la fenêtre principale. Les différentes démarches à suivre pour gérer cet événement seront très facilement généralisables aux autres événements. a) Implémentation de l’interface MouseListener Voyons donc comment traiter l’événement que constitue un clic dans la fenêtre principale. Par souci de simplicité, nous nous contenterons pour l’instant de signaler l’événement en affichant un message dans la fenêtre console. En Java, tout événement possède ce que l’on nomme une source . Il s’agit de l’objet lui ayant 2 Walid BOUDHIAFI FSEG donné naissance : bouton, article de menu, fenêtre... Dans notre exemple, cette source sera la fenêtre principale. Pour traiter un événement, on associe à la source un objet de son choix dont la classe implémente une interface particulière correspondant à une catégorie d’événements . On dit que cet objet est un écouteur de cette catégorie d’événements. Chaque méthode proposée par l’interface correspond à un événement de la catégorie. Ainsi, il existe une catégorie d’ événements souris qu’on peut traiter avec un écouteur de souris , c’est-à-dire un objet d’une classe implémentant l’interface MouseListener . Cette dernière comporte cinq méthodes correspondant chacune à un événement particulier : mousePressed , mouseReleased , mouseEntered , mouseExited et mouseClicked . Une classe susceptible d’instancier un objet écouteur de ces différents événements devra donc correspondre à ce schéma (nous parlerons un peu plus tard du type MouseEvent de l’unique argument de ces différentes métho des) : class EcouteurSouris implements MouseListener { public void mouseClicked (MouseEvent ev) { ..... } public void mousePressed (MouseEvent ev) { ..... } public void mouseReleased(MouseEvent ev) { ..... } public void mouseEntered (MouseEvent ev) { ..... } public void mouseExited (MouseEvent ev) { ..... } // autres methodes et champs de la classe } Pour l’instant, nous n’entrerons pas trop dans les détails et nous nous contenterons de savoir que l’événement mouseClicked correspond à un clic usuel (appui suivi de relâchement, sans déplacement). C’est donc celui qui nous intéresse ici, et que nous traiterons donc en redéfinissant ainsi la méthode mouseClicked : public void mouseClicked(MouseEvent ev) { System.out.println ("clic dans fenetre") ;} Mais comme notre classe doit implémenter l’interface MouseListener , elle doit en redéfinir toutes les méthodes. Nous pouvons toutefois nous permettre de ne rien faire de particulier pour les autres événements, et donc de fournir des méthodes "vides". Pour traiter un clic souris dans notre fenêtre, il suffit donc d’associer à notre fenêtre un objet d’un type tel que EcouteurSouris . Pour ce faire, nous utilisons la méthode addMouseListener . Cette dernière figure dans toutes les classes susceptibles de générer des événements souris, en particulier dans JFrame . Nous pouvons donc introduire dans le constructeur de notre fenêtre une instruction de la forme : addMouseListener (objetEcouteur) ; dans laquelle objetEcouteur est un objet d’une classe du type EcouteurSouris dont nous venons de fournir le schéma. Java se montre ici très souple puisque l’objet écouteur peut être n’importe quel objet dont la classe implémente l’interface voulue. Dans une situation aussi simple qu’ici, nous pouvons même ne pas créer de classe séparée telle que EcouteurSouris en faisant de la fenêtre elle-même son propre écouteur d’événements souris. Notez que cela est possible car la seule chose qu’on demande à un objet écouteur est que sa classe implémente l’interface voulue (ici MouseListener ). Nous pouvons donc adopter ce schéma : class MaFenetre extends JFrame implements MouseListener { public MaFenetre () // constructeur { ..... addMouseListener (this) ; // la fenetre sera son propre ecouteur d’evenements souris } public void mouseClicked(MouseEvent ev) // methode gerant un clic souris { System.out.println ("clic dans fenetre") ; } public void mousePressed (MouseEvent ev) {} public void mouseReleased(MouseEvent ev) {} public void mouseEntered (MouseEvent ev) {} public void mouseExited (MouseEvent ev) {} } // autres methodes de la classe MaFenetre } 3 Walid BOUDHIAFI FSEG b) La notion d’adaptateur Dans les exemples précédents, nous n’avions besoin que de la méthode mouseClicked . Mais nous avons dû fournir des définitions vides pour les autres afin d’implémenter correctement toutes les méthodes requises par l’interface MouseListener . Pour vous faciliter les choses, Java dispose d’une classe particulière MouseAdapter qui implémente toutes les méthodes de l’interface MouseListener avec un corps vide. Autrement dit, tout se passe comme si MouseAdapter était définie ainsi : class MouseAdapter implements MouseListener { public void mouseClicked (MouseEvent ev) {} public void mousePressed (MouseEvent ev) {} public void mouseReleased(MouseEvent ev) {} public void mouseEntered (MouseEvent ev) {} public void mouseExited (MouseEvent ev) {} } Dans ces conditions, vous pouvez facilement définir une classe écouteur des événements souris ne comportant qu’une méthode (par exemple mouseClicked ), en procédant ainsi : class EcouteurSouris extends MouseAdapter { public void mouseClicked (MouseEvent e) // ici, on ne redefinit { ..... // que la (ou les) methode(s) qui } // nous interesse(nt) } Voici un schéma récapitulatif montrant comment utiliser cette technique pour n’écouter, à l’aide d’un objet d’une classe EcouteurSouris , que les clics complets générés par une fenêtre : class MaFenetre extends JFrame { ..... addMouseListener (new EcouteurSouris()) ; ..... } class EcouteurSouris extends MouseAdapter { public void mouseClicked (MouseEvent ev) // seule la methode mouseClicked { ..... } // nous interesse ici ..... } Cependant, si l’on procède ainsi, les deux classes MaFenetre et EcouteurSouris sont indépendantes. Dans certains programmes, on préférera que la fenêtre concernée soit son propre écouteur (comme nous l’avons fait dans les exemples précédents n’utilisant pas d’adaptateur). Dans ce cas, un petit problème se pose : la classe fenêtre correspondante ne peut pas dériver à la fois de JFrame et de MouseAdapter 1. C’est là que la notion de classe anonyme prend tout son intérêt. Il suffit en effet de remplacer le canevas précédent par le suivant : class MaFenetre extends JFrame { ..... addMouseListener (new MouseAdapter { public void mouseClicked (MouseEvent ev) { ..... } }) ; ..... } Ici, on a créé un objet d’un type classe anonyme dérivée de MouseAdapter et dans laquelle on a redéfini de façon appropriée la méthode mouseClicked . import javax.swing.* ; import java.awt.event.* ; class MaFenetre extends JFrame { public MaFenetre () // constructeur { setTitle ("Gestion de clics") ; setBounds (10, 20, 300, 200) ; addMouseListener ( new MouseAdapter() 4 Walid BOUDHIAFI FSEG { public void mouseClicked(MouseEvent ev) { int x = ev.getX() ; int y = ev.getY() ; System.out.println ("clic au point de coordonnees " + x + ", " + y ) ;} } ) ;}} public class Clic3 { public static void main (String args[]) { MaFenetre fen = new MaFenetre() ; fen.setVisible(true) ; } } III. Premier composant : un bouton Jusqu’ici, nous n’avons pas introduit de composant particulier dans la fenêtre graphique. Nous allons maintenant voir comment y placer un bouton et intercepter les actions correspondantes. Notez qu’il s’agit là du composant le plus simple qui soit, et dont l’usage est certainement le plus intuitif. a) Création d’un bouton et ajout dans la fenêtre On crée un objet bouton en utilisant le constructeur de la classe JButton , auquel on communique le texte qu’on souhaite voir figurer à l’intérieur : JButton monBouton ; ..... monBouton = new JButtton ("ESSAI") ; // creation d’un bouton portant l’etiquette "ESSAI" Il faut ensuite introduire ce composant dans la fenêtre. Ici, les choses sont un peu moins naturelles, car un objet de type JFrame possède une structure a priori quelque peu complexe. En effet, il est théoriquement formé d’une superposition de plusieurs éléments, en particulier une racine, un contenu et une vitre. En général, il vous suffit de savoir que c’est sa partie contenu qui nous intéresse puisque c’est à elle que nous incorporerons les différents composants. La méthode getContentPane de la classe JFrame fournit la référence à ce contenu, de type Container . Ainsi, depuis une méthode quelconque d’une fenêtre, nous obtiendrons une référenceà son contenu par : Container c = getContentPane() ; D’autre part, la méthode add de la classe Container permet d’ajouter un composant quelconque à un objet de ce type. Pour ajouter le bouton précédent (de référence monBouton ) au contenu de référence c , il suffit de procéder ainsi : c.add(monBouton) ; Bien entendu, si l’on n’a pas besoin de c par ailleurs, on pourra condenser ces deux instructions en : getContentPane().add(monBouton) ; b) Affichage du bouton : la notion de gestionnaire de mise en forme Nous venons de voir comment créer un nouveau bouton et nous pouvons introduire les instructions évoquées dans le constructeur de notre fenêtre : class Fen1Bouton extends JFrame { public Fen1Bouton () { setTitle ("Premier bouton") ; setSize (300, 200) ; monBouton = new JButton ("ESSAI") ; getContentPane().add(monBouton) ; } JButton monBouton ; } Notez que, contrairement à une fenêtre, un bouton est visible par défaut ; il est donc inutile de lui appliquer la méthode setVisible(true) (mais cela reste possible). Si nous affichons notre fenêtre, nous constatons toutefois que le bouton est bien présent, mais qu’il occupe tout l’espace disponible1. En fait, la disposition des composants dans une fenêtre est gérée par ce qu’on nomme un gestionnaire de mise en forme ou encore de disposition (en anglais Layout Manager ). Il existe plusieurs gestionnaires (fournis, naturellement, sous forme de classes) utilisant des règles spécifiques pour disposer les composants. Nous les étudierons en détail par la suite. Pour l’instant, sachez que, par défaut, Java utilise un gestionnaire de classe BorderLayout avec lequel, en l’absence d’informations 5 Walid BOUDHIAFI FSEG spécifiques, un composant occupe toute la fenêtre. Mais il existe un gestionnaire plus intéressant, de la classe FlowLayout, qui dispose les différents composants "en flot", c’est-à-dire qu’il les affiche un peu comme du texte, les uns à la suite des autres, d’abord sur une même "ligne", puis ligne après ligne... Nous verrons plus tard que ce gestionnaire permet également d’agir sur la taille des composants. Pour choisir un gestionnaire, il suffit d’appliquer la méthode setLayout à l’objet contenu de la fenêtre (n’oubliez pas que c’est déjà à l’objet contenu qu’on ajoute les composants). Ainsi, pour obtenir un gestionnaire du type FlowLayout souhaité, nous procéderons comme ceci : getContentPane().setLayout(new FlowLayout()) ; Voici un programme complet qui crée un bouton dans la fenêtre graphique : import javax.swing.* ; import java.awt.* ; import java.awt.event.* ; class Fen1Bouton extends JFrame { public Fen1Bouton () { setTitle ("Premier bouton") ; setSize (300, 200) ; monBouton = new JButton ("ESSAI") ; getContentPane().setLayout( new FlowLayout()) ; getContentPane().add(monBouton) ; } private JButton monBouton ; } Remarques Ici, nous avons ajouté le bouton à la fenêtre, avant son affichage par setVisible . Nous aurions aussi pu le faire après ; dans ce cas, c’est l’ajout du bouton qui aurait provoqué automatiquement un nouvel affichage de la fenêtre. Il est également possible de faire disparaître temporairement un bouton par setVisible(false) , puis de le faire réapparaître par setVisible(true) . Nous avons dû importer le paquetage java.awt qui contient les classes Container et FlowLayout . D’une manière générale, on peut éviter d’avoir à s’interroger sans cesse sur la répartition dans les paquetages des différentes classes utilisées dans les interfaces graphiques, en important systématiquement awt , awt.event , swing et swing.event . C’est ce que nous ferons généralement ; nous nous contenterons de signaler les cas où d’autres paquetages seront nécessaires. Si vous cherchez à ajouter le bouton à la fenêtre elle-même et non à son contenu, vous obtiendrez un message d’erreur très explicite lors de l’exécution (il vous indiquera même la modification à effectuer). c) Gestion du bouton avec un écouteur Un bouton ne peut déclencher qu’un seul événement correspondant à l’action de l’utilisateur sur ce bouton. Généralement, cette action est déclenchée par un clic sur le bouton, mais elle peut aussi être déclenchée à partir du clavier (sélection du bouton et appui sur la barre d’espace). La démarche exposée au paragraphe 2 pour gérer un clic souris dans une fenêtre s’applique pour gérer l’action sur un bouton. Il suffit simplement de savoir que l’événement qui nous intéresse est l’unique événement d’une catégorie d’événements nommée Action . Il faudra donc : créer un écouteur qui sera un objet d’une classe qui implémente l’interface ActionListener ; cette dernière ne comporte qu’une méthode nommée actionPerformed ; 6 Walid BOUDHIAFI FSEG associer cet écouteur au bouton par la méthode addActionListener (présente dans tous les composants qui en ont besoin, donc en particulier dans la classe JButton ). Voici comment nous pouvons adapter le programme précédent de façon qu’il affiche un message ( clic sur bouton Essai ) à chaque action sur le bouton : import javax.swing.* ; import java.awt.* ; import java.awt.event.* ; class Fen1Bouton extends JFrame implements ActionListener // Attention : ne pas oublier implements { public Fen1Bouton () { setTitle ("Premier bouton") ; setSize (300, 200) ; monBouton = new JButton ("ESSAI") ; getContentPane().setLayout( new FlowLayout()) ; getContentPane().add(monBouton) ; monBouton.addActionListener( this ); } public void actionPerformed (ActionEvent ev) { System. out .println ("action sur bouton ESSAI") ; } private JButton monBouton ; } ##### d) Gestion de plusieurs composants Dans le paragraphe précédent, la fenêtre graphique ne contenait qu’un seul bouton. Il va de soi qu’elle peut en contenir plusieurs. En ce qui concerne leur création et leur ajout à la fenêtre, il suffit de procéder comme nous l’avons fait auparavant. Si nous continuons d’utiliser le gestionnaire de type FlowLayout , les différents boutons seront affichés séquentiellement dans l’ordre de leur ajout ; cela nous conviendra pour l’instant. En ce qui concerne maintenant la gestion des actions sur ces différents boutons, on peut se contenter de ce qui a été fait précédemment (tous les boutons afficheront alors le même message). En fait, Java vous offre une très grande liberté pour cette gestion puisque, comme nous l’avons déjà dit, chaque événement de chaque composant peut disposer de son propre objet écouteur. De plus, chacun de ces écouteurs peut être ou non objet d’une même classe ; on peut même avoir une classe pour certains boutons et une autre classe pour d’autres... Bien entendu, le choix dépendra du problème à résoudre : il s’effectuera selon les traitements qu’il faudra réellement déclencher pour chaque action et aussi en fonction des informations nécessaires à leur accomplissement. Nous vous proposerons ici quelques situations qui vous permettront d’appréhender la richesse des possibilités de Java et qu’il vous sera facile de transposer à n’importe quel composant. Au passage, nous verrons comment régler les éventuels problèmes d’idenfication d’un composant source d’un événement en recourant aux méthodes getSource et getAction-Command . Malgré leur ressemblance, nous vous conseillons de bien étudier ces différents programmes. Lors du développement de vos propres applications, vous serez ainsi en mesure d’effectuer vos choix en toute connaissance de cause. d.1) La fenêtre écoute les boutons On peut faire de la fenêtre l’objet écouteur de tous les boutons. Même dans ce cas, plusieurs possibilités existent ; en effet, on peut : prévoir exactement la même réponse, quel que soit le bouton ; 7 Walid BOUDHIAFI FSEG prévoir une réponse dépendant du bouton concerné, ce qui nécessite de l’identifier ; nous verrons qu’on peut le faire en utilisant l’une des méthodes getSource ou getActionCommand. d.1.1) Tous les boutons déclenchent la même réponse : Ici, on se contente de généraliser à tous les boutons ce qui a été fait dans l’exemple précédent ; tous les boutons déclenchent l’affichage du même message. import javax.swing.* ; import java.awt.* ; import java.awt.event.* ; class Fen2Boutons extends JFrame implements ActionListener { public Fen2Boutons () { setTitle ("Avec deux boutons") ; setSize (300, 200) ; monBouton1 = new JButton ("Bouton A") ; monBouton2 = new JButton ("Bouton B") ; Container contenu = getContentPane() ; contenu.setLayout( new FlowLayout()) ; contenu.add(monBouton1) ; contenu.add(monBouton2) ; monBouton1.addActionListener( this ); // la fenetre ecoute monBouton1 monBouton2.addActionListener( this ); // la fenetre ecoute monBouton2 } public void actionPerformed (ActionEvent ev) // gestion commune a { System. out .println ("action sur un bouton") ; // tous les boutons } private JButton monBouton1, monBouton2 ; } public class Boutons1 { public static void main (String args[]) { Fen2Boutons fen = new Fen2Boutons() ; fen.setVisible( true ) ; } } Trace d’exécution d.1.2 )La méthode getSource Ici, nous continuons d’employer une seule méthode pour les deux boutons. Mais nous faisons appel à la méthode getSource (présente dans toutes les classes événements, donc dans ActionEvent ) ; elle fournit une référence (de type Object ) sur l’objet ayant déclenché l’événement concerné. import javax.swing.* ; import java.awt.* ; import java.awt.event.* ; class Fen2Boutons extends JFrame implements ActionListener { public Fen2Boutons () { setTitle ("Avec deux boutons") ; setSize (300, 200) ; monBouton1 = new JButton ("Bouton A") ; monBouton2 = new JButton ("Bouton B") ; 8 Walid BOUDHIAFI FSEG Container contenu = getContentPane() ; contenu.setLayout( new FlowLayout()) ; contenu.add(monBouton1) ; contenu.add(monBouton2) ; monBouton1.addActionListener( this ); monBouton2.addActionListener( this ); } public void actionPerformed (ActionEvent ev) { if (ev.getSource() == monBouton1) System. out .println ("action sur bouton numero 1") ; if (ev.getSource() == monBouton2) System. out .println ("action sur bouton numero 2") ; } private JButton monBouton1, monBouton2 ; } public class Boutons2 { public static void main (String args[]) { Fen2Boutons fen = new Fen2Boutons() ; fen.setVisible( true ) ;}} d.1.3 La méthode getActionCommand La méthode getSource permet d’identifier la source d’un événement et elle a le mérite de s’appliquer à tous les événements générés par tous les composants. Il existe une autre technique d’identification d’une source d’événements qui ne s’applique qu’aux événements de la catégorie Action . Elle se fonde sur le fait que tout événement de cette catégorie est caractérisé par ce que l’on nomme une chaîne de commande , c’est-à-dire une chaîne de caractères ( String ) associée à l’action. Par défaut, dans le cas d’un bouton, la chaîne de commande n’est rien d’autre que l’étiquette de ce bouton. La méthode getActionCommand , présente uniquement dans la classe ActionEvent , permet d’obtenir la chaîne de commande associée à la source d’un événement. Dans l’exemple ci-dessous, nous continuons d’employer une seule méthode pour nos deux boutons, que nous identifions cette fois à l’aide de getActionCommand : import javax.swing.* ; import java.awt.* ; import java.awt.event.* ; class Fen2Boutons extends JFrame implements ActionListener { public Fen2Boutons () { setTitle ("Avec deux boutons") ; setSize (300, 200) ; monBouton1 = new JButton ("Bouton A") ; monBouton2 = new JButton ("Bouton B") ; Container contenu = getContentPane() ; contenu.setLayout( new FlowLayout()) ; contenu.add(monBouton1) ; contenu.add(monBouton2) ; monBouton1.addActionListener( this ); monBouton2.addActionListener( this ); } public void actionPerformed (ActionEvent ev) 9 Walid BOUDHIAFI FSEG { String nom = ev.getActionCommand() ; System. out .println ("Action sur bouton " + nom) ; } private JButton monBouton1, monBouton2 ; } public class Boutons3 { public static void main (String args[]) { Fen2Boutons fen = new Fen2Boutons() ; fen.setVisible( true ) ; } } Remarques La méthode getComponent fournit la même référence que getSource , mais du type Component . Ainsi, e.getComponent() est équivalent à (Component)e.getSource(). e) Classe écouteur différente de la fenêtre Dans les exemples précédents, nous avons fait de la fenêtre l’objet écouteur de ses boutons.Voyons maintenant des situations dans lesquelles l’écouteur est différent de la fenêtre. Parmi les nombreuses possibilités existantes, nous en examinerons deux : - une classe écouteur par bouton, - une seule classe écouteur pour tous les boutons. e.1) Une classe écouteur pour chaque bouton Ici, nous prévoyons donc que chaque bouton possède sa propre classe écouteur. Cela permet ainsi de disposer d’une méthode actionPerformed spécifique à chaque bouton. import javax.swing.* ; import java.awt.* ; import java.awt.event.* ; class Fen2Boutons extends JFrame { public Fen2Boutons () { setTitle ("Avec deux boutons") ; setSize (300, 200) ; monBouton1 = new JButton ("Bouton A") ; monBouton2 = new JButton ("Bouton B") ; Container contenu = getContentPane() ; contenu.setLayout( new FlowLayout()) ; contenu.add(monBouton1) ; contenu.add(monBouton2) ; EcouteBouton1 ecout1 = new EcouteBouton1() ; EcouteBouton2 ecout2 = new EcouteBouton2() ; monBouton1.addActionListener(ecout1); monBouton2.addActionListener(ecout2); } private JButton monBouton1, monBouton2 ; } class EcouteBouton1 implements ActionListener { public void actionPerformed (ActionEvent ev) { System. out .println ("action sur bouton 1") ; } 10 Walid BOUDHIAFI FSEG } class EcouteBouton2 implements ActionListener { public void actionPerformed (ActionEvent ev) { System. out .println ("action sur bouton 2") ; } } public class Boutons4 { public static void main (String args[]) { Fen2Boutons fen = new Fen2Boutons() ; fen.setVisible( true ) ; } } e.2) Une seule classe écouteur pour les deux boutons On peut aussi utiliser une seule classe écouteur pour les deux boutons, ce qui signifie que l’on ne dispose plus que d’une seule méthode actionPerformed commune aux deux boutons. Pour identifier le bouton concerné au sein de cette méthode, on peut toujours recourir à getActionCommand ; l’emploi de getSource est généralement peu aisé.Mais on peut aussi prévoir d’associer un objet écouteur différent à chaque bouton (attention : cette fois, la classe est commune, seuls les objets diffèrent) et s’arranger pour que chacun possède un champ permettant de l’identifier. Ce champ peut tout à fait être initialisé à la construction, par exemple à partir d’une information fournie lors de l’appel du constructeur de l’objet écouteur. Voici un exemple, dans lequel nous conservons dans chaque écouteur un numéro fourni à la construction (nous avons choisi artificiellement les valeurs 10 et 20) : import javax.swing.* ; import java.awt.* ; import java.awt.event.* ; class Fen2Boutons extends JFrame { public Fen2Boutons () { setTitle ("Avec deux boutons") ; setSize (300, 200) ; monBouton1 = new JButton ("Bouton A") ; monBouton2 = new JButton ("Bouton B") ; Container contenu = getContentPane() ; contenu.setLayout( new FlowLayout()) ; contenu.add(monBouton1) ; contenu.add(monBouton2) ; EcouteBouton ecout1 = new EcouteBouton(10) ; EcouteBouton ecout2 = new EcouteBouton(20) ; monBouton1.addActionListener(ecout1); monBouton2.addActionListener(ecout2); } private JButton monBouton1, monBouton2 ; } class EcouteBouton implements ActionListener { public EcouteBouton ( int n) { this .n = n ; } public void actionPerformed (ActionEvent ev) { System. out .println ("action sur bouton " + n) ; } private int n ; } public class Boutons5 { public static void main (String args[]) 11 Walid BOUDHIAFI FSEG { Fen2Boutons fen = new Fen2Boutons() ; fen.setVisible( true ) ; } } e.3) Dynamique des composants Dans les exemples précédents, les boutons étaient créés en même temps que la fenêtre et ils restaient affichés en permanence. Il en ira souvent ainsi. Néanmoins, il faut savoir qu’on peut, à tout instant : - créer un nouveau composant, - supprimer un composant, - désactiver un composant, c’est-à-dire faire en sorte qu’on ne puisse plus agir s...
Les bases de la programmation graphique
FSEGFSEG
1/72
100%
Rendu du PDF...