Mme SADEG
s_sadeg@[Link]
Ecole nationale Supérieure d’Informatique (ESI)
2010/2011
Contenu du cours
Introduction à la programmation graphique
Composants graphiques
Gestionnaires de mise en forme
Gestion des évènements
Dessin
Introduction
La majorité des programmes informatiques
nécessitent une interaction avec l’utilisateur { travers:
L’entrée de données par l’utilisateur
Des réponses à des questions
L’affichage des résultats obtenus par le programme
Cet échange s’effectue { travers une interface
utilisateur(User interface) qui peut être soit en mode
texte ou en mode graphique
Interface graphique
Une interface graphique (GUI pour Graphical User
Interface) est formée d’une ou plusieurs fenêtres
contenant divers composants graphiques (widgets) tels
que :
boutons,
menus,
champs texte,
liste déroulante,
cases { cocher…etc.
Programmation évènementielle
L’utilisateur de l’interface graphique interagit avec les
objets qui la composent en effectuant des actions
(déplacement, clic de souris, frappe de touche de
clavier…etc)
Ces actions déterminent le cheminement du
programme, donc l’ordre d’exécution des instructions
de peut être prévu { l’écriture du code. Ce type de
programmation est dit « programmation conduite par
les évènement » ou « programmation
évènementielle »
Les différents composants d’une
application graphique
Une application graphique est composée de trois
parties:
Les composants graphiques: ils composent l’interface
graphique de l’application
Les méthodes « écouteurs » d’évènements : font appel
aux méthode d’application pour répondre aux
évènements.
Les méthodes d’application: reçoivent les données de la
GUI et effectuent un traitement puis renvoient les
résultats à la GUI pour être affichées
Les principaux concepts de la
programmation graphique
La programmation graphique est basée sur les trois
concepts suivants:
Les composants graphiques
Les gestionnaires d’emplacement (ou de positionnement)
La gestion des évènements
Les principaux concepts de la
programmation graphique
Les composants graphiques
Ils sont de deux types:
Les conteneurs (containers): destinés { contenir d’autres
composants graphiques. La fenêtre est un conteneur.
Les composants simples ou élémentaires qui doivent être
contenus dans des conteneurs ex: Boutons, menus, cases à
cocher…etc.
Les principaux concepts de la
programmation graphique
Les gestionnaires d’emplacement
Une interface graphique est souvent composée de
plusieurs composants.
La gestion de leur emplacement est déléguée à un
gestionnaire qui s’occupe de
Calculer leur position
Adapter leurs tailles selon la taille de la fenêtre
…etc
Les principaux concepts de la
programmation graphique
La gestion des évènements
Pour gérer les évènements générés par les actions de
l’utilisateur sur l’interface graphique, java utilise des
écouteurs (Listeners en anglais)
Les composants graphiques (boutons, listes, menus,…)
sont écoutés (observés)
chaque composant graphique a ses écouteurs qui
écoutent type d’événement (par exemple, clic de souris).
Dès qu’un évènement survient, l’écouteur exécute
l’action appropriée
Les API
API (Application Programming Interface) est la
bibliothèque de programmation fournie par java
Java offre deux bibliothèques pour faciliter la
programmation graphique:
AWT (Abstract Window Toolkit)
Swing
Qui font partie de JFC (Java Foundation Class) qui offre des facilités
pour construire des interfaces graphiques
Swing est construit au dessus de AWT
Même gestion des évènements
Les classes de swing héritent des classes de AWT
Différences entre swing et AWT
Tous les composants de AWT ont leurs équivalents
dans swing mais ceux-ci sont plus esthétiques et
offrent plus de fonctionnalités
Swing offre de nombreux composants qui n’existent
pas dans AWT.
Il est donc conseillé d’utiliser les composants Swing.
Paquetages principaux
AWT: [Link] et [Link]
Swing: [Link], [Link]
La classe JFrame
/*créer
import [Link].*; un objet de type
JFrame et placer sa
référence dans fen*/
/*Donner à la fenetre
public class PremFen { une hauteur de 300
public pixels et args[])
static void main(String une latgeur
{ de
300 pixels*/
/*afficher ce
texte dans la
JFrame fen = new JFrame();
barre de titre*/
[Link](300,150);
[Link]("ma première fenetre");
[Link](true);
/* rendre la
fenêtre visible*/
}
}
La classe JFrame
L’exécution du code crée une fenêtre ordinaire que
l’utilisateur peut manipuler comme toutes les autres
fenêtre: il peut la déplacer, la redimensionner, la
réduire…etc.
Ces fonctionnalités communes { toutes les fenêtres n’
ont pas été prévue dans notre code, elles sont prises en
charge par la classe JFrame
La classe JFrame
L’objet fen est une instance de la classe JFrame. Il a été
créé en invoquant un des constructeurs de la classe
JFrame ( Il en existe plusieurs)
La méthode setVisible avec l’argument true fait
apparaître la fenêtre sur l’écran. Si on supprime cette
instruction, l’objet fen existera en mémoire mais sera
invisible. De même, l’appel setVisible (false) rend la
fenêtre invisible mais ne détruit pas l’objet.
Taille et emplacement d’une fenêtre
setSize (int width, int height) détermine la taille de la
fenêtre. Avec les arguments 300 et 150 cette méthode modifie
la taille de la fenêtre en mettant la largeur à 300 pixels et la
hauteur { 150 pixels. Par défaut, la taille d’une fenêtre est de 0 x
0 pixels.
setLocation (int x, int y) détermine l’emplacement de la
fenêtre. x et y sont les coordonnées de l’angle gauche supérieur
de la fenêtre tel que x est le nombre de pixel à partir de la
gauche de l’écran et y est le nombre de pixels { partir du haut de
l’écran.
setBounds(int x, int y , int width, int height) spécifie
la taille de la fenêtre et son emplacement à la fois.
La méthode setDefaultCloseOperation()
La méthode setDefaultCloseoperation() précise
l’action { effectuer lorsque l’utilisateur ferme la fenêtre
(en cliquant sur la petite croix en haut à droite de la
fenêtre). Elle a comme argument une des constantes
suivantes:
JFrame.EXIT_ON_CLOSE — fermer la fenêtre.
JFrame.HIDE_ON_CLOSE — cacher la fenêtre
(argument par défaut)
JFrame.DISPOSE_ON_CLOSE — Détruire l’objet
fenêtre.
JFrame.DO_NOTHING_ON_CLOSE — Ne rien faire.
import [Link].*;
public class PremFen2 {
public static void main(String args[]) {
JFrame fen = new JFrame();
[Link](400,300,300,150);
[Link]("ma première fenetre");
[Link](true);
[Link](
JFrame.EXIT_ON_CLOSE );
//[Link](
JFrame.DO_NOTHING_ON_CLOSE);
//[Link](
JFrame.HIDE_ON_CLOSE);
}
}
Fenêtre personnalisée
Si on veut personnaliser notre fenêtre et lui ajouter
des composants en leur associant des fonctionnalités
supplémentaires et réagir à certains évènements, Il est
préférable de définir notre propre classe fenêtre dérivée
de JFrame et manipuler un objet de cette classe.
Fenêtre personnalisée
import [Link].*;
class Fenetre extends JFrame {
public Fenetre() {
setTitle("Ma fenetre personnalisée");
setSize(300,150);
}
}
public class MaFenetre{
public static void main(String args[]) {
JFrame fen = new Fenetre();
[Link](true);
}
}
Fenêtre personnalisée
L’exécution de ce code donne exactement le même
résultat que l’exécution du premier, { la différence que
celui-ci peut être enrichi en ajoutant à la classe Fenetre
de nouveaux objets et de nouvelles fonctionnalités.
Dans nos exemple, nous avons créé une seule fenêtre,
mais rien ne nous empêche d’en créer plusieurs selon les
besoin de notre application graphique.
Exemple avec deux fenêtres
import [Link].*;
class Fenetre extends JFrame {
public Fenetre() {
setTitle("Ma fenetre personnalisée");
setSize(300,150);
}
}
public class MesFenetres{
public static void main(String args[]) {
Fenetre fen1 = new Fenetre();
Fenetre fen2 = new Fenetre();
[Link](300,400);
[Link](true);
[Link](true);
}
}
Les composants graphiques
Ils sont de deux types:
Composants simples (élémentaires ou atomiques):
boutons, cases à cocher, bouton radio, liste
déroulantes…etc
Conteneurs
Composants lourds
Pour afficher des fenêtres (instances de JFrame), Java
s’appuie sur les fenêtres fournies par le système
d’exploitation hôte dans lequel tourne la JVM
Les composants Java qui, comme les Jframe,
s’appuient sur des composants du système hôte sont
dit « lourds »
L’utilisation de composants lourds améliore la rapidité
d'exécution mais nuit à la portabilité et impose les
fonctionnalités des composants
Composants légers
AWT utilise les widgets du système d’exploitation pour
tous les composants graphiques (fenêtres, boutons,
listes, menus,…)
Swing ne les utilise que pour les fenêtres de base
« top-level »
Les autres composants, dits légers, sont dessinés
par Swing dans ces containers lourds
Les conteneurs
Une interface graphique est composée d’un ensemble
de composants placés { l’intérieur d’une ou plusieurs
fenêtres.
Les composants sont contenus dans la fenêtre. Celle-ci
est donc dite conteneur ou container en anglais.
Un conteneur est un objet qui peut contenir d’autres
composants graphiques. Visuellement, c’est une zone
de l’écran contenant des objets plus petits.
Une fenêtre est un conteneur alors qu’un bouton ou
une case à côcher sont des composants qui doivent
toujours être contenus dans un conteneur.
Les conteneurs
Il y a deux types de conteneurs:
Les conteneurs top-level : JFrame, JApplet, JDialog,
JWindow (rarement utilisé).
les conteneurs intermédiaires: JPanel, JScrollPane,
JSplitPane, JToolPane
Containers lourds
Il y a principalement 3 sortes de containers lourds
JFrame fenêtre pour les applications
JApplet pour les applets
JDialog pour les fenêtres de dialogue
Pour construire une interface graphique avec Swing, il
faut créer un (ou plusieurs) container lourd et placer à
l’intérieur les composants légers qui forment l’interface
graphique.
Hiérarchie des containers lourds
Container
Window JComponent Panel
Frame Dialog JWindow Applet
JFrame JDialog JApplet
La classe JComponent
La plupart des composants (widgets) de Swing sont des
instances de sous-classes de la classe JComponent qui
hérite dela classe Container
Les instances des sous-classes de JComponent sont de
composants « légers »
Tous les composants légers des sous-classes de
JComponent peuvent donc contenir d’autres
composants
JPanel
JPanel est dérivé de JComponenent et est la classe
mère des containers intermédiaires les plus simples
Un objet JPanel sert à regrouper des composants dans
une zone d'écran
Il n’a pas d’aspect visuel déterminé ; son aspect
visuel est donné par les composants qu’il contient
Il peut aussi servir de composant dans lequel on
peut dessiner ce que l’on veut, ou faire afficher
une image (par la méthode paintComponent)
Ajouter un bouton
Pour ajouter un bouton à la fenêtre il suffit de :
1. Créer un objet JButton en utilisant le constructeur de la
classe JButton avec comme argument la chaine de
caractère que l’on souhaite voir figurer { l’intérieur.
2. Ajouter le bouton à la fenêtre en utilisant la méthode add
de la classe Container
import [Link].*;
import [Link].*;
class Fenetre2 extends JFrame {
JButton bouton;
public Fenetre2() {
setTitle("Ma fenetre personnalisée");
setBounds(400,300,500,250);
bouton = new JButton("Bouton");
add(bouton);
}
}
public class FenetreAvecBouton{
public static void main(String args[]) {
JFrame fen = new Fenetre2();
[Link](true);
}
}
Notion de gestionnaire de mise en forme
L’affichage de la fenêtre montre que le bouton est présent
(contrairement à la fenêtre, il est visible par défaut), mais
qu’il occupe tout l’espace disponible. Pourquoi ?
La disposition des composants dans une fenêtre est géré par
un gestionnaire de mise en forme ou d’emplacement ou
encore de disposition( Layout manager en anglais)
Java fournit plusieurs gestionnaires ayant chacun sa propre
politique (ses règles)pour disposer les composants (nous les
étudierons plus tard).
Chaque conteneur a un gestionnaire de mise en forme par
défaut.
Pour la classe Jframe, le gestionnaire par défaut est de type
BorderLayout avec lequel par défaut un composant occupe
toute la fenêtre
import [Link].*;
import [Link].*;
class Fenetre2 extends JFrame {
JButton bouton;
public Fenetre2() {
setTitle("Ma fenetre personnalisée");
setBounds(400,300,500,250);
setLayout(new FlowLayout());
bouton = new JButton("Bouton");
add(bouton);
}
}
public class FenetreAvecBouton{
public static void main(String args[]) {
JFrame fen = new Fenetre2();
[Link](true);
}
}
Exemple avec deux boutons
import [Link].*;
import [Link].*;
class Fenetre2 extends JFrame {
JButton bouton1,bouton2;
public Fenetre2() {
setTitle("Ma fenetre personnalisée");
setBounds(400,300,500,250);
setLayout(new FlowLayout());
bouton1 = new JButton("Bouton1");
bouton2 = new JButton("Bouton2");
add(bouton1);
add(bouton2);
}
}
public class FenetreAvecBouton{
public static void main(String args[]) {
Fenetre2 fen = new Fenetre2();
[Link](true);
}
}
Introduction
L’utilisateur d’une interface graphique peut changer la
taille d’une fenêtre, mais cela ne doit pas modifier son
aspect. Les composants graphiques doivent alors être
repositionnés et /ou redimensionnés.
Cette tâche est déléguée au gestionnaire de mise en
forme (layout manager) utilisé par la fenêtre (ou autre
conteneur)
Il existe plusieurs types de layout managers avec des
algorithmes (politiques) de placement différents
Tailles des composants
Tous les composants graphiques (classe Component)
ont plusieurs types de tailles qui sont utiliséers pour
leur affichage
taille maximum
taille préférée
taille minimum
Ces paramètres peuvent être récupérés ou spécifiés
en utilisant les Accesseurs et modificateurs
associés (classe [Link]) :
{get|set}{Maximum|Preferred|Minimum}Size
Taille préférée d’un composant
La taille préférée est la plus utilisée par les layout managers
on peut l’indiquer en redéfinissant la méthode
Dimension getPreferredSize()
On peut aussi l’imposer avec la méthode
void setPreferredSize(Dimension)
La classe Dimension est utilisée pour donner des dimensions
de composants en pixels. Elle possède 2 variables d’instance
publiques de type int: height et width
Taille minimum d’un composant
Quand un composant n’a plus la place pour être affiché
à sa taille préférée, il est affiché à sa taille minimum
sans passer par des tailles intermédiaires
Si la taille minimum est très petite, le résultat est
inesthétique; il est donc conseillé de fixer une taille
minimum, par exemple en la fixant à la taille préférée
[Link]([Link]());
Layout manager
A l’ajout d’un composant, l’utilisateur ne précise pas
l’emplacement de celui-ci, il se contente juste de donner
des indications propres au layout manager utilisé par le
conteneur
Celui-ci (le layout manager) met en forme les composants
« au mieux » (de la meilleure manière possible)suivant:
l’algorithme de placement qui lui est propre
les indications de positionnement des composants
la taille du container
les tailles préférées des composants
Les différents types de Layout manager
Les types les plus courants de gestionnaire de mise en place
(dans [Link]) sont :
BorderLayout : placer aux 4 points cardinaux
FlowLayout : placer à la suite
GridLayout : placer dans une grille
GridBagLayout : placements complexes
BoxLayout : placer verticalement ou horizontalement
Layout manager par défaut
Chaque type de container a un gestionnaire de mise
en forme par défaut:
Une JFrame est gérée par un BorderLayout
un JPanel est géré par un FlowLayout
…etc
On peut changer Le gestionnaire de mise en forme
d’un Container par la méthode
setLayout(LayoutManager) de la classe
Container
BorderLayout
Affiche au maximum 5 composants (aux 4 points
cardinaux et au centre)
Essaie de respecter la hauteur préférée du nord et du
sud et la largeur préférée de l’est et de l’ouest ;
le centre occupe toute la place restante
C’est le layout manager par défaut de JFrame et
Jdialog
FlowLayout
Rangement de haut en bas et de gauche à droite
Les composants sont affichés à leurs tailles préférées
C’est layout manager par défaut de JPanel et Japplet
BoxLayout
Aligne les composants sur une colonne ou une ligne
(on choisit à la création)
Respecte la largeur (resp. hauteur) préférée et
maximum, et l’alignement horizontal (resp. vertical)
Layout manager par défaut de Box et de JToolBar
GridLayout
Les composants sont disposés en lignes et en colonnes
Les composants ont tous la même dimension
Ils occupent toute la place qui leur est allouée
On remplit la grille ligne par ligne ou colonne par
colonne (selon les indications données au
constructeur)
GridBagLayout
Utilise un quadrillage dont les composants peuvent
occuper plusieurs « cases » ; la disposition de chaque
composant est précisée par une instance de la classe
GridBagConstraints
C’est le layout manager le plus souple mais aussi le
plus complexe
CardLayout
affiche sur une même zone des composants différents
à des moments différents
les composants sont affichés à tour de rôle
Ce layout manager est souvent remplacé par le
composant JTabbedPane qui offre le même type de
disposition, en plus simple mais plus puissant, avec
des onglets
Interfaces graphiques complexes
Pour disposer les composants d’une interface graphique
complexe, il existe 3 possibilités:
1. Décomposer l’interface en zones en utilisant des
conteneurs intermédiaires (pouvant contenir eux-
mêmes d’autres conteneurs) et attribuer { chacun
son propre gestionnaire de mise en forme.
2. Utiliser le gestionnaire GridBagLayout.
3. Combiner les possibilités 1 et 2.
Interfaces graphiques complexes
Introduction
L’utilisateur utilise le clavier et la souris pour intervenir
sur le déroulement du programme.
Le système d’exploitation engendre des événements {
partir des actions de l’utilisateur
Le programme doit lier des traitements à ces
événements
Source et écouteur
Les événements font entrer en relation deux types
d’objets :
les sources : ce sont les objets ayant donné naissance à
l’événement(bouton, fenêtre, ...)
les écouteurs : ce sont des objets associés aux sources
dont la classe implémente une interface correspondant à
une catégorie d’événements
Classes d’événements
Les événements sont représentés par des instances de
sous-classes de [Link]:
KeyEvent
MouseEvent
FocusEvent
WindowEvent
ActionEvent
ItemEvent
ComponentEvent
Conventions de nommage
Si un composant graphique peut engendrer des
événements de type xxxEvent L’interface écouteur
s'appellera xxxListener
Sa classe (ou une de ses classes ancêtres) déclare les
méthodes add|remove}xxxListener()
Comment gérer un évènement
La gestion d’un évènement se fait en trois étapes:
1. Choisir une catégorie d’événements
2. Enregistrer un écouter pour une certaine catégorie
d’évènements
[Link](ecouteur)
//Ecouteur étant un objet de XXXListener
3. Ecrire les gestionnaires d’événements dans la classe de
l’écouteur, c { d, définir toutes les méthodes de l’interface
implémentée par la classe de l’écouteur et qui
correspondant à la famille d'événements auquel l’écouteur
va s’enregistrer
Exemple 1: Gestion d’un clic dans la fenêtre
Supposons que nous souhaitions écrire un message à
chaque fois qu’un clic survient dans notre fenêtre :
1. Choix de la catégorie d’évènements:
MouseEventimplémente l’interface MouseListener
2. Enregistrer un écouteur:
[Link](this);
Le premier this signifie que la source est la fenêtre et le second
this signifie que l’écouteur est la fenêtre elle même.
3. Ecrire les méthodes de l’interface MouseListener
L’interface MouseListener
l’interface MouseListener que l’ écouteur doit
implémenter comporte cinq méthodes correspondant
chacune à un événement particulier lié à la souris ;
mousePressed (bouton pressé sur un composant)
mouseReleased (bouton relaché sur un composant)
mouseEntered (la souris entre dans un composant)
mouseExited (la souris sort d’un composant)
mouseClicked (bouton cliqué sur un composant)
ces méthodes sont appelées par la source dés que
l’utilisateur réalise l’action correspondante
Exemple 1: Gestion d’un clic dans la fenêtre
Solution 1
import [Link].*;
import [Link].*;
class MaFenetre extends JFrame implements MouseListener {
public MaFenetre()
{
[Link](200,200,500,350);
[Link]("Gestion des clics");
[Link](this);
// enregistre l’écouteur
// ici une même classe est source et écouteur
}
public void mouseClicked (MouseEvent ev) {
[Link]("Clic dans la fenetre !");
}
public void mousePressed (MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
public void mouseEntered (MouseEvent ev) {}
public void mouseExited (MouseEvent ev) {}
}
public class Clic1 {
public static void main (String args[]) {
JFrame fen = new MaFenetre();
[Link](true);
}
}
Exemple 1: Gestion d’un clic dans la fenêtre
Solution 2
Dans la solution précédente, l’écouteur de la fenêtre était
la fenêtre elle-même. Une autre méthode consiste à
créer un objet ObjetEcouteur et en passer la référence à
la méthode AddMouseListener
mport [Link].*;
import [Link];
class MaFenetre extends JFrame {
public MaFenetre()
{
[Link](200,200,500,350);
[Link]("Gestion des clics");
Ecouteur ecouteur = new Ecouteur();
[Link](ecouteur);
}
}
class Ecouteur implements MouseListener {
public void mouseClicked (MouseEvent ev) {
[Link]("Clic dans la fenetre !");
}
public void mousePressed (MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
public void mouseEntered (MouseEvent ev) {}
public void mouseExited (MouseEvent ev) {}
}
public class Clic2 {
public static void main (String args[]) {
JFrame fen = new MaFenetre();
[Link](true);
}
}
Notion d’adaptateur
Pour éviter au programmeur d’avoir {
implanter toutes les méthodes d’une interface
« écouteur », AWT fournit des classes (on les
appelle des adaptateurs) qui implantent toutes
ces méthodes
Le code des méthodes ne fait rien
Cela permet au programmeur de ne redéfinir
dans une sous-classe que les méthodes qui
l’intéressent
import [Link].*;
import [Link];
class MaFenetre extends JFrame {
public MaFenetre()
{
[Link](200,200,500,350);
[Link]("Gestion des clics");
[Link](new MouseAdapter() {
public void mouseClicked (MouseEvent ev) {
[Link]("Clic dans la fenetre !");
}
}) ;
}
}
public class Clic3 {
public static void main (String args[]) {
JFrame fen = new MaFenetre();
[Link](true);
}
}
Exemple 2: Gestion d’un bouton avec
écouteur
Nous désirons ajouter un bouton à la fenêtre et gérer
l’évènement de clic sur le bouton
Pour associer une action { l’évènement clic sur un
bouton donné il faut utiliser l’événement Action :
cr éer un écouteur qui sera un objet d’une classe
implémentant l’interface ActionListener
associer cet écouteur au bouton par la méthode
addActionListener
import [Link].*;
import [Link].*;
import [Link].*;
class FenBouton extends JFrame implements
ActionListener {
private JButton monBouton;
public FenBouton() {
[Link](200,200,500,350);
[Link]("Evènement action sur un bouton");
[Link] = new JButton("Un bouton");
[Link](new FlowLayout());
[Link](monBouton);
[Link](this);
}
public void actionPerformed (ActionEvent ev) {
[Link]("action sur monBouton");
}
}
Gérer plusieurs composants
Probl ème
Fenêtre comporte un ensemble de composants ; en général
plusieurs composants du même type ([Link]. une fenêtre avec
deux boutons).
comment attacher un comportement différent a chacun des
composants ?
Deux solutions
classe écouteur diff érente pour chaque composant
méthode getSource qui fournit une référence sur l’objet
ayant déclenché l’événement permet d’identifier l’émetteur
public void actionPerformed (ActionEvent ev) {
if ([Link]() == this.bouton1) {
/* Ou encore if ([Link]() == "Bouton
1")*/
[Link]("action sur bouton1");
} else {
[Link]("action sur bouton2") ;
}
}
}
public class BoutonsEvents {
public static void main (String args[]) {
JFrame fen = new FenBouton3();
[Link](true);
}
}
Conteneurs de haut niveau
Conteneurs généraux
Conteneurs spécifiques
Composants de base
Informations non éditables
Présentation de données Informations
hautement formattées