M2 ISF Introduction à la P.O.O et langage java (fascicule 2) O. Auzende 2012-2013 1 Le paquetage graphique java.awt ........................................................................................................................ 3 Principe de construction d’une fenêtre graphique ........................................................................................... 3 Exemple de construction d’une fenêtre graphique .......................................................................................... 4 La gestion des événements .................................................................................................................................... 6 Principe de la gestion des événements ............................................................................................................ 6 Mise en œuvre en java..................................................................................................................................... 6 Programmation ................................................................................................................................................ 7 Exercice........................................................................................................................................................... 8 Les conversions et les calculs .............................................................................................................................. 10 Conversion d’une chaîne en nombre ............................................................................................................. 10 Conversions d’un nombre en chaîne ............................................................................................................. 10 Exercice......................................................................................................................................................... 10 Application financière (partie 1) ........................................................................................................................ 11 Les applets Java .................................................................................................................................................. 12 Qu’est-ce qu’une applet ?.............................................................................................................................. 12 Insertion d’une applet dans une page HTML ................................................................................................ 13 Méthodes d’une applet .................................................................................................................................. 13 Exécution d’une applet .................................................................................................................................. 13 Transformation d’une application en applet .................................................................................................. 13 Les paramètres d’une applet .......................................................................................................................... 14 Application financière (partie 2) ........................................................................................................................ 14 2 Programmation Orientée Objet et langage java Le paquetage graphique java.awt Le paquetage java.awt fournit toutes les classes permettant de bâtir des fenêtres graphiques. La classe Component est à l’origine de tous les composants graphiques. o En italiques, les classes abstraites (qui n’autorisent pas la création d’objets). Component est abstraite ; son rôle est de proposer des méthodes qui seront héritées par toutes les sous-classes. o Dans la parabole, ce qui est extérieur au paquetage java.awt, mais dérive d’une classe de java.awt. o En flèches pointillées, les implémentations d’interfaces. Button Canvas Checkbox Choice Component Panel Applet Container Dialog Label FileDialog Window Frame List Scrollbar TextArea TextComponent TextField MenuBar MenuComponent MenuItem BorderLayout CardLayout FlowLayout GridBagConstraints LayoutManager GridBagLayout GridLayout Principe de construction d’une fenêtre graphique Les composants (textes, boutons, cases à cocher, etc) sont insérés dans un objet dérivant de Container : o Les objets de type Panel sont des zones non délimitées, permettant de ranger des composants. o Les objets de type Window sont des fenêtres standard ; il y a deux sous-classes : Frame : les objets de ce type sont des fenêtres avec barre de titre et scrollbar Dialog : les objets de ce type sont des fenêtres de dialogue avec l’utilisateur Un LayoutManager (gestionnaire de placement) définit comment sont placés les objets. C’est une interface qu’implémentent plusieurs classes, dont : o BorderLayout qui répartit les objets au Nord, Sud, Est, Ouest et Centre (c’est l’option par défaut pour un Frame) o FlowLayout qui les répartit de gauche à droite puis passe à la ligne suivante (c’est l’option par défaut pour un Panel) o GridLayout qui les répartit dans un tableau dont toutes les cases ont la même taille. 3 Trois exemples import java.awt.* ; class Appli1 { public static void main(String arg[]) { Frame w = new Frame("Exemple") ; w.add("North", new Label("Un")) ; w.add("Center", new Label("Deux")) ; w.add("South", new Label("Trois")) ; w.show() ; w.pack() ; } } import java.awt.* ; class Appli2 { public static void main(String arg[]) { Frame w = new Frame("Exemple") ; w.setLayout(new FlowLayout()) ; w.add(new Label("Un")) ; w.add(new Label("Deux")) ; w.add( new Label("Trois")) ; w.show() ; w.pack() ; } } import java.awt.* ; class Appli3 { public static void main(String arg[]) { Frame w = new Frame("Exemple") ; w.setLayout(new GridLayout(2,2)) ; w.add(new Label("Un")) ; w.add(new Label("Deux")) ; w.add( new Label("Trois")) ; w.add( new Label("Quatre")) ; w.show() ; w.pack() ; } } Exemple de construction d’une fenêtre graphique Schéma : 4 BorderLayout par défaut : FlowLayout choisi : GridLayout choisi : Le fichier UtilFenetre.java ci-dessous comporte deux classes : o la classe Fenetre construisant la fenêtre o la classe publique UtilFenetre constituant le programme principal import java.awt.* ; class Fenetre extends Frame { protected Panel p1, p2, p3, p31, p32 ; protected TextArea txt ; protected Button bouton1, bouton2, bouton3 ; protected CheckboxGroup cbg ; protected Checkbox chb1, chb2, chb3 ; protected List selection1, selection2 ; Fenetre() { setLayout(new FlowLayout()) ; // construction du Panel p1 p1 = new Panel() ; p1.setLayout(new GridLayout(4,1)) ; p1.add(new Label("Jour")) ; selection1 = new List(3) ; selection1.addItem("lundi") ; selection1.addItem("mardi") ; selection1.addItem("mercredi") ; selection1.addItem("jeudi") ; selection1.addItem("vendredi") ; selection1.addItem("samedi") ; selection1.addItem("dimanche") ; p1.add(selection1) ; p1.add(new Label("Horaire")) ; selection2 = new List(3) ; selection2.addItem("9 h - 12 h") ; selection2.addItem("12 h - 15 h") ; selection2.addItem("15 h - 18 h") ; selection2.addItem("18 h - 21 h") ; p1.add(selection2) ; add(p1) ; // construction du Panel p2 p2 = new Panel() ; p2.setLayout(new GridLayout(4,1)) ; p2.add(new Label("Localisation")) ; cbg = new CheckboxGroup(); chb1 = new Checkbox("Paris", cbg, true); p2.add(chb1) ; chb2 = new Checkbox("Lyon", cbg, false); p2.add(chb2) ; chb3 = new Checkbox("Marseille", cbg, false); p2.add(chb3) ; add(p2) ; // construction du Panel p3 p3 = new Panel() ; p3.setLayout(new BorderLayout()) ; p31 = new Panel(); bouton1 = new Button("Valider") ; p31.add(bouton1) ; bouton2 = new Button("Désélectionner") ; p31.add(bouton2) ; p3.add("North", p31) ; txt = new TextArea(5,30) ; p3.add("Center",txt) ; p32 = new Panel() ; bouton3 = new Button("Quitter") ; p32.add(bouton3) ; p3.add("South", p32) ; add(p3) ; } // fin du constructeur } // fin de la classe Fenetre public class UtilFenetre { // classe utilisateur public static void main(String args[]) { Fenetre f = new Fenetre() ; f.pack() ; f.show() ; } } Pour le moment aucun événement n’est pris en compte sur cette fenêtre 5 La gestion des événements Principe de la gestion des événements La fenêtre graphique délègue la gestion des événements à d’autres classes : c’est le modèle MVC (Méthode Vue - Contrôleur) Fenêtre = vue (instance d’une classe) Prise de décision = contrôleur (instance d’une autre classe) Action = méthode (instance d’une troisième classe) Mise en œuvre en java On attache un Listener (surveillant) aux objets graphiques que l’on souhaite surveiller (Button, Window, etc.). Il existe différents Listeners dépendant du type d’objet à surveiller, mais tous sont des instances d’interfaces. On a donc besoin d’une classe implémentant les interfaces nécessaires. On appellera cette classe la classe Adaptateur. Un objet de la classe Adaptateur, étant de fait devenu un listener, sera alors automatiquement averti des événements (event) qui se produisent sur les objets graphiques surveillés. Il décidera alors des actions à entreprendre en fonction de la demande de l’utilisateur, et donnera l’ordre à un exécuteur de faire ces actions. L’exécuteur sera un objet d’une classe que l’on appellera la classe Delegue ; il exécutera les actions demandées par l’objet Adaptateur et interviendra sur la vue pour en modifier l’apparence. Illustration par deux exemples Clic sur un bouton contenu dans la fenêtre Clic sur le bouton de fermeture de la fenêtre Résumé La VUE est la fenêtre graphique. C’est une instance d’une classe graphique. Le CONTROLEUR est une instance d’une classe implémentant les Listeners nécessaires ; on appellera cette classe la classe Adaptateur car elle décide comment « adapter » la fenêtre aux actions demandées par l’utilisateur. La METHODE est une instance d’une classe contenant les méthodes à effectuer ; on appellera cette classe la classe Delegue car le CONTROLEUR « délègue » à la METHODE la responsabilité des actions à entreprendre sur la fenêtre. 6 Programmation Etape 1. Dans le constructeur de la fenêtre, on déclare un attribut de nom delegue de la classe Delegue protected Delegue delegue ; puis on demande à la classe Delegue la création d’un objet Delegue par appel au constructeur en lui envoyant l’adresse de la fenêtre : delegue = new Delegue(this) ; L’adresse du délégué ainsi créé est donc stockée dans l’attribut delegue tandis que le délégué stocke dans son attribut fen l’adresse de la fenêtre pour pouvoir ultérieurement ultérieurement agir sur elle : Analogie avec le courrier : Nous écrivons à un destinataire que nous venons de découvrir (à une adresse que nous gardons en mémoire) et nous lui envoyons notre propre adresse (this) pour qu’il puisse lui-même la stocker et nous répondre plus tard. Etape 2. On définit une classe Adaptateur qui “écoute” les événements et décide des actions à faire accomplir par le délégué. Pour cela, la classe Adaptateur implémente un ou plusieurs Listeners selon les objets à surveiller. Exemple : pour surveiller les éléments sur un bouton et sur une fenêtre, il faut écrire : class Adaptateur implements WindowListener, ActionListener {...} et définir dans la classe Adaptateur les méthodes des interfaces WindowListener (7) et ActionListener (1). Etape 3. On déclare dans le constructeur de la fenêtre un attribut appelé adapt de la classe Adaptateur : protected Adaptateur adapt ; puis on demande au constructeur de la classe Adaptateur de créer un objet de la classe Adaptateur en lui envoyant l’adresse du délégué, puisque c’est au délégué que l’adaptateur s’adressera : adapt = new Adaptateur(delegue) ; 7 Penser encore à l’analogie avec le courrier : nous écrivons à un second destinataire (l’Adaptateur adapt), mais nous lui demandons de répondre ultérieurement au premier destinataire (le delegue), dont il n’a pas a priori l’adresse. Il faut donc lui passer cette adresse, pour qu’il puisse la stocker. La fenêtre stocke l’adresse de l’adaptateur dans l’attribut adapt. L’adaptateur stocke l’adresse du délégué dans un attribut delegue : Etape 4. Dans le constructeur de la fenêtre, on “enregistre” l’Adaptateur adapt sur les objets à surveiller. Les méthodes d’enregistrement des adaptateurs dépendent du type des objets à surveiller. Exemple : si bouton1 est un objet de la classe Button, et si adapt doit surveiller bouton1, on écrira : bouton1.addActionListener(adapt) ; Etape 5. On complète dans la classe Adaptateur les méthodes obligatoires provenant des Listeners implémentés, puis on écrit dans la classe Delegue les méthodes nécessaires pour que le délégué puisse effectuer les opérations nécessaires. Exercice Compléter le fichier UtilFenetre.java précédent afin d’obtenir après validation le résultat ci-contre : import java.awt.* ; import ... class Fenetre extends Frame { // la classe de la fenêtre (la VUE) protected Panel p1, p2, p3, p31, p32 ; protected TextArea txt ; protected Button bouton1, bouton2, bouton3 ; protected CheckboxGroup cbg ; protected Checkbox chb1, chb2, chb3 ; protected List selection1, selection2 ; protected ... protected ... 8 Fenetre() { // construction des Panel p1, p2 et p3 : ... // on garde les instructions telles quelles // ajouts pour la gestion des événements // création du délégué et de l’adaptateur delegue = ... adapt = ... // enregistrement de l’adaptateur comme listener addWindowListener... bouton1.addActionListener... bouton2.addActionListener... bouton3.addActionListener... } } public class UtilFenetre { // la classe utilisateur public static void main(String args[]) { Fenetre f = new Fenetre() ; f.pack() ; f.show() ; } } class Delegue { protected Fenetre fen ; // partie traitement (la METHODE) Delegue(Fenetre f) { fen = f ; } public void quitter() { ... } public void annulle() { fen.selection1.deselect... fen.selection2.deselect... fen.chb1.setState... fen.chb2.setState... fen.chb3.setState... fen.txt.setText... } public void affichetexte() { String res = "Vous avez choisi le " + ... res=res + "\ndans la tranche horaire " + ... res=res + "\nà " + ... fen.txt.setText... } } class Adaptateur implements ActionListener, WindowListener { // aiguillage (le CONTROLEUR) protected Delegue delegue ; Adaptateur(Delegue d) { delegue = d ; } // méthode indispensable comme ActionListener public void actionPerformed(ActionEvent e) { Object src = ... String param = ... if (param == "Quitter") delegue.quitter() ; else if (param == "Désélectionner") delegue.annulle() ; else delegue.affichetexte() ; } // méthodes indispensables comme WindowListener public void windowClosing(WindowEvent e) { delegue.quitter() ; } public void windowClosed(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowOpened(WindowEvent e) {} } 9 Les conversions et les calculs Toute donnée entrée dans un champ de saisie ou récupérée d’une liste de sélection est une chaîne de caractères. Pour être utilisable en vue de calculs, elle doit être convertie en nombre. Inversement, toute donnée à afficher dans une fenêtre graphique doit être de type chaîne de caractères. Il faut donc convertir les nombres en chaînes de caractères. Conversion d’une chaîne en nombre En un entier n : o o int n = ... int n = ... En un double d : o o double d = ... double d = ... Conversions d’un nombre en chaîne Conversion d’un entier n en chaîne ch : String ch = ... Conversion d’un double d en chaîne ch : String ch = ... Exercice Compiler et exécuter l’application UtilCalcul. Compléter ensuite cette application pour qu’elle exécute la conversion d’euros en dollars : import java.awt.* ; import java.awt.event.* ; class Fenetre extends Frame { static double t = 1.4 ; // 1 euro = 1.4 dollars ; mettre à jour le taux protected Panel p0,p1,p2 ; protected TextField txt1, txt2 ; protected Button bouton ; protected Delegue delegue ; protected Adaptateur adapt ; Fenetre() { p0 = new Panel() ; p0.add(new Label("Conversion euros --> dollars")); add("North", p0); p1 = new Panel() ; p1.setLayout(new GridLayout(2,3)); p1.add(new Label("montant en €")); p1.add(new Label(" ")) ; p1.add(new Label("montant en $")) ; txt1 = new TextField(3) ; p1.add(txt1); bouton = new Button(" = "); p1.add(bouton) ; txt2 = new TextField(3) ; p1.add(txt2); add("Center", p1) ; p2 = new Panel() ; p2.add(new Label("Taux actuel : 1 euro vaut " + t + " $")); add("South", p2); delegue = new Delegue(this) ; adapt = new Adaptateur(delegue) ; addWindowListener(adapt) ; bouton.addActionListener(adapt) ; } } public class UtilCalcul { public static void main(String args[]) { Fenetre f = new Fenetre() ; f.pack() ; f.show() ; } } 10 class Delegue { protected Fenetre fen Delegue(Fenetre f) { fen = f ; } public void quitter() System.exit(0) } public void calcule() ... ... ... ... ... } } ; { ; { // méthode à compléter class Adaptateur implements ActionListener, WindowListener { protected Delegue delegue ; public Adaptateur(Delegue d) { delegue = d ; } public void actionPerformed(ActionEvent e) { delegue.calcule() ; } public void windowClosing(WindowEvent e) { delegue.quitter() ; } public void windowClosed(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowOpened(WindowEvent e) {} } Application financière (partie 1) Il s’agit de compléter une application financière permettant de déterminer si un emprunt pour un achat immobilier est autorisé ou non par une banque et de calculer les mensualités relatives au remboursement de cet emprunt. L’accord de la banque pour autoriser l’emprunt dépend : o du prix du bien à acquérir o de l’apport personnel dont dispose le client o de l’âge du client o du revenu mensuel du client o du nombre d’années de remboursement (de 10 à 30 ans) L’interface de saisie des données est fournie dans le fichier Emprunt.java du dossier application-financire. Elle se présente comme suit : 11 L’autorisation d’accorder l’emprunt dépend de trois conditions : Condition 1 Le montant à emprunter (différence entre le prix du bien et l’apport personnel) ne peut dépasser 80 fois le revenu mensuel. Sinon, un message doit être affiché (voir ci-contre) : Condition 2 La somme de l’âge du client et du nombre d’années de remboursement de l’emprunt doit être inférieure à 70. Sinon, un message est affiché (voir ci-contre) : Si les deux premières conditions sont remplies, alors : o le taux annuel du prêt est déterminé. Il dépend du nombre d’années de remboursement : - si nombre d’années <=10, taux = 6 % annuel - si 10 < nombre d’années <= 20, taux = 5.5 % annuel - si 20 < nombre d’années <= 30, taux = 5 % annuel o la mensualité de remboursement est calculée o la condition 3 est testée : un prêt ne peut être autorisé que si la mensualité de remboursement ne dépasse pas 33 % du revenu mensuel. Sinon, il est refusé avec un message expliquant le refus. Exemple où le prêt est refusé : Exemple où le prêt peut être autorisé : Compléter l’application en implémentant les fonctionnalités décrites ci-dessus. Les applets Java Qu’est-ce qu’une applet ? Une applet est une petite application portable, insérée dans une page HTML et chargée par un navigateur en même temps que la page HTML. Exécutée par l’interpréteur java du navigateur, l’applet permet de délocaliser certains traitements (calculs, animations graphiques, vérification de la validité d’un formulaire, etc.) chez le client. 12 Du point de vue informatique, une applet est une instance d’une classe java héritant de la classe Applet : class monApplet extends Applet { ... } Elle gère seule son apparence dans la zone de la page HTML qui lui est réservée. Insertion d’une applet dans une page HTML en gras les lignes obligatoires URL où on cherche le fichier .java nom du fichier de pseudo-code texte si navigateur non compatible nom de l’applet dans la page html largeur puis hauteur de la zone d’affichage de l’applet paramètres éventuels en nombre quelconque <applet codebase=codebase_URL code="nomclasse.class" alt="texte_de_remplacement" name="nom_instance" width=pixels height=pixels > <param name=nom_param1 value="valeur1"> <param name=nom_param2 value="valeur2"> </applet> Méthodes d’une applet La classe maître de l’applet est une classe publique, dérivant de la classe Applet. Elle ne comporte jamais de méthode main, mais dispose de méthodes spécifiques : o init() réalisant l’initialisation de l’applet (remplace le constructeur) o paint(Graphics g) qui redessine en permanence l’applet sur l’écran à l’aide d’un contexte graphique g fourni. Si l’on veut permettre à l’utilisateur d’interagir avec l’applet, il faut gérer les événements en définissant (comme précédemment) les classes Adaptateur (contrôleur) et Delegue (exécuteur). Exécution d’une applet Il y a deux manières d’exécuter des applets : o faire appel à un visualiseur (l’appletViewer) à qui on donne le nom de la page HTML contenant l’applet : appletViewer nompage.html La page HTML n’est pas visible, seule l’applet est visualisée o faire appel à un navigateur en lui faisant afficher la page HTML contenant l’applet Transformation d’une application en applet On peut transformer une application en applet à condition : o de ne pas avoir besoin de lire ou écrire des données sur la machine cliente o de ne pas avoir de traitement à faire sur le serveur (autre que la simple lecture d’un fichier, qui est autorisée) Liste des modifications à effectuer : o o o o o o o o importer le paquetage java.applet faire dériver la classe de la fenêtre (la VUE) de la classe Applet (au lieu de la classe Frame) supprimer la classe principale de l’application (ce qui impose de renommer le fichier) la classe de la fenêtre étant devenue la classe maître, la déclarer public et renommer son constructeur en static void init() modifier la classe Adaptateur pour qu'elle n'implémente plus l'interface WindowListener modifier la classe Delegue en conséquence écrire la page HTML compiler et tester avec l’appletViewer et avec un navigateur. 13 Les paramètres d’une applet Une page HTML peut passer des paramètres à une applet. Si la page HTML contient les lignes : <applet code= "truc.class" …> <param name="nom" value="dupont"> <param name="valeur" value="3.56"> </applet> alors on peut récupérer le nom dans les méthodes de l’applet par : String nom =getParameter("nom") ; String valeur =getParameter("valeur") ; On récupère toujours une chaîne de caractères. Si on veut convertir cette chaîne en nombre, on utilise les méthodes habituelles de conversion d’une chaîne en int, float ou double. Application financière (partie 2) 1) Transformer l’application Emprunt.java en une applet intégrée dans une page HTML. Ecrire la page emprunt.html appelant l’applet de la manière suivante : <html> <head> <title> Applet</title> </head> <body> <h2><center>Applet Emprunt</center></h2> <center> <applet code="...class" width=800 height=400> </applet> </center> </body> </html> 2) Mettre les trois valeurs du taux en paramètres dans la page HTML. Modifier ensuite l’applet pour que ces valeurs soient récupérées et utilisées. 14