java avancé dess isidis année 2003/2004 jean-christophe soulié [email protected]

125
JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié [email protected]

Upload: nadiya-chemin

Post on 03-Apr-2015

107 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

JAVA Avancé

DESS ISIDISAnnée 2003/2004

Jean-Christophe Soulié[email protected]

Page 2: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 2

Plan Gestion des évènements MVC Les observeurs Le réflexion Swing Le squelette d’un éditeur de texte

Page 3: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 3

Gestion des évènements Un composant enregistre des auditeurs

d’évènements (Listeners) Lorsqu’un évènement se produit dans un

composant, il est envoyé aux auditeurs enregistrés Chaque auditeur définit les actions à entreprendre,

dans des méthodes aux noms prédéfinis Exemple :

Un Bouton enregistre des ActionListener Lors d’un clic, un ActionEvent est envoyé aux ActionListener enregistrés

Ceci provoque l’exécution de la méthode actionPerformed de chaque ActionListener

Page 4: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 4

Exemple Une classe de boutons

class MonBouton extends Button {int incr;

MonBouton(String title, int incr) {super(title);this.incr = incr;

}

int getIncr() { return incr}}

Une classe d’étiquettes auditricesclass ListenerLabel extends Label implements ActionListener{

ListenerLabel() { super("0", Label.CENTER);}

public void actionPerformed(ActionEvent evt) {MonBouton b = (MonBouton) evt.getSource();int c = Integer.parseInt(getText());c += b.getIncr();setText(Integer.toString(c));

}}

Page 5: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 5

Exemple (fin) Le cadre

class PlusOuMoins extends Frame {PlusOuMoins() {

super("Plus ou moins");Bouton oui = new MonBouton("Plus", 1);Bouton non = new MonBouton("Moins", -1);Label diff = new ListenerLabel();oui.addActionListener((ActionListener) diff);non.addActionListener((ActionListener) diff);

}

public static void main(String args[]) {Frame r = new PlusOuMoins();r.pack();r.setVisible(true);r.addWindowListener(new WindowCloser());

}}

Et pour fermerclass WindowCloser extends WindowAdapter {

public void windowClosing(WindowEvent evt) {System.exit(0);

}}

Page 6: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 6

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 Origine : Smalltalk (Xerox Park,

Palo Alto – Milieu des années 70)

Page 7: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 7

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();

}}

Page 8: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 8

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;

}}

Page 9: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 9

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;

}}

Page 10: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 10

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;

}}

Page 11: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 11

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

Page 12: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 12

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

Page 13: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 13

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(); }

}

Page 14: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 14

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); }

}

Page 15: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 15

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)"); }

} }

Page 16: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 16

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) $

Page 17: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 17

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éé

Page 18: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 18

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.

Page 19: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 19

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.

Page 20: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 20

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.

Page 21: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 21

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.

Page 22: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 22

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);}

}}

Page 23: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 23

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

Page 24: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 24

Swing – l’arbre d’héritage

Page 25: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 25

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);...

}...

}

Page 26: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 26

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.

Page 27: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 27

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));

Page 28: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 28

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.)

Page 29: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 29

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.

Page 30: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 30

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);

Page 31: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 31

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)

Page 32: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 32

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();

Page 33: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 33

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

Page 34: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 34

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éesImageIcon tabimage; //l’icône dans les ongletsJTabbedPane tabbedPane; //le panneau à feuillesString[] boutonNames = {"TOP","BOTTOM","LEFT","RIGHT","add","remove"};JButton[] boutons = new JButton[boutonNames.length]; //les boutons de gestionJLabel statut; //le message d’étatAudioClip 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}

Page 35: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 35

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");

}

Page 36: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 36

JTabbedPane : exemple (4) Les actions des boutons La classe SwingConstants contient les constantes de

placementpublic 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();}

Page 37: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 37

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(); 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);

}

Page 38: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 38

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);

}

Page 39: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 39

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)

Page 40: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 40

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);

}}

Page 41: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 41

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

Page 42: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 42

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);

Page 43: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 43

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();

}}

Page 44: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 44

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() {...}}

Page 45: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 45

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);}

Page 46: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 46

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);}

Page 47: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 47

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 < 0)|| (nx > dim.width)) {

vx = - vx;nx = x +vx;

}if ((ny < 0)||( 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);

Page 48: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 48

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

Page 49: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 49

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 celluleinterface TreeModel {

...public Object getChild(Object parent, int index);public Object getRoot();public boolean isLeaf(Object node);...

}

Page 50: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 50

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 TreeModelclass DefaultTreeModel implements TreeModel

interface TreeNodeinterface MutableTreeNode extends TreeNodeclass DefaultMutableTreeNode implements MutableTreeNode

JTree()JTree(TreeNode racine)JTree(TreeNode racine, boolean enfantsPermis)JTree(TreeModel modele)JTree(TreeModel modele, boolean enfantsPermis)

Page 51: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 51

Jtree : exempleclass 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);

}...

}

Page 52: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 52

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.

Page 53: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 53

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"));

Page 54: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 54

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());}

}

Page 55: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 55

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() + " ");

}}

Page 56: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 56

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.

Page 57: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 57

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");

}...

}

Page 58: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 58

JTree : exemple(3)public DefaultMutableTreeNode addClass(Class c) {

if (c.isInterface() || c.isPrimitive()) return null; //pas les interfaces

findUserObject(c) //cherche c dans treeDefaultMutableTreeNode 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 visibleTreePath path = new TreePath(model.getPathToRoot(newNode));tree.makeVisible(path);return newNode;

}

Page 59: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 59

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;

}

Page 60: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 60

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); //essayonsaddClass(c);textField.setText("");

}catch (ClassNotFoundException e) {

Toolkit.getDefaultToolkit().beep(); //si la classe n’existe pas

}}

Page 61: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 61

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.

Page 62: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 62

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.

Page 63: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 63

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"};

Page 64: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 64

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)

Page 65: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 65

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));

}}

Page 66: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 66

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)

Page 67: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 67

JTable : détailsclass 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);

}}

Page 68: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 68

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)

Page 69: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 69

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

Page 70: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 70

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.

Page 71: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 71

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 = { ... };

}

Page 72: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 72

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;

}

Page 73: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 73

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);

}}

Page 74: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 74

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;}

}

Page 75: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 75

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èleclass 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);

}});

}}

Page 76: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 76

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)

Page 77: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 77

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.

Page 78: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 78

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

Page 79: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 79

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().

Page 80: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 80

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éé.

Page 81: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 81

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);

}}

Page 82: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 82

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();

}

Page 83: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 83

Les listenersclass 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());

}

Page 84: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 84

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") + "\"";

}...

Page 85: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 85

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.

Page 86: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 86

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

Page 87: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 87

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());...}

}

Page 88: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 88

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());

}...

}

Page 89: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 89

Les formes et le canvasclass 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);

}}

}

Page 90: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 90

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.

Page 91: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 91

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é";}

}

Page 92: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 92

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();

}

Page 93: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 93

É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);...

Page 94: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 94

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);

}}

}

Page 95: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 95

…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();

}

Page 96: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 96

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);}

}

Page 97: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 97

UndoableEditSupport (fin) Au lieu de lancer les événements,

on poste les Edit :

public void mousePressed(MouseEvent e) {UndoableEdit edit;edit = ...canvas.postEdit(edit);...

}

Page 98: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 98

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();

}}

Page 99: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 99

É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.

Page 100: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 100

É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);

Page 101: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 101

É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 {...}

}

Page 102: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 102

É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();

}}

Page 103: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 103

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

Page 104: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 104

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

Page 105: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 105

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

Page 106: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 106

Document / Vue Un composant de texte présente une vue d’un

document. TextArea et TextField associés au PlainDocument TextPane associé à StyledDocument

CorrespondanceJTextArea editor;Document document = editor.getDocument();editor.setDocument(new PlainDocument());

Page 107: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 107

É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);

Page 108: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 108

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;...

}

Page 109: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 109

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();

Page 110: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 110

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.

Page 111: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 111

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;

Page 112: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 112

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();

Page 113: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 113

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();

}}

Page 114: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 114

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());

}}

Page 115: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 115

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(); // texteeditMenuManager.doCut(); // boutons

}}

Page 116: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 116

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() {...}

}

Page 117: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 117

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);

}}

Page 118: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 118

EditMenuManager (suite) C’est aussi un CaretListener ,

pour écouter les sélectionspublic void caretUpdate(CaretEvent e) {

int now = e.getDot();int before = e.getMark();boolean nowSelected = now != before;if (nowSelected)

doSelected();else

doDeselected();}

Page 119: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 119

EditMenuManager (fin) La mise- à- jour des boutons est

paresseusepublic 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: ...

}}

Page 120: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 120

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) {...}}

Page 121: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 121

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());

}

Page 122: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 122

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;

}

Page 123: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 123

É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);

}}

Page 124: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 124

Les menus Dans le menu « Fichier », on ajoute des

raccourcisprotected 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;

}

Page 125: JAVA Avancé DESS ISIDIS Année 2003/2004 Jean-Christophe Soulié soulie@lil.univ-littoral.fr

DESS ISIDIS - 2003/2004 125

La barre d’outils On ajoute les tooltips, des espaces et de la

glueprivate 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;

}