La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Master ISIDIS1 Programmation Orientée Objet Avancée.

Présentations similaires


Présentation au sujet: "Master ISIDIS1 Programmation Orientée Objet Avancée."— Transcription de la présentation:

1 Master ISIDIS1 Programmation Orientée Objet Avancée

2 Master ISIDIS2 Plan  MVC  Réflexivité  Design Pattern

3 Master ISIDIS3 MVC

4 Master ISIDIS4 MVC (Model-View-Controller)  Le modèle gère les données  La vue affiche les données  Le contrôleur gère la communication et les mise-à-jour

5 Master ISIDIS5 Exemple (1) class PlusouMoinsMVC { Model model; View view; Controller control; public PlusouMoinsMVC() { model = new Model(); control = new Controller(); view = new View( control); control. setModel( model); control. setView( view); view. setVisible( true); view. addWindowListener( new WindowCloser()); } public static void main (String[] argv) { PlusouMoinsMVC r = new PlusouMoinsMVC(); }

6 Master ISIDIS6 Exemple (2)  Le modèle contient la donnée  La mise-à-jour par update()  Le renseignement par getValue() class Model { int compteur; Model() { compteur = 0; } void update( int incr) { compteur += incr; } int getValue() { return compteur; }

7 Master ISIDIS7 Exemple (3)  La vue affiche les composants et les données  La mise-à-jour du texte de l’étiquette est faite par update().  La notification de modifications au contrôleur. C’est le contrôleur qui écoute !  Les renseignements sont pris par getValue(). La vue se débrouille pour les obtenir. class View extends Frame { Button oui = new Button("Up !"); Button non = new Button("Down !"); Label diff = new Label("0", Label.CENTER); public View(Controller c) { super("Plus ou moins"); add(oui, BorderLayout.NORTH); add(non, BorderLayout.SOUTH); add(diff, BorderLayout.CENTER); oui.addActionListener(c); non.addActionListener(c); pack(); } void update(int compte) { diff.setText(Integer.toString(compte)); } int getValue(ActionEvent e) { Button b = (Button) e.getSource(); return (b == oui) ? 1 : -1; }

8 Master ISIDIS8 Exemple (4)  Le contrôleur : Réveillé par les actions produites dans la vue Récupère des information dans la vue Met à jour dans le modèle Récupère la nouvelle valeur dans le modèle La transmet pour affichage à la vue class Controller implements ActionListener { private Model m; private View v; public void actionPerformed(ActionEvent e) { m.update(v.getValue(e)); v.update(m.getValue()); } public void setModel (Model m) { this.m = m; } public void setView (View v) { this.v = v; }

9 Master ISIDIS9 Réflexivité

10 Master ISIDIS10 Réflexion  L'objet Class, qui contient toutes les informations relative à la classe (on l'appelle parfois meta-class).  En fait, l'objet Class est utilisé pour créer tous les objets « habituels » d'une classe.  Il y a un objet Class pour chacune des classes d'un programme.  A chaque fois qu'une classe est écrite et compilée, un unique objet de type Class est aussi créé

11 Master ISIDIS11 Réflexion  Durant l'exécution, lorsqu'un nouvel objet de cette classe doit être créé, la JVM qui exécute le programme vérifie d'abord si l'objet Class associé est déjà chargé.  Si non, la JVM le charge en cherchant un fichier.class du même nom. Ainsi un programme Java n'est pas totalement chargé en mémoire lorsqu'il démarre, contrairement à beaucoup de langages classiques.  Une fois que l'objet Class est en mémoire, il est utilisé pour créer tous les objets de ce type.

12 Master ISIDIS12 Réflexion  Class.forName("NomClasse");  Cette méthode est une méthode static de Class (qui appartient à tous les objets Class ).  Un objet Class est comme tous les autres objets, il est donc possible d'obtenir sa référence et de la manipuler (c'est ce que fait le chargeur de classes).  Un des moyens d'obtenir une référence sur un objet Class est la méthode forName(), qui prend en paramètre une chaîne de caractères contenant le nom de la classe dont vous voulez la référence.  Elle retourne une référence sur un objet Class.

13 Master ISIDIS13 Réflexion  La classe Class (décrite précédemment dans ce chapitre) supporte le concept de réflexion, et une bibliothèque additionnelle, java.lang.reflect, contenant les classes Field, Method, et Constructor (chacune implémentant l'interface Member ).  Les objets de ce type sont créés dynamiquement par la JVM pour représenter les membres correspondants d'une classe inconnue.

14 Master ISIDIS14 Réflexion  On peut alors utiliser les constructeurs pour créer de nouveaux objets, les méthodes get() et set() pour lire et modifier les champs associés à des objets Field, et la méthode invoke() pour appeler une méthode associée à un objet Method.  De plus, on peut utiliser les méthodes très pratiques getFields(), getMethods(), getConstructors(), etc. retournant un tableau représentant respectivement des champs, méthodes et constructeurs (pour en savoir plus, jetez un oeil à la documentation en ligne de la classe Class ).  Ainsi, l'information sur la classe d'objets inconnus peut être totalement déterminée dynamiquement, sans rien en savoir à la compilation.

15 Master ISIDIS15 Réflexion : un exemple  Un extracteur de méthodes public class ShowMethods { public static void main(String[] args) { try { Class c = Class.forName(args[0]); Method[] m = c.getMethods(); Constructor[] ctor = c.getConstructors(); if(args.length == 1) { for (int i = 0; i < m.length; i++) System.out.println(m[i]); for (int i = 0; i < ctor.length; i++) System.out.println(ctor[i]); } else { for (int i = 0; i < m.length; i++) if(m[i].toString().indexOf(args[1])!= -1) System.out.println(m[i]); for (int i = 0; i < ctor.length; i++) if(ctor[i].toString().indexOf(args[1])!= -1) System.out.println(ctor[i]); } } catch(ClassNotFoundException e) { System.err.println("Classe non trouvée : " + e); } } }

16 Master ISIDIS16 Design Pattern

17 Master ISIDIS17 Modélisation d’objets …  Des objectifs parfois antagonistes : Encapsuler des données sans en empêcher l’accès Trouver un bon niveau de granularité des objets Limiter les dépendances entre les objets Concevoir des objets polyvalents, flexibles, réutilisables Simplicité d’utilisation Implémentation performante …

18 Master ISIDIS18 Modélisation d’applications  Modéliser correctement une application : Processus complexe Expertise acquise au fil des expériences Problèmes de conception récurrents :  Design Pattern

19 Master ISIDIS19 Un Design Pattern (1)  Nom  Exposé du problème  Contexte de mise en œuvre, contraintes limitantes  Description de la solution proposée  Conseils d’implémentation  Exemple d’implémentation  Confrontation avec d’autres Design Pattern

20 Master ISIDIS20 Exemple  Nom Salle d’attente  Exposé du problème On doit attendre  Description de la solution proposée Toujours relaxante et pas confinée  Conséquence Attente active ou passive ? Durée de l ’attente ? Distraction ?  Exemple d’implémentation Aéroport, dentiste, …

21 Master ISIDIS21 Un Design Pattern (2)  Modèles parfois (souvent ?) triviaux  Relative standardisation du nommage des Design Patterns

22 Master ISIDIS22 Un Design Pattern (3)  Ce que c’est : Description d ’une solution classique à un problème récurent Décrit une partie de la solution… Avec des relations avec le système et les autres parties... C ’est une technique d ’architecture logicielle

23 Master ISIDIS23 Un Design Pattern (4)  Ce que ce n’est pas : Une brique :  Un pattern dépend de son environnement Une règle :  Un pattern ne peut pas s ’appliquer mécaniquement Une méthode :  Ne guide pas une prise de décision ; un pattern est la décision prise Nouveau :  Lao-Tzu (-550) travaillait déjà sur les patterns...

24 Master ISIDIS24 Un Design Pattern (5)  Avantages : Un vocabulaire commun Capitalisation de l ’expérience Un niveau d ’abstraction plus élevé qui permet d ’élaborer des constructions logicielles de meilleure qualité Réduire la complexité Guide/catalogue de solutions

25 Master ISIDIS25 Un Design Pattern (6)  Inconvénients : Effort de synthèse ; reconnaître, abstraire, … Apprentissage, expérience Les patterns « se dissolvent » en étant utilisés Nombreux…  Lesquels sont identiques ?  De niveaux différents … des patterns s ’appuient sur d ’autres…

26 Master ISIDIS26 Principales classes de Design Patterns  Patterns de création : Création d’objet, sans instanciation directe d’une classe  Patterns de composition : Composition de groupe d’objets  Patterns comportementaux : Modélisation de communications inter- objets et du flot de données

27 Master ISIDIS27 Les Design Patterns Purpose CreationalStructuralBehavioral Scope Class Factory Method AdapterInterpreter Template Method Object Abstract Factory Builder Prototype Singleton Adapter Bridge Composite Decorator Facade Proxy Chain of Responsibility Command Iterator Mediator Memento Flyweight Observer State Strategy Visitor

28 Master ISIDIS28 Application des formes lors de la conception  Trouver les bons objets  Bien choisir la granularité des objets  Spécifier les interfaces des objets  Spécifier l'implantation des objets  Mieux réutiliser Héritage vs composition Délégation  Compiled-Time vs Run-Time Structures  Concevoir pour l'évolution

29 Master ISIDIS29 Creational patterns  Formes de création : Abstraire le processus d'instanciation Rendre indépendant de la façon dont les objets sont créés, composés, assemblés, représentés Encapsuler la connaissance de la classe concrète qui instancie Cacher ce qui est créé, qui crée, comment et quand

30 Master ISIDIS30 Abstract Factory (1)  Objectif : obtenir des instances de classes implémentant des interfaces connues, mais en ignorant le type réel de la classe obtenue  Exemple : une application gérant des documents polymorphes générateurs de composants graphiques supportant une multitude de look-and-feels

31 Master ISIDIS31 Abstract Factory (2)  Abstract Factory : Déclare une interface pour les opérations qui créent les objets abstraits  ConcreteFactory : Implémente les opérations qui créent les objets concrets  AbstractProduct : Déclare une interface pour un type d’objet  ConcreteProduct : Définit un objet qui va être créé par la « ConcreteFactory » correspondante Implémente l’interface de « AbstractProduct »  Client : Utilise juste les interfaces déclarées par les classes « AbstractFactory » et « ProductFactory »

32 Master ISIDIS32 Abstract Factory (3)  Le pattern « AbstractFactory » permet de : Isoler les classes concrètes Échanger facilement les familles de produit Rendre consistant les classes  Mais : L’évolution n’est pas facile

33 Master ISIDIS33 Factory Method / Virtual Constructor (1)  On utilise le FactoryMethod lorsque : une classe ne peut anticiper la classe de l'objet qu'elle doit construire une classe délègue la responsabilité de la création à ses sous-classes, tout en concentrant l'interface dans une classe unique

34 Master ISIDIS34 Factory Method / Virtual Constructor (2)  Permet de : Relier les sous-classes Connecter des hiérarchies de classes parallèles

35 Master ISIDIS35 Factory Method / Virtual Constructor (3)  Exemple :

36 Master ISIDIS36 Prototype (1)  Objectif : obtenir une instance d’un objet à partir d’une autre instance  Exemple : drag-and-drop de composants inconnus avec touche Ctrl enfoncée

37 Master ISIDIS37 Prototype (2)  Permet de : Ajouter et enlever des produits durant l’exécution Spécifier de nouveaux objets en faisant varier les valeurs Réduire les sous-classes Configurer une application dynamiquement avec des classes

38 Master ISIDIS38 Prototype (3)  Exemple :

39 Master ISIDIS39 Singleton (1)  Objectif : s’assurer qu’une seule instance d’un type spécifique existe dans le système et fournit l’accès à cet objet  Exemple : un spooler d’impression

40 Master ISIDIS40 Singleton (2)  Permet de : Contrôler l’accès à une seule instance Contrôler le nombre d’instances Rendre les opérations plus flexibles que si on utilisait les classes

41 Master ISIDIS41 Structural Wrapper  Formes de structure : Comment les objets sont assemblés Les patterns sont complémentaires les uns des autres

42 Master ISIDIS42 Adapter / Wrapper (1)  Objectif : obtenir un objet qui permet d’en utiliser un autre en conformité avec une certaine interface  Exemple : mise en « conformité » de composants d’origines diverses

43 Master ISIDIS43 Adapter / Wrapper (2)  On utilise l'Adapter lorsque on veut utiliser : Une classe existante dont l'interface ne convient pas Plusieurs sous-classes mais il est est coûteux de redéfinir l'interface de chaque sous-classe en les sous-classant. Un adapter peut adapter l'interface au niveau du parent.

44 Master ISIDIS44 Adapter / Wrapper (3)  Exemple :

45 Master ISIDIS45 Proxy / Surrogate (1)  Objectif : obtenir un objet qui agit comme intermédiaire dans la communication avec un autre objet (un « passeur d’ordre »)  Exemples : un objet qui reporte les opérations coûteuses au moment où on utilise réellement les résultats de ces opérations (chargement d’une image à la fin d’un document, …) ; un objet qui transforme une collection en lecture-seule

46 Master ISIDIS46 Proxy / Surrogate (2)  Exemple :

47 Master ISIDIS47 Proxy / Surrogate (3)  Exemple :

48 Master ISIDIS48 Composite (1)  Objectif : manipuler indifféremment des objets atomiques ou des agrégats d’objets  Exemple : une application manipulant des formes graphiques et des compositions de ces formes

49 Master ISIDIS49 Composite (2)  Conséquences : Définit des hiérarchies de classes combinant des objets primitifs et des objets composites Rend le client plus simple Facilite l’ajout de nouveaux composants

50 Master ISIDIS50 Composite (3)  Exemple :

51 Master ISIDIS51 Decorator (1)  Objectif : ajouter à des instances spécifiques des comportements spécifiques  Exemple : bordure d’un composant graphique

52 Master ISIDIS52 Decorator (2)  Exemple :

53 Master ISIDIS53 Facade (1)  Objectif : fournir une interface simplifiée et limitée à un système complexe  Exemple : donner accès à des passes spécifiques d’un compilateur

54 Master ISIDIS54 Facade (2)  Exemple :

55 Master ISIDIS55 Behavioural Patterns  Formes de comportement pour décrire : Des algorithmes Des comportements entre objets Des formes de communication entre objet

56 Master ISIDIS56 Chain of responsibility (1)  On utilise Chain of Responsibility lorsque : plus d'un objet peut traiter une requête, et il n'est pas connu a priori l'ensemble des objets pouvant traiter une requête est construit dynamiquement

57 Master ISIDIS57 Chain of responsibility (2)  Caractéristiques Réduit le couplage Ajoute de la flexibilité en assignant de la responsabilité aux objets

58 Master ISIDIS58 Chain of responsibility (3)  Exemple :

59 Master ISIDIS59 Chain of responsibility (4)  Exemple :

60 Master ISIDIS60 Command  Objectif : réifier une commande en un objet embarquant d’éventuels paramètres  Exemple : uniformiser les différentes méthodes de commande d’un système et gérer l’undo et le redo

61 Master ISIDIS61 Interpreter (1)  On utilise Interpreter lorsqu'il faut interpréter un langage et que : La grammaire est simple L'efficacité n'est pas un paramètre critique

62 Master ISIDIS62 Interpreter (2)  Soit la grammaire suivante :

63 Master ISIDIS63 Interpreter (3)  Représentation de l’expression régulière ‘raining & (dogs | cats)*’

64 Master ISIDIS64 Interpreter (4)  Modèle de l’interpréteur :

65 Master ISIDIS65 Iterator  Objectif : permettre d’itérer de manière générique sur les éléments d’une collection, quelle que soit la nature des éléments ou de la collection  Exemple : une collection ordonnée

66 Master ISIDIS66 Mediator (1)  On utilise Mediator lorsque : Quand de nombreux objets doivent communiquer ensemble La réutilisation d'un objet est délicate car il référence et communique avec de nombreux autres objets

67 Master ISIDIS67 Mediator (2)  Exemple :

68 Master ISIDIS68 Memento  On utilise Memento lorsque : On veut sauvegarder tout ou partie de l'état d'un objet pour éventuellement pouvoir le restaurer, et Une interface directe pour obtenir l'état de l'objet briserait l'encapsulation

69 Master ISIDIS69 Observer / Listener  Objectif : permettre à un objet d’informer d’autres objets qu’il ne connaît pas de l’évolution de son état interne  Exemple : un bouton à la suite d’un click

70 Master ISIDIS70 Observeurs  Une classe : Observable Un objet observable issu de cette classe dispose, entre autres, des méthodes suivantes :  addObserver(Observer o) permet de rajouter un observeur  setChanged() indique un changement de l’état de l’objet  notifyObservers(Object arg) si l'état de l'objet a été changé, l'appel à cette méthode permet de notifier les observateurs potentiels de ce changement, par l'appel de la méthode update avec pour arguments l'objet observé et l'argument arg

71 Master ISIDIS71 Observeurs (suite)  Une interface : Observer Permet de décrire un objet qui souhaite être informé du changement d’état d’objets issus de la classe Observable Introduit une seule méthode : public void update(Observable o, Object arg) qui est appelée lorsque o change d’état

72 Master ISIDIS72 Observeurs : Exemple (1)  L’observé class TableObservable extends Observable { Hashtable table = new Hashtable(); public synchronized Object put(Object clé, Object valeur) { setChanged(); notifyObservers(clé); return table.put(clé, valeur); } public synchronized Object get(Object clé) { return table.get(clé); } public synchronized boolean containsKey(Object clé) { return table.containsKey(clé); } public synchronized Enumeration keys() { return table.keys(); } public int size() { return table.size(); }

73 Master ISIDIS73 Observeurs : Exemple (2)  L’observeur class ObservateurDeTable implements Observer { public ObservateurDeTable(Observable o) { o.addObserver(this); } public void update(Observable o, Object arg) { System.out.println("J'observe l'objet : "+o+"\nqui m'envoie :"+arg); }

74 Master ISIDIS74 Observeurs : Exemple (3) class TestObserver{ public static void main (String[] args) { StringTokenizer lstMots = new StringTokenizer(args[0], ",."); TableObservable table = new TableObservable(); ObservateurDeTable observateur = new ObservateurDeTable(table); while (lstMots.hasMoreTokens()) { String mot = lstMots.nextToken(); if (!table.containsKey(mot)) table.put(mot, new Integer(1)); else { Integer nbre = (Integer) table.get(mot); Integer i = new Integer(1+nbre.intValue()); table.put(mot, i); } System.out.print("==> Dans la phrase \""); System.out.print(args[0]); System.out.print("\",\n il y a "); System.out.print(table.size()); System.out.println(" mots différents qui sont:"); for (Enumeration e = table.keys(); e.hasMoreElements(); ) { String mot = (String) e.nextElement(); System.out.println("==> "+mot+" ("+table.get(mot)+" fois)"); }

75 Master ISIDIS75 Observeurs : Exemple (4)  Trace de l’exécution $ java TestObserver "Voila ma phrase, ma courte phrase." J'observe l'objet : TableObservable@80ca7b7 qui m'envoie : Voila J'observe l'objet : TableObservable@80ca7b7 qui m'envoie : ma J'observe l'objet : TableObservable@80ca7b7 qui m'envoie : phrase J'observe l'objet : TableObservable@80ca7b7 qui m'envoie : ma J'observe l'objet : TableObservable@80ca7b7 qui m'envoie : courte J'observe l'objet : TableObservable@80ca7b7 qui m'envoie : phrase ==> Dans la phrase "Voila ma phrase, ma courte phrase.", il y a 4 mots différents qui sont: ==> phrase (2 fois) ==> ma (2 fois) ==> courte (1 fois) ==> Voila (1 fois) $

76 Master ISIDIS76 Strategy / Policy (1)  Objectif : utiliser de manière non spécifique une collection d’algorithme proches  Exemple : algorithmes de tris de collections de données

77 Master ISIDIS77 Strategy / Policy (2)  Exemple :

78 Master ISIDIS78 State (1)  Objectif : un objet qui change de comportement en fonction de son état interne  Exemple : une socket TCP (état non connectée, connectée, en attente de connection)

79 Master ISIDIS79 State (2)  Exemple :

80 Master ISIDIS80 Template Method (1)  On utilise TemplateMethod : Pour implanter une partie invariante d'un algorithme. Pour partager des comportements communs d'une hiérarchie de classes. Pour contrôler des extensions de sous-classe.

81 Master ISIDIS81 Template Method (2)  Exemple :

82 Master ISIDIS82 Visitor (1)  Objectif : découpler une structure des opérations sur cette structure  Exemple : analyses/transformations d’arbres de syntaxe abstraite dans un compilateur

83 Master ISIDIS83 Visitor (2)  Séquences :

84 Master ISIDIS84 Trouver les bons objets  Les patterns proposent des abstractions qui n'apparaissent pas « naturellement » en observant le monde réel : Composite : permet de traiter uniformément une structure d'objets hétérogènes Strategy : permet d'implanter une famille d'algorithmes interchangeables State  Ils améliorent la flexibilité et la réutilisabilité

85 Master ISIDIS85 Bien choisir la granularité des objets  La taille des objets peut varier considérablement ; comment choisir ce qui doit être décomposé ou au contraire regroupé ? Facade Flyweight Abstract Factory Builder

86 Master ISIDIS86 Spécifier les interfaces des objets  Qu’est-ce qui fait partie d’un objet ou non ? Memento : mémorise les états, retour arrière Decorator : augmente l'interface Proxy : interface délégué Visitor : regroupe des interfaces Facade : cache une structure complexe d'objet

87 Master ISIDIS87 Spécifier l'implantation des objets  Différence type-classe… Chain of Responsibility ; même interface, mais implantations différentes Composite ; les Components ont une même interface dont l'implantation est en partie partagée dans le Composite Command, Observer, State, Strategy ne sont souvent que des interfaces abstraites Prototype, Singleton, Factory, Builder sont des abstractions pour créer des objets qui permettent de penser en termes d'interfaces et de leur associer différentes implantations

88 Master ISIDIS88 Concevoir pour l’évolution (1)  Quelques raisons de « reengineering » : Création d'un objet en référençant sa classe explicitement... Lien à une implantation particulière... pour éviter utilisez AbstractFactory, FactoryMethod, Prototype Dépendance d'une opération spécifique...pour rendre plus souple utilisez Chain Of Responsibility, Command Dépendance d'une couche matérielle ou logicielle...AbstractFactory, Bridge

89 Master ISIDIS89 Concevoir pour l’évolution (2)  Quelques raisons de « reengineering » : Dépendance d'une implantation... pour rendre plus souple utilisez AbstractFactory, Bridge, Memento, Proxy Dépendance d'un algorithme particulier... Builder, Iterator, Strategy, TemplateMethod, Strategy Couplage fort... relâcher les relations utilisez AbstractFactory, Bridge, Chain Of Responsibility, Command, Facade, Mediator, Observer

90 Master ISIDIS90 Concevoir pour l’évolution (3)  Quelques raisons de « reengineering » : Etendre les fonctionnalités en sous-classant peut être couteux (tests, compréhension des superclasses, etc) utilisez aussi la délégation, la composition...Bridge, Chain Of Responsibility, Composite, Decorator, Observer, Strategy, Proxy Impossibilité de modifier une classe...absence du source, trop de répercussions, voyez Adapter, Decorator, Visitor

91 Master ISIDIS91 Design Pattern : Exemple

92 Master ISIDIS92  Une jeu de dés  Un joueur lance 10 fois 2 dés  Si le résultat = 7, alors score=score + 10 points  A la fin, le score du joueur est enregistré dans la table des « highscores » Une premier exemple :

93 Master ISIDIS93 Diagramme d’activité menu view Highscore Start turn=0 Roll Dice turn++ Update highscore Turn<10 [highscore][start][exit] [true] [false]

94 Master ISIDIS94 Diagramme de classes

95 Master ISIDIS95 Modélisation  Gestion de l’IHM  Gestion de la persistance du « highscore » dans une base de données ou un fichier  Réalisation d’une architecture par niveaux : application du « Layer Architectural Pattern »

96 Master ISIDIS96 Niveaux  Aide à structurer une application qui peut être décomposée en groupes de sous-tâches Chaque groupe est un niveau particulier d’abstraction

97 Master ISIDIS97 Niveaux : exemple

98 Master ISIDIS98 Niveaux : structure

99 Master ISIDIS99 Niveaux : structure

100 Master ISIDIS100 Niveaux et composants

101 Master ISIDIS101 Niveaux : variantes  « Relaxed Layered System » Un niveau « j » peut utiliser les services de niveaux j – 1, j – 2, … Un niveau peut être partielle opaque  Des services au niveau j + 1 et les autres dans d’autres niveaux  Faire des niveaux par héritage Les niveaux du plus bas niveau sont implémentés comme les classes de base Les niveaux supérieurs peuvent redéfinir (surcharger) les niveaux inférieurs

102 Master ISIDIS102 Niveaux : exemples d’utilisation  Machines virtuelles : JVM et le format de code binaire  API : niveaux qui encapsulent des niveaux inférieurs  Windows NT : Services System Resource management (Object manager, security monitor, process manager, I/O manager, VM manager) Kernel (exception handling, interrupt, threads) HAL (Hardware Abstraction Level) Hardware

103 Master ISIDIS103 Niveaux : avantages  Réutilisabilité des niveaux  Support pour la standardisation (OSI)  Les dépendances sont conservées localement  Souplesse : Remplacement d’une ancienne implémentation avec le « Adapter Pattern » Échange dynamique avec le « Bridge Pattern »

104 Master ISIDIS104 Niveaux : inconvénients  Enchaînement de comportements différents  Faible efficacité  Travaille inutile : les fonctions d’un niveau peuvent être appelées plusieurs fois pour un même service  Difficulté pour établir une granularité correcte pour les niveaux : Pas assez de niveaux  Pas de bénéfices Trop de niveaux  Complexité

105 Master ISIDIS105 Application de l’architecture par niveaux

106 Master ISIDIS106 Décomposition en package UI > Core > Persist > Util >

107 Master ISIDIS107 Niveau « core »  Contient les classes logiques  Adapte le diagramme de classe pour l’implémentation  Utilise le « Singleton »

108 Master ISIDIS108 Singleton  Assure qu’un classe n’a qu’une seule instance et une seule  Fournit un point d’accès à celle-ci

109 Master ISIDIS109 Niveau « core » : premier diagramme Design Analyse

110 Master ISIDIS110 Décomposition des packages UI > Core > Persist > Util >

111 Master ISIDIS111 Observeurs  Dépendances du type « un à plusieurs » entres les objets  Le changement d’un objet va automatiquement prévenir les observeurs

112 Master ISIDIS112 Observeurs : application  Le changement d’un objet entraîne le changement d’un ensemble d’objets inconnus  L’objet peut notifier un changement à un autre sans qu’il le sache à l’avance

113 Master ISIDIS113 Observeurs : conséquences  Couplage abstrait entre les observés et les observeurs  Permet de réaliser des communications de type « broadcast »  Difficile à maintenir

114 Master ISIDIS114 Utilisation des observeurs

115 Master ISIDIS115 Observeurs : vue

116 Master ISIDIS116 Les vues sont des objets graphiques

117 Master ISIDIS117 Diagramme de séquences

118 Master ISIDIS118 Propagation des changements : Die : Randomizer : DieView 1: getValue( ) 2: setValue(int) 3: notifyObservers( ) 4: update(Observable, Object) 5: getState() 3 : JLabel 6: setText(3)

119 Master ISIDIS119 Architecture en niveaux UI Core Découplage des classes Et des interfaces

120 Master ISIDIS120 Décomposition des packages UI > Core > Persist > Util >

121 Master ISIDIS121 Pattern Factory Method  Caractéristiques : Défini une interface pour créer un objet, mais laisse les sous-classes décider quelle classe instancier Laisse une classe déléguer l’instanciation aux sous-classes

122 Master ISIDIS122 Pattern Factory Method  Applicabilité : Une classe ne peut anticiper la classe d’objet qu’elle doit créer Une classe veut que ses sous-classes spécifient les objets qu’elle crée

123 Master ISIDIS123 Niveau « persist »  Classes techniques de persistance  Assurer l’indépendance core/persist Pouvoir changer de « persistent engine »  Par exemple : Persistance par « sérialisation » Persistance via une base de données relationnelle (JDBC/MySql par exemple)

124 Master ISIDIS124 Application du pattern Produit abstrait Fabrique abstraite Produit concret Fabrique concrète

125 Master ISIDIS125 Application du pattern

126 Master ISIDIS126 Résumé 1.Acrhitectural Pattern : Niveaux 2.Design Pattern : Observer, Factory, Singleton 3.Problème : Combiner les patterns pour combiner leurs forces…

127 Master ISIDIS127 Un deuxième exemple :une banque  Un système bancaire basique : 1 banque, n comptes Chaque compte appartient à un client Chaque compte est crédité d’un certain montant  Fonction de la banque : Débiter un compte Créditer un compte Transférer de l’argent d’un compte à un autre

128 Master ISIDIS128 Solution naïve

129 Master ISIDIS129 Solution naïve

130 Master ISIDIS130 Application du « Pattern Command »  Encapsule une requête comme un objet  Permet de paramétrer des clients avec différentes requêtes  Supporte le undo

131 Master ISIDIS131 « Pattern Command » : conséquences  Découple l’objet qui invoque la commande de celui qui sait comment la réaliser  Il est facile d’ajouter de nouvelles commandes

132 Master ISIDIS132 Application du « Pattern Command »

133 Master ISIDIS133 Application du « Pattern Command »

134 Master ISIDIS134 « Composite Pattern »  Compose les objets en une structure d’arbre pour représenter une hiérarchie complète ou partielle  Le composite laisse le client traiter les objets individuels et les objets composites de manière uniforme

135 Master ISIDIS135 Application du « Composite Pattern »

136 Master ISIDIS136

137 Master ISIDIS137 Utilisation de Singleton

138 Master ISIDIS138 Et ainsi de suite…  Sauvegarde de l’état : Memento Pattern  Observer le compte : Observer Pattern  Balayer tous les objets du graphe : Visitor Pattern  Accès distant : Proxy Pattern  …

139 Master ISIDIS139 Utilisation du proxy

140 Master ISIDIS140 Cas d’étude

141 Master ISIDIS141 Problèmes de modélisation  Structure du document The choice of internal representation for the document affects nearly every aspect of Lexi's design. All editing, formatting, displaying, and textual analysis will require traversing the representation. The way we organize this information will impact the design of the rest of the application.

142 Master ISIDIS142 Problèmes de modélisation  Formatage How does Lexi actually arrange text and graphics into lines and columns? What objects are responsible for carrying out different formatting policies? How do these policies interact with the document's internal representation?

143 Master ISIDIS143 Problèmes de modélisation  Amélioration de l’IHM Lexi's user interface includes scroll bars, borders, and drop shadows that embellish the WYSIWYG document interface. Such embellishments are likely to change as Lexi's user interface evolves. Hence it's important to be able to add and remove embellishments easily without affecting the rest of the application.

144 Master ISIDIS144 Problèmes de modélisation  Supporter le « look-and-feel » Lexi should adapt easily to different look- and-feel standards such as Motif and Windows and Mac without major modification.

145 Master ISIDIS145 Problèmes de modélisation  Correction orthographique et césure How does Lexi support analytical operations such as checking for misspelled words and determining hyphenation points? How can we minimize the number of classes we have to modify to add a new analytical operation?

146 Master ISIDIS146

147 Master ISIDIS147

148 Master ISIDIS148

149 Master ISIDIS149

150 Master ISIDIS150

151 Master ISIDIS151

152 Master ISIDIS152

153 Master ISIDIS153

154 Master ISIDIS154

155 Master ISIDIS155

156 Master ISIDIS156

157 Master ISIDIS157

158 Master ISIDIS158

159 Master ISIDIS159

160 Master ISIDIS160

161 Master ISIDIS161

162 Master ISIDIS162 Autres exemple d’utilisation des patterns : SWING

163 Master ISIDIS163 Swing  Swing est une extension des AWT nombreux nouveaux composants nombreuses facilités séparation entre :  modèle (données)  aspect visuel (UI)  contrôle  Les composants sont légers, sauf JApplet, JWindow, JFrame, JDialog  Ces derniers ont une structure spéciale

164 Master ISIDIS164 Swing – l’arbre d’héritage

165 Master ISIDIS165 JFrame  Une JFrame contient une fille unique, de la classe JRootPane.  Cette fille contient deux filles, glassPane ( JPanel ) et layeredPane ( JLayeredPane ).  La layeredPane a deux filles, contentPane (un Container ) et menuBar (null JMenuBar ).  On travaille dans contentPane.  JApplet, JWindow et JDialog sont semblables. class Tout extends JFrame { Tout() { JPanel panel; getContentPane().add(panel);... }... }

166 Master ISIDIS166 Modèles et vues  Les composants (sauf les conteneurs) ont un modèle qui contient les données associées ButtonModel pour les boutons ListModel pour les données d’un JList TableModel pour les JTable TreeModel pour les JTree Document pour tous les composants de texte  La vue d’un composant sont agrégés en un délégué UI (User Interface) détermine le look-and-feel du composant (bord, couleur, ombre, forme des coches) peut- être changé est parfois spécifié par un dessinateur (renderer) à un niveau plus élevé un changement global, pour tous les composants, est le pluggable look and feel (plaf) trois implémentations (quatre ave le Mac) existent : Windows, CDE/ Motif, Metal (défaut).  Le contrôle est assuré par le modèle.

167 Master ISIDIS167 Look and Feel  Trois “look and feel” existent, de noms "com. sun. java. swing. plaf. windows.WindowsLookAndFeel" "com. sun. java. swing. plaf. motif.MotifLookAndFeel" "javax. swing. plaf. metal. MetalLookAndFeel”  On essaye de l’utiliser par UIManager.setLookAndFeel(lf);  et de l’appliquer à la racine de l’arbre par SwingUtilities. updateComponentTreeUI (SwingUtilities.getRoot(this));

168 Master ISIDIS168 Actions  Moyen commode pour définir une entrée (dans un menu) et simultanément y attacher un auditeur  Entrée simultanée dans Toolbar possible  Tout changement dans l’un se reflète sur l’autre (grisé etc.)

169 Master ISIDIS169 AbstractAction  AbstractAction est une classe abstraite elle implémente l’interface Action Action étend ActionListener la seule méthode à écrire est actionPerformed()  Les conteneurs JMenu, JPopupMenu et JToolBar honorent les actions : un même objet d’une classe implémentant AbstractAction peut être « ajouté » à plusieurs de ces conteneurs. les diverses instances opèrent de concert. par exemple, un objet ajouté à un menu et à une barre d’outils est activé ou désactivé simultanément dans les deux.  Les classes dérivées de AbstractAction sont utiles quand une même action peut être déclenchée de plusieurs manières.

170 Master ISIDIS170 Emploi d’AbstractAction  Création d’une classe qui étend AbstractAction  Utilisation comme ActionListener  Utilisation dans un menu et dans une barre d’outils class MonAction extends AbstractAction { public void actionPerformed(ActionEvent e) {... } Action monAction = new MonAction(); JButton b = new JButton("Hello"); b. addActionListener(monAction); Action copyAction = new MonAction("Copy"); JMenu menu = new JMenu("Edit"); JToolBar tools = new JToolBar(); JMenuItem copyItem = menu.add(copyAction); JButton copyBtn = tools.add(copyAction);

171 Master ISIDIS171 JTabbedPane  Groupe une liste de conteneurs repérés par des onglets.  Création:  Ajout de conteneurs à un tabbedPane : JTabbedPane() JTabbedPane( int cotéOnglets) addTab(String texteOnglet, Component composant) addTab(String texteOnglet, Icon icone, Component composant) addTab(String texteOnglet, Icon icone, Component composant, String toolTipText)

172 Master ISIDIS172 JTabbedPane  Feuille initiale  Récupérer le choix  Et la feuille elle-même  Nombre total de feuilles tabbedPane.setSelectedIndex(int numero) int tabbedPane. getSelectedIndex() Component tabbedPane.getComponentAt(int numero); int tabbedPane.getTabCount();

173 Master ISIDIS173 JTabbedPane : exemple (1)  Pour naviguer ajouter, enlever les feuilles choisir la position des onglets  De plus un message affiche le numéro de l’onglet, à chaque changement

174 Master ISIDIS174 JTabbedPane : exemple (2)  Acteurs principaux class Panneau extends JPanel implements ActionListener { String [] imageNames = {"arques","berstel","crochemore","desarmenien",...}; ImageIcon[] images = new ImageIcon[imageNames.length]; //les images montrées ImageIcon tabimage; //l’icône dans les onglets JTabbedPane tabbedPane; //le panneau à feuilles String[] boutonNames = {"TOP","BOTTOM","LEFT","RIGHT","add","remove"}; JButton[] boutons = new JButton[boutonNames.length]; //les boutons de gestion JLabel statut; //le message d’état AudioClip layoutson, tabson; //les sons des actions Panneau() {} //création de la scène void createTab() {} //ajoute une feuille et son onglet void killTab() {} //supprime une feuille void setStatus(int index) {...} //gestion du message public void actionPerformed(ActionEvent e) {...} //les actions des boutons }

175 Master ISIDIS175 JTabbedPane : exemple (3)  Création/Suppression de feuilles public void createTab() { JLabel feuille = null; int ong = tabbedPane.getTabCount(); feuille = new JLabel(imageNames[ong % images.length], images[ong % images.length], SwingConstants.CENTER); feuille.setOpaque(true); feuille.setBackground(Color. green); tabbedPane.addTab("Feuille No " + ong, tabimage, feuille); tabbedPane.setSelectedIndex(ong); setStatus(ong); } public void killTab() { // dernière if (tabbedPane.getTabCount()> 0) { tabbedPane.removeTabAt(tabbedPane.getTabCount() - 1); setStatus(tabbedPane.getSelectedIndex()); } public void setStatus( int index) { if (index > -1) statut.setText("Feuille choisie: " + index); else statut.setText("Pas de feuille choisie"); }

176 Master ISIDIS176 JTabbedPane : exemple (4)  Les actions des boutons  La classe SwingConstants contient les constantes de placement public void actionPerformed(ActionEvent e) { String lib = ((JButton) e.getSource()).getActionCommand(); if (lib.equals(boutonNames[0])) { tabbedPane.setTabPlacement(SwingConstants.TOP); layoutson.play(); } else if (lib.equals(boutonNames[1])) { tabbedPane.setTabPlacement(SwingConstants.BOTTOM); layoutson.play(); } else if (lib.equals(boutonNames[2])) { tabbedPane.setTabPlacement(SwingConstants.LEFT); layoutson.play(); } else if (lib.equals(boutonNames[3])) { tabbedPane.setTabPlacement(SwingConstants.RIGHT); layoutson.play(); } else if (lib.equals(boutonNames[4])) createTab(); else if(lib.equals(boutonNames[5])) killTab(); }

177 Master ISIDIS177 JTabbedPane : exemple (5) Panneau() { tabimage = new ImageIcon("gifs/tabimage.gif"); for (int i = 0 ; i < images.length; i++) images[i] = new ImageIcon("gifs/" + imageNames[i] +".jpg"); for (int i = 0; i < boutons.length; i++) boutons[i] = new JButton(boutonNames[i]); statut = new JLabel(); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(0,1)); for (int i = 0; i < boutons.length ; i++){ boutons[i].addActionListener(this); buttonPanel.add(boutons[i]); } JPanel leftPanel = new JPanel(); leftPanel.add(buttonPanel); tabbedPane = new JTabbedPane(SwingConstants.TOP); createTab(); createTab(); tabbedPane.addChangeListener(new ChangeListener(){ public void stateChanged(ChangeEvent e) { setStatus(((JTabbedPane) e.getSource()).getSelectedIndex()); tabson.play(); } }); setLayout(new BorderLayout()); add(leftPanel, BorderLayout.WEST); add(statut, BorderLayout.SOUTH); add(tabbedPane, BorderLayout.CENTER); }

178 Master ISIDIS178 JTabbedPane : exemple (6)  On modifie le contenu après le chargement  La méthode revalidate sert à « forcer » le réaffichage. public void init() { JLabel loading = new JLabel("Initialisation en cours...", JLabel.CENTER); setContentPane(loading); setVisible(true); getRootPane().revalidate(); try { Thread. sleep( 1000); } catch (InterruptedException e) {}; layoutson = getAudioClip(getCodeBase(), "switch.wav"); tabson = getAudioClip(getCodeBase(), "tab.wav"); Panneau panneau = new Panneau(); panneau.addAudioClips(layoutson, tabson); setContentPane(panneau); }

179 Master ISIDIS179 JScrollPane  Gère automatiquement des ascenseurs autour de son composant central qui est un JViewPort.  Constructeurs principaux  Une « vue » s’ajoute au JViewPort, si elle ne l’est dans le constructeur, par JScrollPane() JScrollPane(Component view) scrollPane.getViewPort().add(view)

180 Master ISIDIS180 Exemple class ScrollPanel extends JPanel { public ScrollPanel() { setLayout(new BorderLayout()); Icon iconeTigre = new ImageIcon("BigTiger.gif"); JLabel etiquetteTigre = new JLabel(iconeTigre); JScrollPane scrollPane = new JScrollPane(etiquetteTigre); add(scrollPane, BorderLayout.CENTER); }

181 Master ISIDIS181 JSplitPane  Panneau à compartiments, chaque compartiment est ajustable  Seule une classe de look-and-feel est nécessaire.  Panneau à séparation verticale ou horizontale  Constructeurs : JSplitPane(int orientation, boolean dessinContinu, Component gauche, Component droit) JSplitPane(int orientation, Component gauche, Component droit) JSplitPane(int orientation, boolean dessinContinu) JSplitPane(int orientation) JSplitPane() // horizontal par défaut

182 Master ISIDIS182 JSplitPane : exemple (1)  La taille de la barre de séparation peut être réglée par setDividerSize(int taille)  L’affichage continue spécifié explicitement par setContinuousLayout(boolean dessinContinu)  Poignée d’ouverture/ fermeture spécifiées par setOneTouchExpandable(boolean ouvrable) ImageIcon bleue = new ImageIcon("bleue.gif"); aireGauche = new PanneauBoules(150, bleue.getImage()); ImageIcon rouge = new ImageIcon("rouge.gif"); aireDroite = new PanneauBoules(150, rouge.getImage()); JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_ SPLIT, aireGauche, aireDroite); sp.setDividerSize(5); sp.setContinuousLayout(true); getContentPane().add(sp, BorderLayout.CENTER);

183 Master ISIDIS183 JSplitPane : exemple (2) public class Split extends JFrame { protected PanneauBoules aireGauche, aireDroite; public Split() {... ImageIcon bleue = new ImageIcon("bleue. gif"); aireGauche = new PanneauBoules(150, bleue.getImage()); ImageIcon rouge = new ImageIcon("rouge.gif"); aireDroite = new PanneauBoules(150, rouge.getImage()); JSplitPane sp = new JSplitPane(JSplitPane. HORIZONTAL_ SPLIT, aireGauche, aireDroite); sp.setDividerSize(5); sp.setContinuousLayout(true); getContentPane().add(sp, BorderLayout.CENTER); setVisible(true);... new Thread(aireGauche).start(); new Thread(aireDroite).start(); }

184 Master ISIDIS184 JSplitPane : exemple (3) class PanneauBoules extends JPanel implements Runnable, ComponentListener { Boule[] boules; Image img; Dimension dim; int sommeil; public PanneauBoules(int nBoules, Image img) { sommeil = 10; this.img = img; setBackground(Color.yellow); setPreferredSize(new Dimension(200, 300)); addComponentListener(this); boules = new Boule[nBoules]; dim = getPreferredSize(); for (int k= 0; k < nBoules; k++) boules[k] = new Boule(dim); } public void run() {...} }

185 Master ISIDIS185 JSplitPane : exemple (5)  Runnable public void run() { for(;;) { for (int k = 0; k < boules.length; k++) boules[k].move(dim); repaint(); if (sommeil != 0) { try { Thread.sleep(sommeil); } catch(InterruptedException e) {} } public void paintComponent(Graphics g) { g.setColor(getBackground()); g.fillRect(0, 0, dim.width, dim.height); for (int k = 0; k < boules.length; k++) g. drawImage(img,(int) boules[k].x,(int) boules[k].y, this); }

186 Master ISIDIS186 JSplitPane : exemple (6)  ComponentListener public void componentHidden(ComponentEvent e){} public void componentShown(ComponentEvent e){} public void componentMoved(ComponentEvent e){} public void componentResized(ComponentEvent e){ dim = getSize(); for (int k = 0; k < boules.length; k++) boules[k].moveIntoRect(dim); }

187 Master ISIDIS187 JSplitPane : exemple (7)  Les boules class Boule { protected double x, y, vx, vy; public Boule(Dimension dim) { x = dim.width * Math.random(); y = dim.height * Math.random(); double angle = 2 * Math.PI * Math.random(); vx = 2* Math.cos(angle); vy = 2* Math.sin(angle); } public void move(Dimension dim) { double nx =x +vx; double ny =y +vy; if ((nx dim.width)) { vx = - vx; nx = x +vx; } if ((ny dim.height)) { vy = - vy; ny = y +vy; } x = nx; y = ny; } public void moveIntoRect(Dimension dim) { x = Math.max(x, 0); x = Math.min(x, dim.width); y = Math.max(y, 0); y = Math.min(y, dim.height);

188 Master ISIDIS188 JTree  Description hiérarchique de données  Sept autre classes utilisées TreeModel : contient les données figurant dans l’arbre TreeNode : implémentation des nœuds et de la structure d’arbre TreeSelectionModel : contient le ou les nœuds sélectionnés TreePath : un tel objet contient un chemin (de la racine vers le sommet sélectionné par exemple) TreeCellRenderer : est appelé pour dessiner un nœud TreeCellEditor : l’éditeur pour un nœud est éditable TreeUI : look-and-feel

189 Master ISIDIS189 JTree  Un arbre est créé à partir d’un TreeModel  Il existe plusieurs modèles de sélection sélection d’un seul élément sélection de plusieurs éléments contigus sélection de plusieurs éléments disparates  On peut indiquer un CellRenderer pour afficher une cellule de façon particulière.  On peut indiquer un CellEditor pour changer la valeur d’une cellule interface TreeModel {... public Object getChild(Object parent, int index); public Object getRoot(); public boolean isLeaf(Object node);... }

190 Master ISIDIS190 JTree  JTree fournit une vue du modèle  Le modèle d’arbre est en deux étapes:  Le modèle des nœuds est en trois étages:  Constructeurs une feuille  peut recevoir des fils ?  reste sans fils ? interface TreeModel class DefaultTreeModel implements TreeModel interface TreeNode interface MutableTreeNode extends TreeNode class DefaultMutableTreeNode implements MutableTreeNode JTree() JTree(TreeNode racine) JTree(TreeNode racine, boolean enfantsPermis) JTree(TreeModel modele) JTree(TreeModel modele, boolean enfantsPermis)

191 Master ISIDIS191 Jtree : exemple class Arbre extends JPanel { JTree tree; public Arbre() { DefaultMutableTreeNode top, noeud, fils, n; top = new DefaultMutableTreeNode("Top"); tree = new JTree(top); noeud = new DefaultMutableTreeNode("Repertoire 1"); top.add(noeud); n = new DefaultMutableTreeNode("1a"); noeud.add(n); n = new DefaultMutableTreeNode("1b"); noeud.add(n);... noeud = new DefaultMutableTreeNode("Repertoire 2"); top.add(noeud); n = new DefaultMutableTreeNode("2a"); noeud.add(n);.... fils = new DefaultMutableTreeNode("2d"); noeud.add(fils); n = new DefaultMutableTreeNode("3a"); fils.add( n); }... }

192 Master ISIDIS192 JTree  Le contenu d’un nœud est appelé user object  C’est un objet  A l’affichage, la méthode toString() d’un nœud  délègue à la méthode toString() du contenu.

193 Master ISIDIS193 JTree  Un DefaultTreeCellRenderer s’occupe du rendu. Il peut être modifié par des fonctions utilitaires par une redéfinition DefaultTreeCellRenderer rendu ; rendu = (DefaultTreeCellRenderer) tree.getCellRenderer(); rendu.setOpenIcon(new ImageIcon("Opened.gif")); rendu.setLeafIcon(new ImageIcon("Leaf.gif"));

194 Master ISIDIS194 JTree  Un TreeSelectionListener rapporte tous les changements dans les sélections  De nombreuses fonctions utilitaires tree.addTreeSelectionListener(new Selecteur()); class Selecteur implements TreeSelectionListener { public void valueChanged(TreeSelectionEvent e ) { message.setText("Nouveau : " + e.getNewLeadSelectionPath()); }

195 Master ISIDIS195 JTree  On parcourt un arbre par une énumération  Il en existe quatre : breadthFirstEnumeration depthFirstEnumeration postorderEnumeration preorderEnumeration public void actionPerformed(ActionEvent ev) { DefaultMutableTreeNode n, top; Enumeration e; top = (DefaultMutableTreeNode) tree.getModel().getRoot(); System.out.println("\ n En largeur"); e =top.breadthFirstEnumeration(); while (e.hasMoreElements()) { n = (DefaultMutableTreeNode) e.nextElement(); System.out.println(n.getUserObject() + " "); }

196 Master ISIDIS196 JTree : exemple(1)  Dans cette application, on entre un nom de classe dans la zone de texte, et la classe s’insère dans la hiérarchie des classes.  La classe Class permet de connaître la classe mère.  On n’insère une classe que si elle n’est pas déjà dans l’arbre.

197 Master ISIDIS197 JTree : exemple(2)  C’est addClass(Class c) qui fait l’insertion class ClassTreeFrame extends JFrame implements ActionListener { private DefaultMutableTreeNode root; private DefaultTreeModel model; private JTree tree; private JTextField textField; public ClassTreeFrame() { setTitle("ClassTree"); root = new DefaultMutableTreeNode(Object.class); model = new DefaultTreeModel(root); tree = new JTree(model); addClass( getClass()); getContentPane().add(new JScrollPane(tree), "Center"); textField = new JTextField(); textField.addActionListener(this); getContentPane().add(textField, "South"); }... }

198 Master ISIDIS198 JTree : exemple(3) public DefaultMutableTreeNode addClass(Class c) { if (c.isInterface() || c.isPrimitive()) return null; //pas les interfaces findUserObject(c) //cherche c dans tree DefaultMutableTreeNode node = findUserObject(c); if (node != null) return node; Class s = c.getSuperclass(); //classe mère DefaultMutableTreeNode parent = addClass(s); //appel récursif DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(c); model.insertNodeInto(newNode, parent, parent.getChildCount()); //à la fin //développe l’arbre pour que le nœud soit visible TreePath path = new TreePath(model.getPathToRoot(newNode)); tree.makeVisible(path); return newNode; }

199 Master ISIDIS199 JTree : exemple(4)  Trouver un nœud dans un arbre Un simple parcours, en largeur par exemple public DefaultMutableTreeNode findUserObject(Object obj){ Enumeration e = root.breadthFirstEnumeration(); while (e.hasMoreElements()) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement(); if (node.getUserObject().equals(obj)) return node; } return null; }

200 Master ISIDIS200 JTree : exemple(5)  Lire le nom de la classe On fait confiance à Java… public void actionPerformed(ActionEvent event) { String text = textField.getText(); try { Class c = Class.forName(text); //essayons addClass(c); textField.setText(""); } catch (ClassNotFoundException e) { Toolkit.getDefaultToolkit().beep(); //si la classe n’existe pas }

201 Master ISIDIS201 JTable  JTable affiche des données dans un tableau  TableModel régit la gestion des données  On peut fournir les données dans un tableau bidimensionnel d’objets : Object[][] et utiliser le DefaultTableModel, mais il vaut mieux étendre AbstractTableModel.  La sélection est régi par une modèle de sélection  De plus, il y a un modèle de colonnes.  Un tableau est entouré d’ascenseurs, en général.

202 Master ISIDIS202 JTable  Les constructeurs sont : JTable() modèles par défaut pour les trois modèles JTable(int numRows, int numColumns) avec autant de cellules vides JTable(Object[][] rowData, Object[] columnNames) avec les valeurs des cellules de rowData et noms de colonnes columnNames. JTable(TableModel dm) avec le modèle de données dm, les autres par défaut. JTable(TableModel dm, TableColumnModel cm) avec modèle de données et modèle de colonnes fournis. JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) Les trois modèles sont fournis. JTable(Vector rowData, Vector columnNames) ici, les données sont fournies par colonne.

203 Master ISIDIS203 JTable : exemple class TablePlanetes extends JPanel { TablePlanetes() { setLayout(new BorderLayout()); JTable table = new JTable(cellules, columnNames); add(new JScrollPane(table), BorderLayout.CENTER); } private Object[][] cellules = { { "Mercure", new Double(2440), new Integer(0), "non"}, { "Vénus", new Double(6052), new Integer(0), "non"}, { "Terre", new Double(6378), new Integer(1), "non"}, { "Mars", new Double(3397), new Integer(2), "non"}, { "Jupiter", new Double(71492), new Integer(16), "oui"}, { "Saturne", new Double(60268), new Integer(18), "oui"}, { "Uranus", new Double(25559), new Integer(17), "oui"}, { "Neptune", new Double(24766), new Integer(8), "oui"}, { "Pluton", new Double(1137), new Integer(1), "non"} }; private String[] columnNames = { "Planète", "Rayon", "Lunes", "Gazeuse"};

204 Master ISIDIS204 JTable  Les données sont accessible par un modèle. Ils peuvent être stockés ou calculés, de façon transparente.  La classe AbstractTableModel implémente les méthodes d’un modèle de table, sauf  qui retournent respectivement le nombre de lignes le nombre de colonnes l’objet à afficher dans les ligne et colonne indiquées (sa méthode toString est utilisée). public int getRowCount() public int getColumnCount() public Object getValueAt(int ligne, int colonne)

205 Master ISIDIS205 JTable : un premier exemple  En plus des trois méthodes obligées, la fonction getColumClass a été redéfinie, ce qui produit la justification à droite class SimpleTable extends JPanel { SimpleTable() { setLayout(new BorderLayout()); TableModel dataModel = new AbstractTableModel() { public int getColumnCount() { return 10; } public int getRowCount() { return 10;} public Object getValueAt(int row, int col) { return new Integer((1 + row)*(1 + col)); } public Class getColumnClass(int column) { return Number.class; } }; JTable table = new JTable(dataModel); add(new JScrollPane(table)); }

206 Master ISIDIS206 JTable : un deuxième exemple  Construction par  avec bien entendu  méthodes à écrire (plus getColumnName qui, par défaut, numérote A, B, etc.): TableModel model = new ModelInvestment(30, 5, 10); JTable table = new JTable(model); class ModelInvestment extends AbstractTableModel {...} public int getRowCount() public int getColumnCount() public Object getValueAt(int ligne, int colonne) public String getColumnName(int colonne)

207 Master ISIDIS207 JTable : détails class ModelInvestment extends AbstractTableModel { private int annees; private int tauxMin; private int tauxMax; private static double depot = 100000.0; ModelInvestment(int annees, int tauxMin, int tauxMax) { this.annees = annees; this.tauxMin = tauxMin; this.tauxMax = tauxMax; } public int getRowCount() { return annees;} public int getColumnCount() { return tauxMax - tauxMin + 1;} public Object getValueAt(int ligne, int colonne) { double taux = (colonne + tauxMin) / 100.0; double depotFinal = depot * Math.pow(1 + taux, ligne); return NumberFormat.getCurrencyInstance().format(depotFinal); } public String getColumnName(int colonne) { double taux = (colonne + tauxMin) / 100.0; return NumberFormat.getPercentInstance().format(taux); }

208 Master ISIDIS208 JTable  La classe abstraite java.text.NumberFormat est la classe de base pour le formatage de nombres.  Nombreuses méthodes statiques retournant des formats appropriés.  Le formatage effectif se fait par la méthode du format  Exemples de méthodes:  Le format dépend de la Locale, c’est-à-dire du pays concerné. NumberFormat.getNumberInstance() NumberFormat.getCurrencyInstance() NumberFormat.getPercentInstance() String format(int donnée)

209 Master ISIDIS209 JTable  La méthode boolean TableModel.isCellEditable(int l, int c) renvoie true si la cellule peut être modifiée (par défaut non)  La méthode int JTable.columnAtPoint(Point p) renvoie l’indice de la colonne du tableau où est le point  La méthode int JTable.convertColumnIndexToModel(int colonne) renvoie l’indice, dans le modèle, de l’indice colonne

210 Master ISIDIS210 JTable : tri par ligne (1)  On veut trier les lignes, en fonction d’une colonne désignée par un double clic.  On veut que le tri se fasse sur la vue, pas sur le modèle, pour que le modèle soit inchangé.  Pour cela, on introduit un filtre de modèle similaire aux filtres de streams.  Ce filtre enregistre une référence au modèle réel, et intercepte les communications entre la table et son modèle pour les réinterpréter.  Le filtre maintient une permutation des lignes déterminée par le tri virtuel des lignes en fonction de la colonne choisie.

211 Master ISIDIS211 JTable : tri par ligne (2)  Le modèle est associé à la table class TablePlanetes extends JPanel { TablePlanetes() { setLayout(new BorderLayout()); DefaultTableModel model = new DefaultTableModel(cellules, columnNames); FiltreTriModel sorter = new FiltreTriModel(model); JTable table = new JTable(sorter); sorter.addEcouteur(table); add(new JScrollPane(table), BorderLayout.CENTER); } private Object[][] cellules ={... }; private String[] columnNames = {... }; }

212 Master ISIDIS212 JTable : tri par ligne (3)  La classe FiltreTriModel est un modèle de table avec une référence au modèle réel un tableau de lignes une méthode de tri de ce tableau  Le tri est fait par la méthode statique de la classe Arrays, en fonction de la colonne choisie.  Pour cela, la classe Ligne doit implémenter l’interface Comparable. class FiltreTriModel extends AbstractTableModel { public FiltreTriModel(TableModel m) { model = m; lignes = new Ligne[model.getRowCount()]; for (int i = 0; i < lignes.length; i++) { lignes[i] = new Ligne(); lignes[i].index = i; } public void sort(int c) { colonneTri = c; Arrays.sort(lignes); fireTableDataChanged(); }... private TableModel model; private int colonneTri; private Ligne[] lignes; }

213 Master ISIDIS213 JTable : tri par ligne (4)  La classe Ligne est interne à FiltreTriModel pour accéder facilement aux données.  Une ligne est plus petite qu’une autre si son élément dans la colonne de tri est plus petit que l’élément de cette même colonne dans l’autre ligne. class FiltreTriModel extends AbstractTableModel {... private class Ligne implements Comparable { public int index; public int compareTo(Object autre) { Ligne autreLigne = (Ligne) autre; Object cellule = model.getValueAt(index, colonneTri); Object autreCellule = model.getValueAt(autreLigne.index, colonneTri); return ((Comparable) cellule).compareTo(autreCellule); }

214 Master ISIDIS214 JTable : tri par ligne (5)  Les trois fonctions obligées tiennent compte de l’ordre virtuel class FiltreTriModel extends AbstractTableModel {... public Object getValueAt(int r, int c) { return model.getValueAt(lignes[r].index, c); } public int getRowCount(){ return model.getRowCount();} public int getColumnCount(){ return model.getColumnCount();} public String getColumnName(int c){ return model.getColumnName(c);} public Class getColumnClass(int c){ return (c == 1 || c == 2) ? Number.class : Object.class; }

215 Master ISIDIS215 JTable : tri par ligne (6)  Et le double clic C’est l’en-tête de colonne qui réagit. Au double clic sur une colonne, on récupère le numéro de la colonne dans le modèle class FiltreTriModel extends AbstractTableModel {... public void addEcouteur(final JTable table) { table.getTableHeader().addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent event) { if (event.getClickCount() < 2) return; int tc = table.columnAtPoint(event.getPoint()); int mc = table.convertColumnIndexToModel(tc); sort(mc); } }); }

216 Master ISIDIS216 JTable : tri par ligne (7)  Événements La classe JTable écoute les événements reçus du modèle Le modèle a plusieurs méthodes pour signaler des modifications de données Les colonnes sont régies par un TableColumnModel qui a ses propres notificateurs d’événements fireTableDataChanged() fireTableStructureChanged() fireTableRowsInverted(int first, int last) fireTableRowsUpdated(int first, int last) fireTableRowsDeleted(int first, int last) fireTableCellUpdated(int row, int col) fireTableChangedEvent(TableModelEvent e)

217 Master ISIDIS217 Undo/Redo  Le « undo » (annuler) et « redo » (refaire) sont parmi les opérations les plus appréciées dans les interfaces ergonomiques.  Ce sont des opérations difficiles à implémenter.  Questions: quelles sont les transactions annulables ? quelle partie de l’environnement doit être sauvegardée pour pouvoir le reconstituer ? vaut- il mieux conserver l’opération, ou son inverse ?  Java fournit un cadre surtout adapté aux opérations sur les textes.  Plusieurs variantes existent, mais il reste du travail au programmeur.

218 Master ISIDIS218 UndoableEdit  L’interface de base est UndoableEdit. Une implémentation par défaut est AbstractUndoableEdit  « Edit » est synonyme de transaction ou opération, terme emprunté aux éditeurs de textes.  Les méthodes sont boolean canUndo() indique que la transaction peut être annulée boolean canRedo() indique que la transaction peut être refaite void die() la transaction ne peut plus être annulée ni répétée void redo() throws CannotRedoException refait la transaction void undo() throws CannotUndoException annule la transaction

219 Master ISIDIS219 AbstractUndoableEdit  C’est l’implémentation par défaut de UndoableEdit  Elle maintient deux booléens internes alive et done qui gèrent correctement le canUndo() et canRedo().  On sous-classe cette classe en redéfinissant undo() et redo().  On utilise la super-classe en appelant super. undo(), super.redo().

220 Master ISIDIS220 Exemple des boutons à cocher  L’opération de coche ou décoche peut être annulée ou refaite, à partir d’un autre composant (paire de boutons, plus souvent entrée de menu ou boutons d’une barre d’outils) Démarche:  Chaque action sur le bouton génère un objet d’une classe ToggleEdit dérivant de AbstractUndoableEdit. L’objet contient le bouton concerné l’état du bouton  La classe ToggleEdit redéfinit les méthodes undo() et redo().  L’opération d’annulation ou répétition est lancée en appelant la méthode undo() ou redo() sur l’objet créé.

221 Master ISIDIS221 ToggleEdit import javax.swing.undo.*; public class ToggleEdit extends AbstractUndoableEdit { private final JToggleButton bouton; private final boolean selectionne; public ToggleEdit(JToggleButton bouton) { this.bouton = bouton; selectionne = bouton.isSelected(); } public void redo() throws CannotRedoException { super.redo(); bouton.setSelected(selectionne); } public void undo() throws CannotUndoException { super.undo(); bouton.setSelected(!selectionne); }

222 Master ISIDIS222 Le panneau  Le panneau est composé de trois boutons à cocher  et de deux boutons d’annulation et répétition:  chaque bouton à cocher ( JCheckBox ) a un écouteur dont la méthode actionPerformed est : JCheckBox gras = new JCheckBox("gras"); JCheckBox ital = new JCheckBox("italique"); JCheckBox soul = new JCheckBox("souligné"); JButton undoButton = new JButton("Undo"); JButton redoButton = new JButton("Redo"); undoButton.addActionListener(new UndoIt()); redoButton.addActionListener(new RedoIt()); public void actionPerformed(ActionEvent ev) { JToggleButton b = (JToggleButton) ev.getSource(); edit = new ToggleEdit(b); updateButtons(); }

223 Master ISIDIS223 Les listeners class UndoIt implements ActionListener { public void actionPerformed(ActionEvent ev) { try { edit.undo(); } catch (CannotUndoException ex) {} finally { updateButtons(); } class RedoIt implements ActionListener { public void actionPerformed(ActionEvent ev) { try { edit.redo(); } catch (CannotRedoException ex) {} finally { updateButtons(); } private void updateButtons() { undoButton.setText(edit.getUndoPresentationName()); redoButton.setText(edit.getRedoPresentationName()); undoButton.setEnabled(edit.canUndo()); redoButton.setEnabled(edit.canRedo()); }

224 Master ISIDIS224 Complément  L’interface UndoableEdit a une méthode getPresentationName qui retourne une chaîne de caractère modifiable en fonction de la transaction  Les méthodes getUndoPresentationName et getRedoPresentationName concatènent le préfix Undo et Redo avec la chaîne fournie par getPresentationName class ToggleEdit { private final JToggleButton bouton; private final boolean selectionne;... public String getPresentationName() { return "\"" + bouton.getText() + (selectionne ? " on" : " off") + "\""; }...

225 Master ISIDIS225 Séquences de transactions  Pour se « souvenir » d’une séquence de transactions, et pouvoir revenir en arrière arbitrairement loin, on utilise un gestionnaire de transactions ( UndoManager ).  Un UndoManager gère les transactions ( Edit ). Il permet de reculer ( undo ) et d’avancer ( redo ) tant que possible.  Une transaction à inscrire dans un gestionnaire doit lui être notifiée, soit directement, par addEdit(UndoableEdit edit) soit en utilisant le fait qu’un UndoManager implémente un UndoableEditListener. On enregistre le gestionnaire dans la liste des auditeurs.

226 Master ISIDIS226 Implémentation simple  Un UndoManager étend CompoundEdit qui lui étend AbstractUndoableEdit  On remplace simplement la variable UndoEdit edit par UndoManager manager et on modifie actionPerformed() en conséquence

227 Master ISIDIS227 Modifications class TogglePanel extends Jpanel implements ActionListener { private UndoManager manager = new UndoManager(); private JButton undoButton,...; public void actionPerformed(ActionEvent e) { JToggleButton b = (JToggleButton) e.getSource(); manager.addEdit(new ToggleEdit(b)); updateButtons(); } class UndoIt implements ActionListener { public void actionPerformed(ActionEvent e){ try { manager.undo(); }... } private void updateButtons() { undoButton.setText(manager.getUndoPresentationName());... }

228 Master ISIDIS228 Un deuxième exemple  Le programme de départ affiche, au clic de souris, un carré ou un cercle, selon que la touche majuscule n’est pas ou est enfoncé.  La séquence des formes engendrées est enregistrée dans un vecteur en vue d’un affichage facile.  Comment l’adapter au undo/redo ? class SimplePaint extends JPanel { protected Vector formes = new Vector(); protected PaintCanvas canvas =new PaintCanvas(formes); protected int width = 50; protected int height = 50; public SimplePaint() { setLayout(new BorderLayout()); add(new Label("Do it", Label.CENTER), BorderLayout.NORTH); add(canvas, BorderLayout.CENTER); canvas.addMouseListener(new AjouterForme()); }... }

229 Master ISIDIS229 Les formes et le canvas class AjouterForme extends MouseAdapter { public void mousePressed(MouseEvent e) { Shape s; if (e.isShiftDown()) s = new Ellipse2D.Double(e.getX(), e.getY(), width, height); else s = new Rectangle2D.Double(e.getX(), e.getY(), width, height); formes.addElement(s); canvas.repaint(); } class PaintCanvas extends JPanel { Vector formes;... public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; super.paintComponent(g2); g2.setColor(Color.black); Enumeration enum = formes.elements(); while (enum.hasMoreElements()) { Shape shape = (Shape) enum.nextElement(); g2.draw(shape); }

230 Master ISIDIS230 Ajouter undo/redo (1)  Comme pour l’exemple précédent deux boutons « undo » et « redo » deux listeners d’actions, un sur chaque bouton  Création d’une classe FormeEdit pour les transactions, et de deux classes dérivées.

231 Master ISIDIS231 Ajouter undo/redo (2) class FormeEdit extends AbstractUndoableEdit { protected Vector formes; protected Shape shape; public FormeEdit(Shape shape, Vector formes) { this.formes = formes; this.shape = shape; } public void undo() { super.undo(); formes.remove(shape); } public void redo() { super.redo(); formes.add(shape); } class CarreEdit extends FormeEdit { public CarreEdit(Shape s, Vector v) { super(s, v); } public String getPresentationName() { return "carré"; }

232 Master ISIDIS232 AjouterForme public void mousePressed(MouseEvent e) { Shape shape; UndoableEdit edit; if (e.isShiftDown()) { shape = new Ellipse2D.Double(e.getX(), e.getY(), width, height); edit = new CercleEdit(shape, formes); } else { shape = new Rectangle2D.Double(e.getX(), e.getY(), width, height); edit = new CarreEdit(shape, formes); } formes.addElement(shape); manager.addEdit(edit); canvas.repaint(); updateButtons(); }

233 Master ISIDIS233 Événements  Il existe une classe spécifique UndoableEditEvent  Un tel événement comporte une source, et un UndoableEdit  Les auditeurs sont de l’interface UndoableEditListener, avec la méthode undoableEditHappened(UndoableEditEvent e).  UndoManager implémente UndoableEditListener, avec la méthode public void undoableEditHappened( UndoableEditEvent e){ addEdit( e.getEdit()) }  Usage :... UndoableEdit edit;... edit = new CercleEdit(shape, formes); UndoableEditEvent ue; ue = new UndoableEditEvent(this, edit);... manager. undoableEditHappened(ue);...

234 Master ISIDIS234 Mais…  Il manque une objet qui lance des UndoableEditEvent ’s. L’implémentation précédente fait comme si, la présente le fait.  Seuls les documents de textes sont capables, pour l’instant, d’en lancer. Lançons cela pour JPanel : class PaintCanvas extends JPanel {... Class uel = UndoableEditListener.class; public void addUndoableEditListener(UndoableEditListener listener) { listenerList.add(uel, listener); } public void removeUndoableEditListener(UndoableEditListener listener) { listenerList.remove(uel, listener); } public void fireUndoableEditUpdate(UndoableEditEvent e) { Object[] l = listenerList.getListenerList(); for (int i = l.length - 2; i >= 0; i -= 2) { if (l[i] == uel ) ((UndoableEditListener) l[i + 1]).undoableEditHappened(e); }

235 Master ISIDIS235 …et donc  Un UndoManager est un listener parfait  Il ne reste plus qu’à lancer les événements public FireUndo() {... canvas.addMouseListener(new AjouterForme()); canvas.addUndoableEditListener(manager); } public void mousePressed(MouseEvent e) { Shape shape; UndoableEdit edit; shape =... edit =... formes.addElement(shape); UndoableEditEvent ue = new UndoableEditEvent(this, edit); canvas.fireUndoableEditUpdate(ue); canvas.repaint(); updateButtons(); }

236 Master ISIDIS236 UndoableEditSupport  Pour faciliter la vie aux programmeurs (en attendant que les choses se simplifient), Java propose une classe utilitaire de gestion de listeners et d’envoi d’événements, les UndoableEditSupport.  Ils réalisent pour l’essentiel ce qui a été programmé en dur. class PaintCanvas extends JPanel { UndoableEditSupport support = new UndoableEditSupport();... public void addUndoableEditListener(UndoableEditListener listener) { support.addUndoableEditListener(listener); } public void removeUndoableEditListener(UndoableEditListener listener) { support.removeUndoableEditListener(listener); } public void postEdit(UndoableEdit e) {// le fireUndoableEditUpdate.... support.postEdit(e); }

237 Master ISIDIS237 UndoableEditSupport (fin)  Au lieu de lancer les événements, on poste les Edit : public void mousePressed(MouseEvent e) { UndoableEdit edit; edit =... canvas.postEdit(edit);... }

238 Master ISIDIS238 Dans les textes  Dans les textes, ça va tout seul. JTextArea editor = new JTextArea(); public UndoRedoText() { editor.getDocument().addUndoableEditListener(new ManageIt()); undoButton.addActionListener(new UndoIt()); redoButton.addActionListener(new RedoIt()); } class ManageIt implements UndoableEditListener { public void undoableEditHappened(UndoableEditEvent e) { manager.undoableEditHappened( e); updateButtons(); }

239 Master ISIDIS239 États  Dans les exemples précédents, on conservait explicitement l’état après modification. Un tel procédé n’est pas suffisant dans de nombreuses situations, comme dans un groupe de boutons radio.  Java propose une forme générale d’état appelé StateEdit. Tout objet dont la classe implémente l’interface StateEditable peut sauvegarder son état avant et après modification dans l’état, et ainsi le récupérer.  Mieux, la prise en compte de l’état de départ et de l’état d’arrivée peut être programmée, permettant ainsi de cumuler des modifications.

240 Master ISIDIS240 États : description  Un StateEdit est créé par  La classe de unObjet implémente l’interface StateEditable.  Un StateEdit contient en interne une table de hachage (en fait deux). Les méthodes  de StateEditable permettent de sauvegarder et de récupérer les données à conserver.  La sauvegarde débute à la création, et s’arrête par la méthode end() de StateEdit. StateEdit etat = new StateEdit(unObjet); public void storeState( Hashtable h); public void restoreState( Hashtable h);

241 Master ISIDIS241 États : structure de l’exemple class TogglePanel extends JPanel implements ActionListener, StateEditable { StateEdit etat; JButton undoButton, redoButton, chooseButton, endButton; JRadioButton gras, ital, soul; ButtonGroup polices; public TogglePanel() { // installer les composants; chooseButton.addActionListener(new ChooseIt()); endButton.addActionListener(new EndIt()); undoButton.addActionListener(new UndoIt()); redoButton.addActionListener(new RedoIt()); } public void storeState(Hashtable h) {...} public void restoreState(Hashtable h) {...} class ChooseIt implements ActionListener {...} class EndIt implements ActionListener {...} class UndoIt implements ActionListener {...} class RedoIt implements ActionListener {...} }

242 Master ISIDIS242 États : fin de l’exemple  Trois boutons radio sont donnés. A partir de Choose, on démarre l’enregistrement des modifications, jusqu’à l’activation du bouton Ok.  Un Undo restitue l’état initial, et un Redo revient à l’état final. class ChooseIt implements ActionListener { public void actionPerformed(ActionEvent ev) { etat = new StateEdit(TogglePanel.this); updateButtons(); } public void storeState(Hashtable h) { h. put(polices, polices.getSelection()); } public void restoreState(Hashtable h) { ButtonModel b = (ButtonModel) h.get(polices); b.setSelected(true); } class UndoIt implements ActionListener { public void actionPerformed(ActionEvent ev) { try { etat.undo(); } catch (CannotUndoException ex) {} updateB(); }

243 Master ISIDIS243 Le squelette d’un éditeur de texte  Objectifs Présenter des interactions d’un composant de texte avec son environnement  Ouverture et sauvegarde des fichiers  Couper-coller  Undo-Redo L’important est la cohérence de l’environnement  Entrées des menus activables seulement si cela a un sens  « Aide implicite » que cela apporte En revanche, on ignore le style du texte lui- même  Style des paragraphes  Polices de caractères

244 Master ISIDIS244 Cahier des charges  Éditeur SDI (single document interface) un seul document présent une seule fenêtre de manipulation du texte  Autres modèles une seule fenêtre, plusieurs documents plusieurs fenêtres, une par document  Commandes de manipulation de documents nouveau, ouvrir, sauver, sauver sous  Commandes de manipulation du texte copier-couper, coller, tout sélectionner annuler-rétablir  Présentation de ces commandes sous forme menu - toolbar - raccourcis clavier

245 Master ISIDIS245 Textes et documents  Classes de textes  Classes de documents | +-- javax.swing JComponent | +-- javax.swing.text.JTextComponent | +-- javax.swing.JTextArea | +-- javax.swing.JTextField | +-- javax.swing.JEditorPane | +-- javax.swing.JTextPane java. lang. Object | +-- javax.swing.text.AbstractDocument implements Document | +-- javax.swing.text.PlainDocument | extends | +-- javax.swing.text.DefaultStyledDocument implements StyledDocument | +-- javax.swing.text.html.HTMLDocument

246 Master ISIDIS246 Document / Vue  Un composant de texte présente une vue d’un document. TextArea et TextField associés au PlainDocument TextPane associé à StyledDocument  Correspondance JTextArea editor; Document document = editor.getDocument(); editor.setDocument(new PlainDocument());

247 Master ISIDIS247 Écouter le texte  Via le document, insertion, suppression, remplacement  Un DocumentListener implémente trois méthodes  appelées après modification d’un attribut, insertion, suppression. Document document = editor.getDocument(); document.addDocumentListener( un listener ); public void changedUpdate (DocumentEvent e); public void insertUpdate (DocumentEvent e); public void removeUpdate (DocumentEvent e);

248 Master ISIDIS248 Sélection  On peut pister les déplacements du point d’insertion ( caret ) par un CaretListener  Un CaretListener possède une méthode caretUpdate appelée chaque fois que le point d’insertion bouge  Un CaretEvent fournit deux méthodes getDot() qui donne le point actuel getMark() qui donne le point précédent  Un mouvement de souris, avec bouton enfoncé, ne provoque pas d’évènement, mais provoque un évènement quand on relâche le bouton Caret caret = editor.getCaret(); caret.addCaretListener( un CaretListener ); public void caretUpdate( CaretEvent e) { int now = e. getDot(); int before = e. getMark(); boolean nowSelected = now != before;... }

249 Master ISIDIS249 Manipulations de texte  Manipulations de texte prédéfinies (sont en fait des méthodes de JTextComponent ) :  les dernières transfèrent dans le presse- papier système.  Le DefaultEditorKit prédéfinit une trentaine d’actions sur les composants de textes. void editor.cut(); void editor.copy(); void editor.paste(); void editor.selectAll(); Clipboard clip = Toolkit. getDefaultToolkit(). getSystemClipboard();

250 Master ISIDIS250 Vue d’ensemble  Le texte une seule zone de texte ( JTextArea ) le document associé ne change pas, sauf pour la commande « nouveau ».  Les actions chaque action ( Action ) (nouveau,…, tout sélectionner) est implémentée dans une classe séparée  Les menus et la barre d’outils construits à partir des actions  Les gestionnaires de cohérence de la cohérence des menu : une EditMenuManager de la cohérence des undo-redo : un UndoHandler de sauvegarde de documents modifiés : une StatusBar.

251 Master ISIDIS251 Composants  Composants de la vue  Composants de la gestion JTextComponent editor; JMenuBar menubar; JToolBar toolbar; StatusBar status; File currentFile = null; JFileChooser selecteurFichier; UndoHandler undoHandler; EditMenuManager editMenuManager;

252 Master ISIDIS252 Les Actions  Une action… par action ! Action undoAction = new UndoAction(); Action redoAction = new RedoAction(); Action newAction = new NewAction(); Action openAction = new OpenAction(); Action saveAction = new SaveAction(); Action saveAsAction = new SaveAsAction(); Action exitAction = new ExitAction(); Action cutAction = new CutAction(); Action copyAction = new CopyAction(); Action pasteAction = new PasteAction(); Action selectAllAction = new SelectAllAction();

253 Master ISIDIS253 UndoAction  Premier exemple : undoAction class UndoAction extends AbstractAction { public UndoAction() { super("Undo", new ImageIcon("gifs/undo.gif")); setEnabled(false); } public void actionPerformed(ActionEvent e) { try { undoHandler.undo(); } catch (CannotUndoException ex) {} undoHandler.update(); }

254 Master ISIDIS254 UndoHandler  Il gère les undo, mais aussi l’état des boutons ! class UndoHandler extends UndoManager { public void undoableEditHappened(UndoableEditEvent e) { super.addEdit(e.getEdit()); update(); } public void update() { undoAction.setEnabled(canUndo()); redoAction.setEnabled(canRedo()); }

255 Master ISIDIS255 CutAction  Couper implique mettre dans la corbeille mettre à jour les boutons class CutAction extends AbstractAction { CutAction() { super("Cut", new ImageIcon("gifs/cut.gif")); } public void actionPerformed(ActionEvent e) { getEditor().cut(); // texte editMenuManager.doCut(); // boutons }

256 Master ISIDIS256 EditMenuManager  Il gère les transitions entre les 4 états du menu la mise-à-jour de la vue (menu et toolbar) par la fonction update() class EditMenuManager implements CaretListener { int state; static final int EMPTY = 0, CUTCOPY = 1, PASTE = 2, FULL = 3; void doInitial() {...} void doCopy() {...} void doCut() {...} void doPaste() {...} void doSelected() {...} void doDeselected() {...} }

257 Master ISIDIS257 EditMenuManager (suite)  Après une sélection :  Après un copy : void doSelected() { if (state == EMPTY) state = CUTCOPY; else if (state == PASTE) state = FULL; updateEnables(state); } void doCopy() { if (state == CUTCOPY) { state = FULL; updateEnables(state); }

258 Master ISIDIS258 EditMenuManager (suite)  C’est aussi un CaretListener, pour écouter les sélections public void caretUpdate(CaretEvent e) { int now = e.getDot(); int before = e.getMark(); boolean nowSelected = now != before; if (nowSelected) doSelected(); else doDeselected(); }

259 Master ISIDIS259 EditMenuManager (fin)  La mise- à- jour des boutons est paresseuse public void updateEnables(int state) { switch (state) { case EMPTY : cutAction.setEnabled(false); copyAction.setEnabled(false); pasteAction.setEnabled(false); break; case CUTCOPY: cutAction.setEnabled(true); copyAction.setEnabled(true); pasteAction.setEnabled(false); break; case PASTE:... case FULL:... }

260 Master ISIDIS260 Ouvrir un fichier  Il faut s’assurer que le fichier courant n’est pas modifié s’il est modifié, demander une éventuelle sauvegarde ouvrir un dialogue de choix de fichier lire ce fichier  Ces opérations sont assumées par la méthode actionPerformed() class OpenAction extends AbstractAction { OpenAction() { super("Ouvrir...", new ImageIcon("gifs/open. gif")); } public void actionPerformed(ActionEvent e) {...} }

261 Master ISIDIS261 Ouvrir un fichier (suite) public void actionPerformed(ActionEvent e) { if (!isConfirmed( "Voulez vous sauver le texte courant\ n"+ " avant d'ouvrir un autre fichier ?", "Sauver avant d'ouvrir ?")) return; int answer = selecteurFichier.showOpenDialog(frame); if (answer != JFileChooser.APPROVE_ OPTION) return; currentFile = selecteurFichier.getSelectedFile(); try { FileReader in = new FileReader(currentFile); getEditor().read(in, null); in.close(); } catch (IOException ex) { ex.printStackTrace(); } status.setSaved(); frame.setTitle(currentFile.getName()); }

262 Master ISIDIS262 Ouvrir un fichier (fin) boolean isConfirmed(String question, String titre) { if (! status.isModified()) return true; int reponse = JOptionPane.showConfirmDialog(null, question, titre, JOptionPane.YES_ NO_ CANCEL_ OPTION); switch(reponse) { case JOptionPane.YES_ OPTION:{ saveAction.actionPerformed(null); return !status.isModified(); } case JOptionPane.NO_ OPTION: return true; case JOptionPane.CANCEL_ OPTION: return false; } return false; }

263 Master ISIDIS263 État du document  Il n’existe pas de fonction qui indique une modification du document  StatusBar assume ce rôle… class StatusBar extends JPanel implements DocumentListener { boolean modStatus = false; // true = modified; public boolean isModified() { return modStatus; } public void changedUpdate(DocumentEvent ev) { setModified();} public void insertUpdate(DocumentEvent ev) { setModified();} public void removeUpdate(DocumentEvent ev) { setModified();} public void setSaved() { modStatus = false; getEditor().getDocument().addDocumentListener(this); saveAction.setEnabled(false); } public void setModified() { modStatus = true; getEditor().getDocument().removeDocumentListener(this); saveAction.setEnabled(true); }

264 Master ISIDIS264 Les menus  Dans le menu « Fichier », on ajoute des raccourcis protected JMenuBar createMenubar() { JMenuBar mb = new JMenuBar(); JMenu menu; JMenuItem item; menu = new JMenu("Fichier"); item = menu. add(newAction); item.setIcon(null); item.setMnemonic('N'); item = menu. add(openAction); item.setIcon(null); item.setMnemonic('O');... menu.addSeparator(); item = menu.add(exitAction); mb. add(menu);... return mb; }

265 Master ISIDIS265 La barre d’outils  On ajoute les tooltips, des espaces et de la glue private JToolBar createToolbar() { JButton b; JToolBar tb = new JToolBar(); b = tb.add(newAction); b.setText(null); b.setToolTipText("nouveau");... tb.add(Box.createHorizontalStrut(10)); b = tb.add(copyAction); b.setText(null); b.setToolTipText("copier");... tb.add(Box.createHorizontalGlue()); return tb; }


Télécharger ppt "Master ISIDIS1 Programmation Orientée Objet Avancée."

Présentations similaires


Annonces Google