Cours 3

2014-2015
Programmation d’interfaces
avec
TM*
Swing de Java
*
de ORACLE (http://www.oracle.com/technetwork/java/index.html)
2I007 & LI357 / Université Paris VI
1
Choun Tong LIEU
2014-2015
Plan
I.
II.
Généralité
Conteneurs
1. Top-Level
2. Et quelques autres
III. Agencement (Layout)
IV. Quelques composantes simples
V. Listener (écouteur / réflexe)
2I007 & LI357 / Université Paris VI
2
Choun Tong LIEU
2014-2015
I. Généralité


Les composantes Swing font partie de JFC (Java TM Foundation Classes)
qui regroupe les éléments permettant la création d'interfaces graphiques.
Des simples boutons, menus, listes, curseurs, …
aux composantes plus sophistiquées
file chooser
split pane
table
2I007 & LI357 / Université Paris VI
tree
3
Choun Tong LIEU
2014-2015





Les noms des composantes AWT sont repris en Swing avec le préfixe "J".
Par exemple : Button (en AWT) et JButton (en Swing).
packages différents : java.awt et javax.swing
Contrairement au AWT (Abstract Window Toolkit), Swing est construit
avec des codes non natifs  look and feel indépendant de la couche
inférieure d'interface graphique (X Window System, Windows, Mac OS,
etc, …).
Plus de fonctionnalité dans une composante Swing que dans la même
composante AWT :
●
une image dans un bouton Swing,
●
une composante Swing n'est pas nécessairement rectangulaire,
●
modifier le dessin d'une bordure d'une composante Swing,
●
modifier le comportement et l'apparence d'une composante Swing,
●
…
La classe Component offre aux sous-classes
la possibilité de ne pas posséder sa propre fenêtre
pour les affichages. Chaque instance qui n'a pas de fenêtre propre
affichera alors dans la fenêtre de l'instance parent.
2I007 & LI357 / Université Paris VI
4
Choun Tong LIEU
2014-2015

Généralement, chaque composante AWT (Frame, Panel, Button, etc, …) a
sa propre fenêtre.

Le JFrame de Swing a une fenêtre, les composantes (JPanel, JButton,
etc, …) n'en ont pas. Chaque instance de ces dernières emprunte pour son
affichage la fenêtre de l'instance mère (si elle existe, sinon celle de grand-mère,
etc, …).
2I007 & LI357 / Université Paris VI
5
Choun Tong LIEU
2014-2015
import java.awt.*;
class Exemple_1_1 {
public static void main (String argvs[]) {
Frame f = new Frame("Exemple_1_1");
Panel p = new Panel();
Button b = new Button("Bouton 1_1");
arbre des
widgets
arbre des
fenêtres
f
fenêtre de f
p
fenêtre de p
f.setVisible(true);
b
f.add(p);
p.add(b);
...
xwininfo: Window id: 0x260003e "Exemple_1_1"
}
}
f
p
b
fenêtre de b
Root window id: 0x3f (the root window) (has no name)
Parent window id: 0x1001455 (has no name)
...
1 child:
0x2600041 (has no name): () 175x55+-4+-20 +0+0
1 child:
0x2600042 (has no name): () 167x31+4+20 +4+20
1 child:
0x2600047 (has no name): () 85x24+41+5 +45+25
2I007 & LI357 / Université Paris VI
6
Choun Tong LIEU
2014-2015
import javax.swing.*;
class Exemple_1_2 {
public static
JFrame f
JPanel p
JButton b
void main (String argvs[]) {
= new JFrame("Exemple_1_2");
= new JPanel();
= new JButton("Bouton 1_2");
f.setVisible(true);
f.getContentPane().add(p);
p.add(b);
...
arbre des
widgets
arbre des
fenêtres
f
fenêtre de f
p
b
}
}
xwininfo: Window id: 0x2e00041 "Exemple_1_2"
fenêtre de f
empruntée par p
et par b pour l'affichage
Root window id: 0x3f (the root window) (has no name)
Parent window id: 0x1001539 (has no name)
...
1 child:
0x2e00044 (has no name): () 175x54+-4+-20 +0+0
2I007 & LI357 / Université Paris VI
7
Choun Tong LIEU
2014-2015

Pas de fenêtre physique pour JPanel et JButton.
●
économie de ressources et de gestion pour le serveur; toute la gestion de
ces composantes se fait localement côté client.
●
plus de possibilités dans le graphisme pour dessiner ces composantes sans
être contraint à utiliser le cadre rectangulaire et opaque d'une fenêtre.
●
par exemple, pour avoir un bouton transparent :
import java.awt.*;
import javax.swing.*;
class Exemple_1_3 {
public static void main (String argvs[]) {
JFrame f = new JFrame("Exemple_1_3");
JButton a = new JButton("AAAAAAAAAA");
JButton b = new JButton("BBBBB");
JButton c = new JButton("CCCCC");
...
b.setOpaque(false);
...
}
}
2I007 & LI357 / Université Paris VI
8
Choun Tong LIEU
2014-2015
II. Conteneurs
Top-Level :

●
a une fenêtre; elle est en contact avec le gestionnaire de fenêtre (JFrame,
JDialog, etc, …) ou en contact avec la fenêtre du navigateur (JApplet, etc,
…).
JFrame
●
f = new JFrame("Exemple_2_1");
contient une seule composante fille instance de la classe JRootPane (voir
l'arbre ci-dessous).
JRootPane r = f.getRootPane();
●
on peut ajouter directement dans f des composantes par add(). Elles seront
ajoutées dans le conteneur contentPane de f. On récupère sa composante
contentPane par la méthode
Container c = f.getContentPane ();
2I007 & LI357 / Université Paris VI
9
Choun Tong LIEU
2014-2015
avant d'y ajouter une composante par
c.add(new JButton("Bouton 2_1"));
●
JRootPane
●
●
●
●
JRootPane r = f.getRootPane();
instance sans fenêtre, utilisée uniquement
pour être fille d'un conteneur Top-Level.
à droite, son arbre d'instance et ses filles.
contient un glassPane et un layeredPane.
2I007 & LI357 / Université Paris VI
10
absent à la création
d’une instance de JFrame
Choun Tong LIEU
2014-2015
●
instance glassPane
Component g = f.getGlassPane();
sans fenêtre et non affichée par défaut,
●
lorsqu'elle est affichée (visible), elle est transparente (glass) en se mettant
devant tous les autres composantes et intercepte tous les évènements souris,
●
utilisée pour dessiner par-dessus tous les autres composantes,
instance layeredPane
●
●
JLayeredPane l = f.getLayeredPane();
sans fenêtre et affichée par défaut,
●
contient un contentPane et une barre de menu, et les place (voir dessin
ci-dessus).
instance contentPane
●
●
Container c = f.getContentPane();
●
●
●
sans fenêtre et affichée par défaut,
sert à contenir tous les composantes ajoutées au conteneur Top-Level,
par défaut, l'outil de placement est un BorderLayout permettant de
placer les composantes au centre et aux 4 points cardinaux,
2I007 & LI357 / Université Paris VI
11
Choun Tong LIEU
2014-2015
●
Un exemple avec un JFrame :
import java.awt.*;
import javax.swing.*;
class Exemple_2_1 {
public static void main (String argvs[]) {
JFrame
f = new JFrame("Exemple_2_1");;
JRootPane
r = f.getRootPane();
Component
g = f.getGlassPane();
JLayeredPane l = f.getLayeredPane();
Container
c = f.getContentPane();
JMenuBar
m = f.getJMenuBar(); // == null
f.setVisible(true);
c.add(new JButton("Bouton 2_1"));
...
}
}
2I007 & LI357 / Université Paris VI
12
Choun Tong LIEU
2014-2015
●
Un exemple avec un JApplet contenu dans la fenêtre principale d'un
navigateur :
Exemple_2_2.html
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio">
<META HTTP-EQUIV="Content-Type" content="text/html">
<TITLE>Exemple 2_2 avec une Applet</TITLE>
</HEAD>
<BODY>
<!-- Insert HTML here -->
<applet
code=Exemple_2_2.class
name=Exemple_2_2
width=120
height=60 >
<param name=background value="008080">
<param name=foreground value="FFFFFF">
</applet>
</BODY>
</HTML>
2I007 & LI357 / Université Paris VI
13
Choun Tong LIEU
2014-2015
Exemple_2_2.java
import javax.swing.*;
public class Exemple_2_2 extends JApplet {
public void init () {
JPanel p = new JPanel();
JTree
t = new JTree();
setVisible(true);
getContentPane().add(p);
p.add(t);
}
}
2I007 & LI357 / Université Paris VI
14
Choun Tong LIEU
2014-2015
Quelques autres conteneurs :

●
JLayeredPane
●
par défaut, sans gestionnaire d’agencement (voir ci-dessous),
●
place ses filles dans des couches (layers) numérotées (petit numéro derrière
 grand numéro devant) : profondeur z.
●
par position dans les 3 dimensions : x, y et profondeur z.
●
ses numéros prédéfinis :
●
public static final Integer DEFAULT_LAYER; // 0
●
public static final Integer PALETTE_LAYER; // 100
●
public static final Integer MODAL_LAYER;
// 200
●
public static final Integer POPUP_LAYER;
// 300
●
public static final Integer DRAG_LAYER;
// 400
●
public static final Integer FRAME_CONTENT_LAYER;
●
valeur -30000,
●
couche utilisée pour mettre le contentPane et le menuBar de
JFrame (voir ci-dessus).
●
à l’intérieur d’une même couche, les filles sont placées par position (0 devant
 (nb_filles – 1) derrière).
2I007 & LI357 / Université Paris VI
15
Choun Tong LIEU
2014-2015
import java.awt.*;
import javax.swing.*;
class Exemple_2_3 {
public static void
JFrame
f
JLayeredPane l
Container
c
JMenuBar
m
JButton
b
main (String argvs[]) {
= new JFrame("Exemple_2_3");;
= f.getLayeredPane();
= f.getContentPane();
= new JMenuBar();
= new JButton("Bouton 2_3 Bis");
m.add(new JMenu("ABC"));
f.setJMenuBar(m);
f.setVisible(true);
c.add(new JButton("Bouton 2_3"));
b.setSize(b.getPreferredSize());
b.setLocation(50, 50);
l.add(b, new Integer(0));
...
}
}
2I007 & LI357 / Université Paris VI
16
Choun Tong LIEU
2014-2015
●
JPanel
●
sans fenêtre propre,
●
ajout des composantes filles par sa méthode add(),
●
contient par défaut un gestionnaire d’agencement (layout manager) de la
classe FlowLayout pour placer ses filles : placement en lignes comme
dans un éditeur de texte, (voir le chapitre III. Agencement ci-dessous)
2I007 & LI357 / Université Paris VI
17
Choun Tong LIEU
2014-2015
III. Agencement (Layout)

Pour un conteneur, on change son gestionnaire d’agencement (layout manager)
par sa méthode
void setLayout (LayoutManager mgr);
Par exemple :

Container
c;
SpringLayout l;
...
c.setLayout(l);
Quelques différentes classes de gestionnaire d’agencement (implémentant
l’interface LayoutManager) :
2I007 & LI357 / Université Paris VI
18
Choun Tong LIEU
2014-2015
●
FlowLayout
●
comme un éditeur de texte, il remplit horizontalement une ligne de
composantes de la gauche vers la droite ou de la droite vers la gauche ou au
centre et passe à la ligne suivante s’il n’y a pas assez de place,
●
Le choix peut être fait à sa création avec des constantes :
●
CENTER (valeur par défaut)
●
LEADING alignement par la gauche (resp. droite) si le conteneur adopte
pour son contenu l’orientation gauche-droite (resp. droite-gauche) (voir les
classes Component et ComponentOrientation avec ses constantes
LEFT_TO_RIGHT, RIGHT_TO_LEFT, etc, …)
●
LEFT
●
RIGHT
●
TRAILING, l’inverse de LEADING
ou plus tard par sa méthode
2I007 & LI357 / Université Paris VI
19
void setAlignment(int align);
Choun Tong LIEU
2014-2015
●
●
Avec des espacements horizontaux (hgap) et verticaux (vgap) possibles
entre les éléments
BoxLayout
●
place les filles de son conteneur en ligne (ne passe
pas à la ligne suivante) ou en colonne (ne passe
à la colonne suivante),
●
avec les choix :
●
LINE_AXIS en ligne (et reste en ligne) selon l’orientation gauche-droite,
droite-gauche, haut-bas ou bas-haut adoptée par le conteneur,
●
PAGE_AXIS même chose que précédemment, mais passe à la ligne ou
colonne suivante pour rester dans la page,
●
X_AXIS en ligne et de la gauche vers la droite,
●
Y_AXIS en colonne et du haut vers le bas.
2I007 & LI357 / Université Paris VI
20
Choun Tong LIEU
2014-2015
●
GridLayout
●
comme un tableau (lignes x colonnes),
●
le conteneur est divisé en rectangles de même taille,
●
●
selon l’orientation gauche-droite, droite-gauche,
haut-bas ou bas-haut adoptée par le conteneur,
BorderLayout
●
place au centre et aux 4 coins cardinaux,
●
on spécifie le coin au moment où on ajoute
une composante :
Panel p;
...
p.setLayout(new BorderLayout());
p.add(new Button("South"), BorderLayout.SOUTH);
2I007 & LI357 / Université Paris VI
21
Choun Tong LIEU
2014-2015
●
CardLayout
●
Comme un jeu de cartes, une seule composante visible à la fois,
●
GridBagLayout
●
Toutes les cellules de la même colonne ont la même largeur.
●
Toutes les cellules de la même ligne ont la même hauteur.
●
On y place une composante avec une contrainte de la classe
GridBagConstraints.
●
Quelques membres de GridBagConstraints :
●
gridx et gridy : indiquent les coordonnées de la cellule en
commençant par 0,
●
gridwidth et gridheight : indiquent combien de cellules la
composante occupe,
●
weightx et weighty : indiquent la taille en proportion que la cellule
va prendre par rapport à toutes les composantes de la même ligne (de la
même colonne).
Il y a respect d’une taille minimale : par exemple, pour un label,
tout le texte devrait être visible si possible.
La valeur 0 indique que la cellule doit suivre les autres.
2I007 & LI357 / Université Paris VI
22
Choun Tong LIEU
2014-2015
●
●
fill peut prendre comme valeur
●
NONE : indique que la composante n’est pas obligée de s’agrandir pour
remplir toute la surface de la cellule,
●
HORIZONTAL : la composante occupe toute la largeur de la cellule,
●
VERTICAL : la composante occupe toute la hauteur de la cellule,
●
BOTH : la composante occupe toute la surface de la cellule.
anchor : dans le cas où la composante est plus petite que la cellule, elle
peut prendre comme valeur
●
CENTER : la composante reste au milieu (par défaut),
●
NORTH : au nord,
●
SOUTHWEST
●
...
2I007 & LI357 / Université Paris VI
23
Choun Tong LIEU
2014-2015
Panel
p;
GridBagLayout
gridbag;
GridBagConstraints c;
Button
button;
...
p.setLayout(gridbag);
...
c.fill
= GridBagConstraints.BOTH;
c.weightx = 1.0;
...
button = new Button("Button1");
gridbag.setConstraints(button, c);
p.add(button);
button = new Button("Button2");
gridbag.setConstraints(button, c);
p.add(button);
...
2I007 & LI357 / Université Paris VI
24
Choun Tong LIEU
2014-2015
●
SpringLayout
●
contrairement aux autres classes de layout qui viennent de AWT,
SpringLayout vient du Swing.
●
ça commence avec l’arithmétique sur les Spring :
●
une instance de Spring comporte 3 valeurs : minimum, préférée et
maximum,
●
si on le note par un triplet [a,b,c] avec a  b c, alors on peut
définir l’arithmétique suivante :
[a1, b1, c1] + [a2, b2, c2]
-[a, b, c]
max([a1, b1, c1], [a2, b2, c2])
[a1, b1, c1] - [a2, b2, c2]
min([a1, b1, c1], [a2, b2, c2])
●
=
=
=
=
=
[a1 + a2, b1 + b2, c1 + c2]
[-c, -b, -a]
[max(a1, a2), max(b1, b2), max(c1, c2)]
[a1, b1, c1] + (-[a2, b2, c2])
-max(-[a1, b1, c1], -[a2, b2, c2])
et les méthodes de la classe Spring pour ces opérations :
2I007 & LI357 / Université Paris VI
25
Choun Tong LIEU
2014-2015
// Pour définir une constante Spring avec ces trois valeurs
static Spring constant (int min, int pref, int max);
// Même chose avec min = pref = max
static Spring constant (int pref);
static Spring minus (Spring s);
static Spring max (Spring s1, Spring s2);
static Spring sum (Spring s1, Spring s2);
●
●
●
●
permet, entre autre, aux composantes sœurs de s'attacher bord contre bord
entre elles ou au conteneur mère avec des contraintes,
●
EAST, WEST, NORTH et SOUTH.
peut donc forcer une composante à changer de taille,
permet aussi les composantes de se placer par position (avec des "Spring"
contantes, voir ci-dessous),
peut remplacer la plus part des "layout" ci-dessus.
2I007 & LI357 / Université Paris VI
26
Choun Tong LIEU
2014-2015
●
quelques méthodes :
// permet de récupérer le Spring qui contrôle le bord edgeName de c par rapport
// au bord haut ou gauche de sa mère
Spring getConstraint (String edgeName, Component c);
// permet de récupérer l'instance contenant les contraintes affectée à c
SpringLayout.Constraints getConstraints (Component c);
// permet de lier le bord e1 de c1 au bord e2 de c2 avec un espace
// constant pad
void putConstraint (String e1,
Component c1, int pad,
String e2, Component c2);
// même chose, mais avec un Spring
void putConstraint (String e1, Component c1, Spring s,
String e2, Component c2);
2I007 & LI357 / Université Paris VI
27
Choun Tong LIEU
2014-2015
●
SpringLayout.Constraints
●
classe de constrainte utilisée par SpringLayout et interne à
SpringLayout,
●
comme un rectangle avec ses propriétés x, y, largeur et hauteur,
●
à la place des entiers, ces propriétés ont comme valeur des Spring,
●
ses quelques constructeurs et méthodes :
// Constructeur créant un objet vide de contrainte avec positionnement à (0, 0)
SpringLayout.Constraints ();
// Constructeur créant des contraintes en x et y et 0 pour la largeur et hauteur
SpringLayout.Constraints (Spring x, Spring y);
// Constructeur créant des contraintes en x, y, largeur et hauteur
SpringLayout.Constraints (Spring x, Spring y,
Spring width, Spring height);
2I007 & LI357 / Université Paris VI
28
Choun Tong LIEU
2014-2015
// mettre une contrainte en x
void setX (Spring x);
// mettre une contrainte sur la hauteur
void setHeight (Spring x);
// mettre une contrainte sur un des bords de la composante avec edgeName
pris
// parmi les SpringLayout.NORTH, SpringLayout.SOUTH,
// SpringLayout.EAST et SpringLayout.WEST
void setConstraint (String edgeName, Spring s);
●
Un exemple permettant de placer le Bouton 1 en haut à gauche de son
conteneur, le Bouton 3 en bas à droite et le Bouton 2 en diagonale
entre les deux avec la particularité suivante lors du changement de taille
du conteneur :
●
●
●
Bouton 1 reste en haut à gauche,
Bouton 3 reste en bas à droite,
Bouton 2 change de taille pour que ses bords haut et gauche (resp. bas
et droit) restent collés à Bouton 1 (resp. Bouton 3).
2I007 & LI357 / Université Paris VI
29
Choun Tong LIEU
2014-2015
import java.awt.*;
import javax.swing.*;
class Exemple_3_1 {
public static void
main (String argvs[]) {
JFrame
f = new JFrame("Exemple_3_1");;
Container
c = f.getContentPane();
SpringLayout l = new SpringLayout();
JButton b1 = new JButton("Bouton 1");
JButton b2 = new JButton("Bouton 2");
JButton b3 = new JButton("Bouton 3");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
c.setLayout(l);
c.add(b1); c.add(b2); c.add(b3);
b2.setBackground(Color.RED);
l.getConstraints(b1).setX(Spring.constant(0));
l.getConstraints(b1).setY(Spring.constant(0));
2I007 & LI357 / Université Paris VI
30
Choun Tong LIEU
2014-2015
l.putConstraint(SpringLayout.SOUTH,
b3, 0, SpringLayout.SOUTH, c);
l.putConstraint(SpringLayout.EAST,
b3, 0, SpringLayout.EAST, c);
l.getConstraints(b2).setX(l.getConstraint(SpringLayout.EAST,
b1));
l.getConstraints(b2).setY(l.getConstraint(SpringLayout.SOUTH,
b1));
l.getConstraints(b2).setWidth(
Spring.sum(l.getConstraints(b3).getX(),
Spring.minus(l.getConstraints(b2).getX())));
l.getConstraints(b2).setHeight(
Spring.sum(l.getConstraints(b3).getY(),
Spring.minus(l.getConstraints(b2).getY())));
f.pack();
f.setVisible(true);
...
}
}
2I007 & LI357 / Université Paris VI
31
Choun Tong LIEU
2014-2015
IV. Quelques composantes simples

JButton
●
On peut utiliser une image à la place d’un texte.
import java.awt.*;
import javax.swing.*;
class Exemple_4_1 {
public static void main (String argvs[]) {
JFrame f;
JButton b;
f = new JFrame("Exemple_4_1");
f.setVisible(true);
b = new JButton(new ImageIcon("image_4_1.jpg"));
f.getContentPane().add(b);
...
}
}
2I007 & LI357 / Université Paris VI
32
Choun Tong LIEU
2014-2015
●
Avec un texte en plus :
b = new Jbutton("Exemple_4_1",
new ImageIcon("image_4_1.jpg"));

JSplitPane
●
permet de partager son espace d’affichage en 2 (vertical ou horizontal)
pour afficher 2 composantes,
●
peut avoir une barre de séparation ajustable.
2I007 & LI357 / Université Paris VI
33
Choun Tong LIEU
2014-2015
import java.awt.*;
import javax.swing.*;
class Exemple_4_2 {
public static void main (String argvs[]) {
JFrame f;
JSplitPane s;
f = new JFrame("Exemple_4_2");
f.setVisible(true);
s = new JSplitPane();
s.setLeftComponent(new JLabel(new ImageIcon("image_4_2.jpg")));
s.setRightComponent(new JLabel(new ImageIcon("image_4_3.jpg")));
s.setOneTouchExpandable(true);
f.getContentPane().add(s);
...
}
}
2I007 & LI357 / Université Paris VI
34
Choun Tong LIEU
2014-2015
V. Listener (écouteur / réflexe)

Réflexes de haut niveau en réaction à une succession d'événements de bas
niveau, par exemple pour un curseur (JSlider) :
ButtonPress + MotionNotify + ButtonRelease →
ChangeListener (méthode stateChanged() )

Les Swing héritent de java.awt.Component → Comportements de
base propres à un composant (Component) :
●
ComponentListener : pour réagir aux changements de taille,
position et visibilité.
●
FocusListener : pour réagir aux changements de focus de
l'entrée clavier.
●
HierarchyBoundsListener : pour réagir quand un ancêtre
change de taille ou de position.
●
HierarchyListener : pour réagir aux changements d'ancêtres.
●
InputMethodListener : pour réagir aux entrées texte, à ne pas
confondre avec les touches clavier du KeyListener ci-dessous.
2I007 & LI357 / Université Paris VI
35
Choun Tong LIEU
2014-2015
●
●
●
●
KeyListener : pour réagir aux touches clavier.
MouseListener : pour réagir aux boutons, aux entrées/sorties de
la souris.
MouseMotionListener : pour réagir aux déplacements de la
souris.
MouseWheelListener : pour réagir aux mouvements de la
roulette de la souris.
2I007 & LI357 / Université Paris VI
36
Choun Tong LIEU
2014-2015

Et chaque composant Swing possède ses propres réflexes :
2I007 & LI357 / Université Paris VI
37
Choun Tong LIEU
2014-2015
2I007 & LI357 / Université Paris VI
38
Choun Tong LIEU
2014-2015

Quelques composants :
• Pour chaque composant, il y a plusieurs types d'écouteurs/réflexes communs et
spécifiques.
• Pour tout composant, on peut y ajouter une ou plusieurs écouteurs/réflexes.
• JButton : (composant simple)
- hérite de javax.swing.AbstractButton (classe abstraite)
• public void addActionListener(ActionListener l)
• public void removeActionListener(ActionListener l)
• public ActionListener[] getActionListeners()
- avec l'écouteur/réflexe principal ActionListener (interface)
• la seule méthode void actionPerformed(ActionEvent e)
- rien n'empêche de réagir aux événements de bas niveau avec
l'écouteur/réflexe MouseListener (interface)
2I007 & LI357 / Université Paris VI
39
Choun Tong LIEU
2014-2015
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Exemple_5_1 {
public static void main
JFrame
f
JPanel
p
JButton
b
MonActionListener a
MonMouseListener m
(String argvs[]) {
= new JFrame("Exemple_5_1");
= new JPanel();;
= new JButton("Bouton 5_1");
= new MonActionListener();
= new MonMouseListener();
f.setVisible(true);
f.getContentPane().add(p);
p.add(b);
b.addActionListener(a);
b.addMouseListener(m);
}
}
2I007 & LI357 / Université Paris VI
40
Choun Tong LIEU
2014-2015
class MonActionListener implements ActionListener {
public void actionPerformed (ActionEvent e) {
System.out.println("Press + Release");
}
}
class MonMouseListener extends MouseAdapter {
public void mousePressed (MouseEvent e) {
System.out.println("Press");
}
public void mouseReleased (MouseEvent e) {
System.out.println("Release");
}
public void mouseEntered (MouseEvent e) {
System.out.println("Enter");
}
public void mouseExited (MouseEvent e) {
System.out.println("Exit");
}
}
2I007 & LI357 / Université Paris VI
41
Choun Tong LIEU
2014-2015
• JFileChooser : (composant composé un peu plus complexe)
- avec l'écouteur/réflexe principal ActionListener (interface)
• la seule méthode void actionPerformed(ActionEvent e)
- qui ne sera pas appelée systématiquement à chaque fois que l'on clique sur
les boutons affichés. C'est selon le contexte.
- Des comportements par défaut sans appeler cette méthode : en cliquant sur
un répertoire, etc, ...
- Par exemple, en cliquant sur le bouton « Ouvrir », la méthode n'est
appelée que si le champs « Nom de fichier : » est rempli et on trouve
dans l'événement « e » les informations « APPROVE_OPTION » et le nom
absolu du fichier sélectionné. Par contre, la méthode est appelée à chaque
fois que l'on clique dans le bouton « Annuler ».
2I007 & LI357 / Université Paris VI
42
Choun Tong LIEU
2014-2015
2I007 & LI357 / Université Paris VI
43
Choun Tong LIEU
2014-2015
• JTree : (composant complexe et sophistiqué)
- des écouteurs/réflexes complexes :
• public void addTreeSelectionListener (
TreeSelectionListener tsl)
appelé si un nœud est sélectionné ou dé-sélectionné.
• public void addTreeExpansionListener(
TreeExpansionListener tel)
appelé si l'arbre est changé.
• public void addTreeWillExpandListener(
TreeWillExpandListener tel)
appelé juste avant le changement.
2I007 & LI357 / Université Paris VI
44
Choun Tong LIEU
2014-2015

Réagir aux changements des propriétés :
• Pour chaque composant (instance), il existe des propriétés portant chacun un
nom distinct (par exemple « font », « background », « foreground »,
etc, ...).
• Toute modification de valeur de ces propriétés provoque l'exécution des réflexes
associées.
• Pour associer ces écouteurs/réflexes à toutes les propriétés (prédéfinies ou
définies par l'utilisateur)
public void addPropertyChangeListener(
PropertyChangeListener listener)
• Ou à une propriété nommée (prédéfinie ou définie par l'utilisateur)
public void addPropertyChangeListener(
String propertyName,
PropertyChangeListener listener)
2I007 & LI357 / Université Paris VI
45
Choun Tong LIEU
2014-2015
import
import
import
import
java.awt.*;
java.awt.event.*;
javax.swing.*;
java.beans.*;
class Exemple_5_3 {
public static void main (String argvs[]) {
JFrame
f = new JFrame("Exemple_5_3");
JPanel
p = new JPanel();;
JButton
b = new JButton("Bouton 5_3");
MonActionListener a = new MonActionListener();
MonPropertyChangeListener prcl = new MonPropertyChangeListener();
f.setVisible(true);
f.getContentPane().add(p);
p.add(b);
b.addActionListener(a);
b.addPropertyChangeListener(prcl);
}
}
2I007 & LI357 / Université Paris VI
46
Choun Tong LIEU
2014-2015
class MonActionListener implements ActionListener {
public void actionPerformed (ActionEvent e) {
((JButton)(e.getSource())).setBackground(Color.red);
}
}
class MonPropertyChangeListener implements PropertyChangeListener {
public void propertyChange (PropertyChangeEvent evt) {
System.out.println(evt);
}
}
2I007 & LI357 / Université Paris VI
47
Choun Tong LIEU
2014-2015
• Il est possible de provoquer ces exécutions par la méthode de l'objet
public void firePropertyChange(
String propertyName, ...)
• L'utilisateur peut définir de nouvelles propriétés liées à un composant (instance)
public final void putClientProperty(
Object key, Object value)
2I007 & LI357 / Université Paris VI
48
Choun Tong LIEU
2014-2015
import
import
import
import
java.awt.*;
java.awt.event.*;
javax.swing.*;
java.beans.*;
class Exemple_5_4 {
public static void main (String argvs[]) {
JFrame
f = new JFrame("Exemple_5_4");
JPanel
p = new JPanel();;
JButton
b = new JButton("Bouton 5_4");
MonActionListener a = new MonActionListener();
MonPropertyChangeListener prcl = new MonPropertyChangeListener();
f.setVisible(true);
f.getContentPane().add(p);
p.add(b);
b.addActionListener(a);
b.putClientProperty("koukou", "valeur de koukou");
b.addPropertyChangeListener("koukou", prcl);
}
}
2I007 & LI357 / Université Paris VI
49
Choun Tong LIEU
2014-2015
class MonActionListener implements ActionListener {
public void actionPerformed (ActionEvent e) {
((JButton)(e.getSource())).
firePropertyChange("koukou", 0, 1);
}
}
class MonPropertyChangeListener implements PropertyChangeListener {
public void propertyChange (PropertyChangeEvent evt) {
System.out.println(evt);
}
}
2I007 & LI357 / Université Paris VI
50
Choun Tong LIEU
2014-2015
• Pour que les événements (asynchrones) soient (mieux) traités, il faut éviter de
laisser exécuter ces composants (le principal) dans un thread normal (qui
fonctionne mieux avec synchronisation). Il vaut mieux le confier à l'EDT (Event
Dispatch Thread) :
2I007 & LI357 / Université Paris VI
51
Choun Tong LIEU
2014-2015
class Exemple_5_5 {
public static void main (String argvs[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Exemple_5_5");
JPanel p = new JPanel();;
JButton b = new JButton("Bouton 5_5");
MonActionListener a = new MonActionListener();
f.setVisible(true);
f.getContentPane().add(p);
p.add(b);
b.addActionListener(a);
}
});
}
}
2I007 & LI357 / Université Paris VI
52
Choun Tong LIEU
2014-2015



Les Swing héritent de java.awt.Component.
Et dans Component,
• à chaque événement reçu, la méthode
protected void processEvent(AWTEvent evenement)
est automatiquement appelée,
• pour choisir les événements à traiter :
protected final void
enableEvents(long masques_evenements)
• en général, on n'a pas à appeler enableEvents() et à choisir les
masques d'événements, car à chaque fois que l'on ajoute un listener, le
ou les masques d'événements correspondants sont automatiquement
ajoutés,
• elle est utile pour les classes héritées pour choisir des événements
particuliers.
Selon les événements (donc leur listener correspondant) à traiter et par
défaut, processEvent() appelle automatiquement la méthode
process???Event() appropriée :
2I007 & LI357 / Université Paris VI
53
Choun Tong LIEU
2014-2015
• protected void processComponentEvent(ComponentEvent e)
•
•
•
•
•
•
•
•
protected
protected
protected
protected
protected
protected
protected
protected
void
void
void
void
void
void
void
void
processFocusEvent(FocusEvent e)
processKeyEvent(KeyEvent e)
processMouseEvent(MouseEvent e)
processMouseMotionEvent(MouseEvent e)
processMouseWheelEvent(MouseWheelEvent e)
processInputMethodEvent(InputMethodEvent e)
processHierarchyEvent(HierarchyEvent e)
processHierarchyBoundsEvent(HierarchyEvent e)
Pour cela, on ajoute le ou les listeners correspondants :
• public void add???Listener(???Listener l)
On peut aussi le ou les retirer :
• public void remove???Listener(???Listener l)
2I007 & LI357 / Université Paris VI
54
Choun Tong LIEU
2014-2015
import
import
import
import
java.lang.*;
javax.swing.*;
java.awt.AWTEvent;
java.awt.event.*;
class Exemple_5_6
{
public static void main (String argvs[]) {
JFrame
f = new JFrame("Exemple_5_6");
MonBouton b = new MonBouton("Mon Bouton");
b.addActionListener(new MonAction());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(b);
f.pack();
f.setVisible(true);
}
}
2I007 & LI357 / Université Paris VI
55
Choun Tong LIEU
2014-2015
class MonBouton extends JButton
{
MonBouton (String s) { super(s); }
protected void processEvent (AWTEvent e) {
super.processEvent(e);
System.out.println("Evenement recu : " + e.getID());
}
}
class MonAction implements ActionListener
{
public void actionPerformed (ActionEvent e) {
System.out.println("Bouton clic.");
}
}
2I007 & LI357 / Université Paris VI
56
Choun Tong LIEU
2014-2015
• Pour un bouton, on ajoute un actionListener qui réagit au click de la souris, mais
aussi aux touches choisies pour ce bouton.
• On ajoute pour cela ce listener par la méthode
public void addActionListener(ActionListener l)
• Si on enlève l'instruction super.processEvent(e); , non seulement la
méthode actionPerformed(ActionEvent e) n'est pas appelée, mais en
plus l'aspect graphique du bouton enfoncé n'est pas honoré. Rien ne fonctionne.
2I007 & LI357 / Université Paris VI
57
Choun Tong LIEU
2014-2015
• Un Listener est une interface :
⁃ Interface EventListener : racine de tout Listener, sans aucune méthode,
c'est juste un tag (marquage).
⁃ Interface ActionListener : la seule méthode
void actionPerformed(ActionEvent e)
⁃ Interface ChangeListener : la seule méthode
public void stateChanged (ChangeEvent e)
⁃ ...
⁃ Interface WindowListener : avec plusieurs méthodes
➢
void windowActivated(WindowEvent e)
➢
...
➢
void windowOpened(WindowEvent e)

En général, pour un Listener avec une ou plusieurs méthodes, il y a un Adapter
correspondant (classe implémentant ce Listener) où toutes ces méthodes sont
définies avec un comportement par défaut. Cela permet au programmeur de créer
une classe héritée de ce Adapter en réécrivant une ou plusieurs de ces méthodes
pour des besoins particuliers. Par exemple :
➢
Class WindowAdapter
2I007 & LI357 / Université Paris VI
58
Choun Tong LIEU
2014-2015
...
➢
Class ContainerAdapter
• Attention : on peut trouver le même Listener utilisé dans différentes composantes
avec bien sûr un comportement différent.
• Par exemple :
⁃ public void addActionListener(ActionListener l)
• JButton, JCheckBox, JComboBox, JfileChooser, etc, ...
⁃ public void addChangeListener(ChangeListener l)
•JButton, JSlider, JSpinner, etc, ...
• Interaction des composantes « top-level » avec le gestionnaire de fenêtre. Par
exemple, avec un JFrame :
JFrame
f = new JFrame("Exemple_5_6");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
• On aura le même effet en utilisant la méthode de JFrame
public void addWindowListener(WindowListener l);
• Et on redéfinit pour WindowListener la ou les méthodes avec
System.exit(0)
➢
void windowClosing(WindowEvent e)
➢
void windowClosed(WindowEvent e)
➢
2I007 & LI357 / Université Paris VI
59
Choun Tong LIEU