Chapitre 5 : Les événements
q Gestion des événements
q Evénements de bas niveau: interfaces
écouteurs et classes Adapter
q Evénements sémantiques
q Architecture MVC : événements sur des
tables ou des listes
q Actions globales sur des menus et barre
d'outils
353
Événements
354
Programmation par événements
> Les programmes qui possèdent une IHM avec clavier,
écran graphique et souris suivent un modèle de
programmation appelé programmation par événements.
> Le programme attend que des événements se
produisent (par exemple, sur le clavier, la souris ou
l'écran), et, lorsque ces événements se produisent, il y
réagit en déclenchant des procédures appropriées dans
les objets qui ont déclaré être intéressés par ces
événements.
355
Programmation par événements
> Un programme Swing (ou une applet) possèdent une
interface graphique clavier/souris et sont donc de ce
type.
> Mécanisme : si on clique la souris, c’est le système qui
découvre l’événement en premier. Il détermine quelle
application contrôle la souris au moment où s’est produit
le clic, et il transmet les informations à cette application
(si elle a déclaré être intéressée par la souris bien sûr,
sinon, l’événement est ignoré).
356
Les événements en Java
> Supposons que l’on clique sur un bouton de la souris.
Cela génère un événement intercepté par le système et
redirigé vers l'application concernée, ici écrite en java.
> Java définit des événements de bas niveau fournissant
une interface au système de fenêtrage de la plateforme
concernée. Il définit aussi des événements plus
sémantiques, relatifs aux objets awt et swing. Un
événement détecté par le système sera traduit en un
événement java approprié.
> Un thread dédié gère les événements java.
357
Les événements en Java
> Le modèle de programmation de java définit les
événements comme ayant une source et une cible.
> Dans notre exemple, le bouton est la source de
l événement, i.e. l’objet où le clic s'est produit. Java
crée alors un objet Event qui contient les informations
associées à cet événement de clic.
> Le thread de gestion des événements appelle alors la
(ou les) procédure(s) associée(s) à l'événement. Ces
procédures sont définies par le programmeur dans les
objets cibles de l’événement.
358
Les événements en Java
> Les procédures déclenchées sont donc définies dans les
objets cibles - et elles ont cet événement en argument.
> si une application est intéressée par une gestion globale,
son cadre peut être l’unique objet cible de tous les
événements. Le cadre invoque alors enableEvents()
pour sélectionner les types d'événements qui l'intéresse,
et il implémente les procédures de gestion associées
pour chaque type d’événement sélectionné.
359
Gestion globale :
méthode enableEvents()
public class toto extends JFrame {
public toto() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
protected void processWindowEvent(WindowEvent e) {
if (e.getID() == WindowEvent.WINDOW_CLOSING){
dispose(); // libère les ressources
System.exit(0);
}
super.processWindowEvent( e ); // passe l ev à la fenêtre
}
}
} 360
Gestion locale :
les écouteurs
Mais un objet intéressé par un événement survenant sur
un objet source, peut aussi se déclarer écouteur
(listener) de cet événement sur l'objet. Un écouteur
est un objet qui capte des événements se produisant sur
un autre objet (ou d un groupe d objets, par ex. un
groupe d éléments de menu). C est une cible locale.
> un écouteur définit une méthode prenant en argument
un événement, et cette méthode sera déclenchée
chaque fois que l événement « écouté » se produira sur
l objet source.
361
Modèle par délégation
> Cette gestion des événements par des écouteurs
suit le modèle appelé
modèle par délégation
La gestion des événements est en effet ici
déléguée aux objets qui se sont déclarés
intéressés par certains événements (et ce sont
eux qui en implémentent les réactions).
362
Rappel : interfaces vs classes
> Les interfaces sont des classes qui déclarent
des méthodes destinées à être implémentées
par d’autres classes.
> Une interface est une classe abstraite qui
déclare des méthodes (implicitement public)
sans leur fournir de code, et d’éventuelles
constantes (membres déclarés alors final
static).
363
Rappel : interfaces vs classes
J Les interfaces permettent de compenser
partiellement l'absence d'héritage multiple dans
Java.
J Une classe peut en effet étendre une autre
classe et implémenter autant d'interfaces qu'elle
le souhaite. Elle héritera donc en partie de
l’interface, en tous cas du prototype et du nom
de certaines méthodes
364
Comment définir un écouteur?
> Tout objet peut devenir écouteur: il suffit que sa
classe implémente une interface écouteur.
> Il y a plusieurs interfaces écouteur (en anglais
listener) qui se distinguent par les types
d’événements qui se produisent.
Ex : dans le cas du clic d’un bouton, on a un
événement d’action de type ActionEvent qui
est généré, et on utilisera l’interface
ActionListener pour y définir la réaction.
365
Comment définir un écouteur?
> Le code qui sera invoqué par l’objet cible lors de la
survenu de l’événement (lequel se produit sur l’objet
source) est une méthode qui doit être définie dans
l’objet cible qui implémentera l'interface écouteur.
Exemple : dans le cas de l'interface ActionListener
c’est la méthode actionPerformed(ActionEvent
e) (littéralement action effectuée) qui sera déclenchée
quand l’événement d’action (ici de type ActionEvent)
se produira.
366
Relier la source à la cible
F Dans ce modèle, il ne suffit pas d implémenter
l’interface listener dans la cible pour
déclencher les procédures lors de ces événements.
> Il faut en plus relier la source de l'événement à la cible.
Cela se fait en ajoutant l'écouteur à l’objet source.
> Dans notre exemple, l'écouteur doit être enregistré sur le
bouton avec la méthode addActionListener. Cette
méthode d’ajout prend en argument un objet cible qui
implémentera l’interface listener.
367
368
Description des
événements Java
369
Evénements java
Les événements Java sont classés en deux
catégories :
1. Les événements de bas niveau (clavier, souris,
opérations sur les fenêtres)
2. Des événements sémantiques (mouvements
des scrollbars, clic sur un objet bouton). Il s agit
d’événements spécifiques, définis sur des
composants swing ou awt spécifiques.
370
Evénements java
La plupart des événements et des interfaces écouteurs
sont définis dans
java.awt.event
Des événements spécifiques aux composants Swing
sont définis dans
javax.swing.event
371
372
1. Evénements
de bas niveau
373
Problématique des Entrées
Il faut avoir le Focus Source
focus Expose
pour recevoir
le clavier
Cible
??? ??
?
ButtonPress
MouseEvent
KeyPress
KeyEvent ButtonRelease
KeyRelease
MotionNotify 374
événements de bas niveau
(définis dans java.awt.event)
> FocusEvent: activation ou désactivation du focus
du clavier sur un composant.
> MouseEvent: mouvements et clics de souris, et
entrée/sortie d'un composant.
> KeyEvent: événements clavier.
> WindowEvent: dés/activation, ouverture/fermeture
et dés/iconification de fenêtres.
> ComponentEvent : changement de taille, de
position, ou de visibilité d’un composant.
375
événements de bas niveau
La liste précédente n’est pas exhaustive. Il existe
d’autres événements de bas niveau, comme par
exemple
> PaintEvent: qui concerne la gestion du réaffichage
(à ne pas traiter avec des écouteurs -> on réécrira la
méthode paint ou la méthode paintComponent).
> ContainerEvent: événements associés à un
conteneur (ajouts, suppressions, etc.).
Mais vous n avez normalement pas besoin de gérer
ces événements car ils sont traités automatiquement.
376
Hiérarchie des événements
de bas niveau
AWTEvent
ComponentEvent
WindowEvent InputEvent FocusEvent
MouseEvent KeyEvent
377
AWTEvent
La classe AWTEvent dérive de la classe
java.util.EventObject
> EventObjet contient une méthode
getSource() qui renvoie l’objet source de
l’événement (c’est-à-dire l'objet où l'événement
s'est logiquement produit).
> EventObject implémente l’interface
Serializable, donc tous ces événements
sont sérialisables.
378
Constantes de AWTEvent
Ces constantes (public final) permettent d’identifier
des classes d’événements. En voici les principales:
MOUSE_EVENT_MASK MOUSE_MOTION_EVENT_MASK
KEY_EVENT_MASK FOCUS_EVENT_MASK
ITEM_EVENT_MASK TEXT_EVENT_MASK
> Type long 1 bit -> On peut lesADJUSTMENT_EVENT_MASK
WINDOW_EVENT_MASK combiner .
Mais il y en a d’autres (ex: COMPONENT_EVENT_MASK).
379
Gestion globale:
on utilise enableEvents()
public class toto extends JFrame {
public toto() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
protected void processWindowEvent(WindowEvent e) {
if (e.getID() == WindowEvent.WINDOW_CLOSING){
dispose(); // libère les ressources
System.exit(0);
}
super.processWindowEvent( e ): // passe l’événement
}
}
} 380
utiliser enableEvents()
Les ID (types d’événements particuliers)
correspondants dans WindowEvent sont:
WINDOW_OPENED, WINDOW_CLOSING,
WINDOW_CLOSED, WINDOW_ACTIVATED,
WINDOW_DESACTIVATED,
WINDOW_ICONIFIED, WINDOW_DEICONIFIED.
Pour les autres classes d’événements, il y a
d’autres ID (des types plus particuliers).
381
utiliser enableEvents()
1. Appeler EnableEvent() sur le composant avec des
masques de AWTEvent liés par un ou bit-à-bit.
2. Implémenter les méthodes correspondantes, par ex :
• processEvent( AWTEvent e )
• processComponentEvent( ComponentEvent e )
• processFocusEvent( FocusEvent e )
• processKeyEvent( KeyEvent e )
• processMouseEvent( MouseEvent e )
• processMouseMotionEvent( MouseEvent e )
F La méthode processWindowEvent n’est disponible
que pour Window et ses sous-classes.
382
2eme méthode :
utiliser des écouteurs délocalisés
Il y a des interfaces écouteurs de bas niveau
correspondants aux types des principaux événements.
Elles sont toutes des extensions de
java.util.EventListener. Par exemple:
> WindowListener // événements fenêtre
> MouseListener // clics + entrée/sortie fenêtre
> MouseMotionListener // mouvements souris
> KeyListener // touches clavier
> FocusListener // focus clavier
> ComponentListener // configuration
383
384
Ecouteurs sur
les fenêtres (WindowEvent)
385
WindowListener
Méthodes de l interface Description
windowOpened(WindowEvent e) Appelée la 1ere fois que la fenêtre s ouvre
windowClosing(WindowEvent e) Menu close du système
windowClosed(WindowEvent e) Appelée quand on a fermé la fenêtre
windowActivated(WindowEvent e) Quand la fenêtre est activée (ex:clic dessus)
windowDeactivated(WindowEvent e) Quand la fenêtre est désactivée
windowIconified(WindowEvent e) Quand la fenêtre est réduite à une icône
windowDeiconified(WindowEvent e) Quand on restore la fenêtre d une icône
386
WindowListener
> Il y a une méthode pour chaque type
d'événements déclaré comme constante dans
WindowEvent.
Ces constantes définissent le type précis de
l'événement c’est le type qui est retourné par
getID().
387
WindowListener
Méthodes de l interface ID du WindowEvent
windowOpened(WindowEvent e) WINDOW_OPENED
windowClosing(WindowEvent e) WINDOW_CLOSING
windowClosed(WindowEvent e) WINDOW_CLOSED
windowActivated(WindowEvent e) WINDOW_ACTIVATED
windowDeactivated(WindowEvent e) WINDOW_DEACTIVATED
windowIconified(WindowEvent e) WINDOW_ICONIFIED
windowDeiconified(WindowEvent e) WINDOW_DEICONIFIED
388
Écouteurs Souris
(MouseEvent)
389
MouseListener
Méthodes de l interface Description
mouseClicked(MouseEvent e) Enfoncer et relâcher: clic sur un composant
mousePressed(MouseEvent e) Enfoncer sur un composant
mouseReleased(MouseEvent e) Relâcher sur un composant
mouseEntered(MouseEvent e) Entrer dans la zone d un composant
mouseExited(MouseEvent e) Quitter la zone d'un composant
390
MouseMotionListener
Méthodes de l interface Description
mouseMoved(MouseEvent e) Mouvement de la souris
mouseDragged(MouseEvent e) Drag : mouvement + bouton enfoncé
391
MouseListener
Fonctionne comme WindowListener. Les méthodes
de MouseListener correspondent aux ID (constantes
public final) de l’événement MouseEvent:
> MOUSE_CLICKED, MOUSE_PRESSED,
MOUSE_RELEASED, MOUSE_MOVED,
MOUSE_DRAGGED, MOUSE_ENTERED,
MOUSE_EXITED.
> mouseClicked(MouseEvent e),
mousePressed(MouseEvent e),
mouseReleased(MouseEvent e), etc.
392
MouseInputListener
> Cette interface écouteur est dans
javax.swing.event.
> Elle implémente à la fois un MouseListener et
un MouseMotionListener.
F Mais attention! Il n existe pas de méthode
addMouseInputListener, et quand on l’utilise sur
une cible, il faudra enregistrer l’écouteur deux
fois sur la source : une fois avec
addMouseListener et une seconde fois avec
addMouseMotionListener.
393
394
Écouteurs Clavier,
Focus et Composant
(KeyEvent, FocusEvent et
ComponentEvent)
395
KeyListener
Méthodes de l interface Description
keyTyped(keyEvent e) Clé pressée et relâchée
keyPressed(keyEvent e) Clé pressée
keyReleased(keyEvent e) Clé relâchée
396
KeyListener
Méthodes de l interface ID de KeyEvent
keyTyped(keyEvent e) KEY_TYPED
keyPressed(keyEvent e) KEY_PRESSED
keyReleased(keyEvent e) KEY_RELEASED
397
FocusListener
Méthodes de l interface Description
focusGained(FocusEvent e) Quand un composant prend le focus clavier
focusLost(FocusEvent e) Quand il le perd
398
FocusListener
Méthodes de l interface ID de FocusEvent
focusGained(FocusEvent e) FOCUS_GAINED
focusLost(FocusEvent e) FOCUS_LOST
399
ComponentListener
Méthodes de l interface Description
componentHidden(ComponentEvent e) Le composant est rendu invisible
componentMoved(ComponentEvent e) La position du composant change
componentResized(ComponentEvent e) La taille du composant change
componentShown(ComponentEvent e) Le composant est rendu visible
400
ComponentListener
Méthodes de l interface ID de ComponentEvent
componentHidden(ComponentEvent e) COMPONENT_HIDDEN
componentMoved(ComponentEvent e) COMPONENT_MOVED
componentResized(ComponentEvent e) COMPONENT_RESIZED
componentShown(ComponentEvent e) COMPONENT_SHOWN
401
Ecouteurs d'événements
de bas niveau
public class Sketcher implements WindowListener {
private static SketcherFrame window; // fenêtre de l’application
private static Sketcher theApp; // l’objet application
public static void main (String[] args) {
theApp = new Sketcher();
theApp.init();
}
public void init() {
window = new SketcherFrame(«Dessin»);
Toolkit leKit = window.getToolkit();
Dimension wndSize = leKit.getScreenSize();
window.setBounds(wndSize.width/6, wndSize.height/6,
2*wndSize.width/3,2*wndSize.height/3);
window.addWindowListener(this);
window.setVisible(true);
}
402
Ecouteurs d’événements
de bas niveau
// Méthode pour l événement windowClosing
public void windowClosing(WindowEvent e ) {
window.dispose(); // libère les ressources de la fenêtre
System.exit(0); // termine l’application
}
// fonctions de l’interface listener que nous devons implémenter
// mais dont nous n avons pas besoin …
public void windowOpened(WindowEvent e ) {};
public void windowClosed(WindowEvent e ) {};
public void windowIconified(WindowEvent e ) {};
public void windowDeiconified(WindowEvent e ) {};
public void windowActivated(WindowEvent e ) {};
public void windowDeactivated(WindowEvent e ) {};
}
// dans SketcherFrame
// on supprime setDefaultCloseOperation(EXIT_ON_CLOSE);
403
Ecouteurs d’événements
de bas niveau
L Gros inconvénient de la gestion par écouteurs :
il faut implémenter toutes les méthodes de
l interface correspondante, y compris celles dont
on ne se sert pas.
J Cet inconvénient peut être supprimé grâce aux
classes Adapter.
404
Classes Adapter
Ce sont des classes qui implémentent une
interface (ici une interface écouteur) mais dont
les méthodes n’ont pas de code : elles ne font
rien.
> On peut alors étendre la classe Adapter choisie
en redéfinissant uniquement les méthodes que
l'on souhaite utiliser. (Les autres sont déjà
définies et vides).
405
Classes Adapter pour les écouteurs
de bas niveau
> Il y a une classe Adapter pour chacun des
écouteurs de bas niveau définis dans le package
java.awt.event, plus une définie dans le
package javax.swing.event étendant
l'interface MouseInputListener.
406
Classes Adapter
d'écouteurs de bas niveau
FocusAdapter
MouseAdapter
WindowAdapter
KeyAdapter
MouseMotionAdapter
MouseInputAdapter
407
1ère méthode: étendre directement
une classe Adapter
F Etendre une classe Adapter.
public class MaClass extends MouseAdapter {
...
unObject.addMouseListener(this);
...
public void mouseClicked(MouseEvent e) {
...
// l’implementation de la méthode
// associée à l’événement vient ici ...
}
} 408
2ème méthode: définir des classes
internes d écouteurs
F Définir une classe interne.
window.addWindowListener(new WindowHandler());
// classe interne WindowHandler
// pour les événements de fermeture
class WindowHandler extends WindowAdapter {
// Méthode pour WINDOW_CLOSING event par exemple
public void windowClosing( WindowEvent e ) {
window.dispose();
System.exit(0);
}
} 409
2ème méthode: exemple
// les import: java.applet.Applet, java.awt.*, java.awt.event.*
public class AdapterSpot extends Applet {
private Point clickPoint = null;
private static final int RADIUS = 7;
public void init() {
addMouseListener(new MyMouseAdapter());
}
public void paint(Graphics g) {
g.drawRect(0, 0, getSize().width - 1,
getSize().height - 1);
410
2ème méthode: exemple
if (clickPoint != null)
g.fillOval(clickPoint.x-RADIUS,
clickPoint.y-RADIUS,
RADIUS*2, RADIUS*2);
} // fin de paint
class MyMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent event) {
clickPoint = event.getPoint();
repaint();
}
}
} 411
412
2. Evénements
sémantiques
413
Événements sémantiques
Ce sont des événements spécifiques, liés à des
opérations spécifiques dans certains composants :
sélection d’éléments de menu, clic sur un bouton, etc.
> Il y a trois classes de base d'événements
sémantiques qui sont dérivés de AWTEvent.
> Il existe aussi des événements sémantiques
spécifiques à des composants Swing dérivés
également de cette classe.
414
Événements sémantiques
EventObject
AWTEvent
ActionEvent ItemEvent AdjustmentEvent
Ces trois événements sémantiques sont
définis dans java.awt.event.
415
ActionEvent
> il se produit quand on effectue une action sur un
composant réactif: clic sur un item de menu ou comme
on l’a vu clic sur un bouton.
> il est émis par les objets de type
– Boutons: JButton, JToggleButton,
JCheckBox
– Menus: JMenu, JMenuItem,
JCheckBoxMenuItem, JRadioBoxMenuItem..
– Texte: JTextField
416
ItemEvent
> il se produit quand un composant est sélectionné
ou désélectionné.
> il est émis par les objets de type
– Boutons: JButton, JToggleButton,
JCheckBox
– Menus: JMenu, JMenuItem,
JCheckBoxMenuItem,JRadioBoxMenuItem
– mais aussi JComboBox, Jlist.
417
AdjustmentEvent
> il se produit quand un élément ajustable, comme
une JScrollbar, est ajusté.
> il est émis par Scrollbar, JScrollbar.
418
Ecouteurs pour
événements sémantiques
Comme pour les événements de bas niveau,
c’est la façon la plus simple de gérer les
événements sémantiques
interface listener Méthode (unique)
ActionListener void actionPerformed(ActionEvent e)
ItemListener void itemStateChanged(ItemEvent e)
AdjustmentListener void adjustmentValueChanged(AdjustmentEvent e)
419
Exemple
Cette applet contrôle l'apparition d'une fenêtre
supplémentaire (un JFrame) qui apparaît lorsqu'on
enfonce le bouton "Start playing…" 420
Exemple
Dans le Jframe qui apparaît, on trouvera un label et une
checkbox qui permettra de cocher si le label est rendu
visible ou invisible.
On pourra aussi iconifier le JFrame ou le désiconifier.
Changer sa taille et sa position, etc.
Les différents événements captés écriront leur source et
leur type dans la zone de texte qui se trouve au centre du
cadre de l’applet. 421
Exemple
public class ComponentEventDemo extends JApplet
implements ComponentListener, ActionListener {
JTextArea display;
JFrame aFrame; // une fenêtre supplémentaire à afficher
public boolean showIt = false;
final static String SHOW = "show";
final static String CLEAR = "clear";
String newline = "\n";
public void init() {
display = new JTextArea();
display.setEditable(false);
JScrollPane scrollPane = new JScrollPane(display);
scrollPane.setPreferredSize(new Dimension(200, 75));
getContentPane().add(scrollPane, BorderLayout.CENTER); 422
JButton b1 = new JButton("Start playing...");
b1.setActionCommand(SHOW);
b1.addActionListener(this);
getContentPane().add(b1, BorderLayout.NORTH);
JButton b2 = new JButton("Clear");
b2.setActionCommand(CLEAR);
b2.addActionListener(this);
getContentPane().add(b2, BorderLayout.SOUTH);
aFrame = new JFrame("A Frame"); // une autre fenêtre
ComponentPanel p = new ComponentPanel(this); // + loin
aFrame.addComponentListener(this); // this écoute aFrame
p.addComponentListener(this); // et son panneau
aFrame.getContentPane().add(p, BorderLayout.CENTER);
aFrame.pack();
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
showIt = false;
}
} );
} // fin de init() 423
public void actionPerformed(ActionEvent e) { // les boutons
if (e.getActionCommand() == SHOW) {
showIt = true;
aFrame.setVisible(true);
} else { // si ce n’est pas SHOW, c’est donc CLEAR
display.setText(""); // efface le contenu central
}
}
public void stop() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
aFrame.setVisible(false);
}
});
}
public void start() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (showIt) {
aFrame.setVisible(true);
} 424
}
});
}
protected void displayMessage(String message) {
display.append(message + newline);
}
public void componentHidden(ComponentEvent e) {
displayMessage("componentHidden event from " +
e.getComponent().getClass().getName());
}
public void componentMoved(ComponentEvent e) {
displayMessage("componentMoved event from " +
e.getComponent().getClass().getName());
}
public void componentResized(ComponentEvent e) {
displayMessage("componentResized event from " +
e.getComponent().getClass().getName());
}
public void componentShown(ComponentEvent e) {
displayMessage("componentShown event from "+
e.getComponent().getClass().getName());
}
} // fin de ComponentEventDemo 425
class ComponentPanel extends JPanel implements ItemListener
{ // c’est le panneau de contenu de "aFrame"
JLabel label;
JCheckBox checkbox;
// le constructeur du panneau
ComponentPanel(ComponentEventDemo listener) {
super(new BorderLayout()); // sinon FlowLayout
label = new JLabel("This is a Label", JLabel.CENTER);
add(label, BorderLayout.CENTER);
checkbox = new JCheckBox("Label visible", true);
checkbox.addItemListener(this);
add(checkbox, BorderLayout.SOUTH);
// le Japplet est écouteur. Il traitera les événements
label.addComponentListener(listener);
checkbox.addComponentListener(listener);
} 426
// le traitement des événements pour la checkbox
public void itemStateChanged(ItemEvent e) { // if
(e.getStateChange() == ItemEvent.SELECTED) {
label.setVisible(true);
}
else {
label.setVisible(false);
}
}
}
427
Événements sémantiques
Il y en a beaucoup d’autres, ainsi par exemple:
> Les sous-classes de AbstractButton peuvent générer
des événements ChangeEvent quand on modifie l’état
d’un bouton.
> Les dérivés de JMenuItem génèrent des
MenuDragMouseEvent et des MenuKeyEvent.
> Une JList génère des SelectionEvent.
> Les modèles associés aux listes et aux tables génèrent
des ListDataEvent et des TableModelEvent (qui
sont envoyés aux vues quand des changements se
produisent sur le modèle).
428
429
Événements sur
des tables ou des listes
430
Architecture Modèle/Vue
> On peut faire partager le modèle de données d’une
JTable ou d’une JList à d’autres composants,
considérés alors comme d’autres « vues » des objets
JTable ou JList (en fait ce sont d’autres vues du
modèle sous-jacent à ces tables ou ces listes)
exemple: soit une liste de noms, affichés dans une JList.
La JList est une vue (interactive) de la liste de noms,
permettant de sélectionner des noms. Mais un morceau
de texte, indiquant en permanence le nombre d’éléments
de la liste, peut aussi être considéré comme une vue du
modèle.
431
Architecture Modèle/Vue
On a vu que la plupart des classes de JComponent
encapsulent un modèle, une vue et un contrôleur.
> Si le modèle est implémenté par une interface
<X>Model prédéfinie, il existe généralement une classe
Adapter nommée Default<X>Model. C’est le cas ici
avec <X>=List ou <X>=Table.
> L’interface <X>Model permet de gérer les données du
modèle et d’ajouter des vues (écouteurs de
changements sur le modèle).
> Si le modèle change, il génère un événement et notifie
les vues (via des méthodes en fire<...>).
432
Architecture Modèle/Vue
> Pour qu’un autre composant soit considéré comme une
vue, il doit :
– implémenter l’interface adéquate pour être écouteur de
l’événement de changement du modèle.
– se faire ajouter à la liste des écouteurs du modèle.
> On peut ainsi faire partager le modèle associé à une
JList (ou une JTable) à un autre composant (cf. exemple
précédent).
> On pourra également faire partager un même modèle de
données à une JTable et une JList.
433
434
La classe JList
> JList(Vector listData) // modèle fixe
> JList(Object[] listData) // modèle fixe
> JList(ListModel dm) // modèle modifiable
Exemple :
String listData[]= {«Younes»,…, «Sarah»};
DefaultListModel model = new DefaultListModel();
For (int i=0; i<listData.length; i++)
model.addElement(listData[i]);
JList dataList = new JList(model);
JScrollPane listeScroll = new
JScrollPane(dataList);
435
La classe JList
> setSelectionMode(int mode); les modes de
sélection sont dans ListSelectionModel et peuvent
valoir SINGLE_SELECTION,
SINGLE_INTERVAL_SELECTION,
MULTIPLE_INTERVAL_SELECTION.
> addListSelectionListener(…); un
ListSelectionListener écoute les
ListSelectionEvent e (chaque fois qu une
sélection change) et implémente une méthode :
ValueChanged.
> Boolean = e.getValueIsAdjusting()
436
Modèle d une JList
Pour le modèle, utiliser la classe DefaultListModel
ou la sous-classer. Ce modèle stocke les objets sous
forme de vecteur et fournit les méthodes :
> addElement(Object), boolean contains(Object),
Object get(index),
> boolean removeElement(Objet),
> Object remove(index), int size().
> addListDataListener(ListDataListener l),
removeListDataListener(ListDataListener l).
> fireContentsChanged, fireIntervalAdded,
fireIntervalRemoved (Object source, int index0,
int index1).
437
Vue d une JList
La vue d'une JList implémentera l’interface
ListDataListener. Elle définit trois méthodes :
> void contentsChanged(ListDataEvent e)
> void intervalAdded(ListDataEvent e)
> void intervalRemoved(ListDataEvent e)
L événement e de type ListDataEvent fournit :
> public int getType(): CONTENTS_CHANGED,
INTERVAL_ADDED, INTERVAL_REMOVED.
> public int getIndex0()
> public int getIndex1()
438
Plusieurs vues d une JList
> Créer un modèle instance de DefaultListModel et
le mémoriser dans un membre. Créer ensuite la liste
avec ce modèle.
> Pour chaque composant désirant être informé des
changements (= d’autres vues ou le contrôleur) :
– Mémoriser le modèle (=le stocker dans un membre).
– Implémenter ListDataListener. Il y a trois
méthodes: contentsChanged, intervalAdded
et intervalRemoved (ListDataEvent e).
– Enregistrer le composant dans le modèle avec
addListDataListener.
439
Modèle d une JTable
On dispose de 3 éléments pour créer un modèle:
l interface TableModel, la classe
AbstractTableModel qui implémente TableModel
et la classe DefaultTableModel.
DefaultTableModel est le plus simple à utiliser :
> DefaultTableModel(int row, int col)
> DefaultTableModel(Object[][] data,
Object[] columnNames)
> DefaultTableModel(Vector data, Vector
columnNames), etc.
440
La classe JTable
> JTable(Object[][] rowData, Object[]
columnNames)
On peut accéder au modèle sous-jacent avec
TableModel getModel()
ou appeler le constructeur initial avec un modèle:
String nomsCol[]={«Prenom», «Nom»};
String rows[][] = { {«Dinah»,«Cohen»}, … ,
{«Said», «Kharrazen»}};
DefaultTableModel model = new
DefaultTableModel(rows,
nomsCol);
JTable table = new JTable(model); 441
DefaultTableModel
> Vector getDataVector(), addRow(Vector data),
insertRow(int, Vector data), Object
getValueAt(int row, int col), setValueAt(Object,
int row, int col), removeRow(int), int
getRowCount(), int getColumnCount(), String
getColumnName(int), addColumn(Object columnName),
etc.
> addTableModelListener(TableModelListener l),
removeTableModelListener(l)
> fireTableChanged(TableModelEvent e),
fireTableRowsInserted(int firstRow, lastRow),
fireTableRowsUpdated(int firstRow, lastRow),
fireTableRowsDeleted(int firstRow, lastRow), etc.
442
Vue d’une JTable
Une autre vue implémentera l’interface
TableDataListener. Il n’y a qu’une méthode :
> void tableChanged(TableModelEvent e)
L événement associé TableModelEvent permet de
récupérer les informations :
> int getType(): INSERT, UPDATE, DELETE.
> int getColumn()
> int getFirstRow()
> int getLastRow()
443
Plusieurs vues d’une JTable
> Créer un modèle (par ex. une instance de
DefaultTableModel) et le mémoriser.
> Pour chaque composant désirant être informé des
changements (les vues, et/ou le contrôleur) :
– Mémoriser le modèle.
– Implémenter TableModelListener. Une méthode:
tableChanged (TableModelEvent e).
– Enregistrer le composant dans le modèle avec
addTableModelListener.
444