Académique Documents
Professionnel Documents
Culture Documents
2 Notions facultatives 14
2.1 Liste chaînée pré-conçue . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 Obtenir les dimensions de l’écran . . . . . . . . . . . . . . . . . . 15
2.3 Obtenir la taille d’un texte . . . . . . . . . . . . . . . . . . . . . 16
2.4 Gérer un fichier texte . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5 Méthode paint et JPanel . . . . . . . . . . . . . . . . . . . . . . 19
2.6 Mettre une image de fond et/ou superposer plusieurs images/-
widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.7 Gérer un groupe de JRadioButton . . . . . . . . . . . . . . . . . 23
2.8 Tracé d’une fonction . . . . . . . . . . . . . . . . . . . . . . . . . 26
Avertissement :
— Ce qui suit est un résumé des concepts essentiels présentés
dans les transparents de cours disponibles sur moodle.
— Il y a également des notions qui ne sont pas vus en cours mais
qui peuvent vous servir.
— Dans les codes que vous trouverez ci dessous, la méthode main
est incluse dans la classe pour des raisons de lisibilité. N’ou-
bliez pas de l’enlever si vous réutilisez ces codes.
— Pour plus de détails, n’oubliez pas de consulter la Javadoc.
1
— Ce document est en version 0.3. Merci de signaler toutes co-
quilles rencontrées.
2
1 Notions essentielles
1.1 Méthode paint
1.1.1 Principe général
Tous les composants graphiques possèdent une méthode public
void paint(Graphics g)
qui définie leur apparence graphique. Si on veut modifier cette apparence, il faut
surcharger (redéfinir) la méthode paint du composant en appelant des méthodes
de la classe Graphics sur l’objet g.
L’appel de cette méthode ne peut être effectué directement dans le code.
C’est le système de gestion graphique (gérer par le système d’exploitation) qui
fait cet appel à chaque fois que le composant doit être dessiné à l’écran après une
modification ou une occultation. Il est toutefois possible de demander au système
d’exploitation d’appeler la méthode paint dès que possible via l’exécution de
l’instruction suivante :
repaint();
Remarque. L’exemple qui suit redéfinit la méthode paint d’un objet héritant de
JFrame. Pour modifier l’apparence graphique d’un objet héritant de JPanel, on
consultera la sous-section 2.5.
Remarque. Pour plus de détails sur les différentes formes géométriques pouvant
être dessinées, on consultera les transparents du cours ou la javadoc pour les
fonctionnalités plus avancées.
import java.awt.*;
import javax.swing.*;
3
g.drawLine(xA,yA,xB,yB);
4
1.2 Événements souris
1.2.1 Principe général
Comme dans le cas des événements boutons (revoir le cours sur la program-
mation événementielle), l’idée consiste à créer un écouteur captant les événe-
ments générés par les mouvements de la souris. Cet écouteur est associé à un
composant graphique (JFrame, JPanel, etc). Des événements seront alors générés
lorsque la souris se déplacera au dessus de ce composant. Plus de détails dans
la javadoc.
Plus précisément, la démarche est la suivante :
— indiquer que votre classe va implémenter l’interface MouseListener
— redéfinir toutes les méthodes de l’interface MouseListener (même si cer-
taines n’ont rien de particulier à faire) :
// Méthode appelée quand le bouton de la souris a été pressée
public void mousePressed(MouseEvent e) { ... }
// Méthode appelée quand le bouton de la souris a été relâchée
public void mouseReleased(MouseEvent e) { ... }
// Méthode appelée quand la souris passe sur le composant
public void mouseEntered(MouseEvent e) { ... }
// Méthode appelée quand la souris sort du composant
public void mouseExited(MouseEvent e) { ... }
// Méthode appelée quand le bouton de la souris a été cliquée
(appuyée puis relâchée)
public void mouseClicked(MouseEvent e) { ... }
Remarque. Pour capter les événements générés par les mouvements de sou-
ris (et non les clicks), le principe est identique mais l’interface à utiliser est
MouseMotionListener au lieu de MouseListener.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
5
// même si elles sont vides car elles sont abstraites
6
1.3 Événements clavier
1.3.1 Principe général
La démarche est très similaire à celle présentée pour le cas des événements
souris (à ceci près que l’interface est KeyListener au lieu de MouseListener). Plus
de détails dans la javadoc.
La démarche est la suivante :
— indiquer que votre classe va implémenter l’interface KeyListener.
— redéfinir toutes les méthodes de l’interface KeyListener (même si certaines
n’ont rien de particulier à faire) :
// méthode exécutée à chaque fois qu’une touche est enfoncée
public void keyPressed(KeyEvent e) { ... }
// méthode exécutée à chaque fois qu’une touche est relâchée
public void keyReleased(KeyEvent e) { ... }
// méthode exécutée à chaque fois qu’une touche unicode est
utilisée (donc pas CTRL, SHIFT ou ALT par exemple)
public void keyTyped(KeyEvent e) { ... }
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public EventClavier() {
setSize(100,100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addKeyListener(this);
setVisible(true);
}
7
System.out.print("C’est la fleche du bas. ");
else
System.out.print("Ce n’est ni espace, ni bas. ");
}
8
1.4 Affichage d’images externes
1.4.1 Principe général
L’affichage d’une image externe se fait en deux étapes :
1. chargement de l’image en mémoire à partir de son nom (le fichier doit
être dans le répertoire courant) :
Toolkit T = Toolkit.getDefaultToolkit();
Image im = T.getImage("insa_logo.png");
Remarque. Comme l’illustre l’exemple qui suit, il est conseillé de charger l’image
en mémoire une seule fois et en dehors de la méthode paint (qui sera fréquem-
ment appelée), afin de réduire le temps d’exécution.
import java.awt.*;
import javax.swing.*;
// chargement de l’image
Toolkit T=Toolkit.getDefaultToolkit();
im = T.getImage("insa_logo.png");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
repaint(); // demande d’appel de la méthode paint
}
9
1.5 Utilisation d’un Timer
1.5.1 Principe général
La classe Timer permet de commander l’exécution d’une méthode à intervalle
de temps régulier. Le constructeur de Timer
public Timer(int delay, ActionListener listener)
crée une instance qui exécutera, tous les delay millisecondes, la méthode actionPerformed
de l’instance qui implémente l’interface ActionListener.
Dans l’exemple ci dessous, il y a une boucle infinie dans la méthode main pour
simplifier le code. Il est possible de mettre en pause le Timer t avec l’instruction
t.stop().
Remarque. Il existe une méthode qui permet de savoir si le Timer est en cours
ou en pause. Soit t une instance de Timer, t.isRunning() retourne false si t est
en pause et true sinon.
import java.awt.event.*;
import javax.swing.*;
10
1.6 Gestion du scintillement
1.6.1 Principe général
Lors de l’exécution de la méthode paint, si le temps qui sépare le dessin du
premier objet graphique (ligne, rectangle...) du dernier est trop long, l’écran peut
scintiller. Typiquement, ce problème apparaît lorsque l’algorithme permettant
de définir l’apparence graphique d’un composant est progressif (le dessin se
fait tout au long de l’algorithme) et exigeant (en terme de temps de calcul).
L’exemple avec scintillement qui suit illustre cette difficulté puisque l’appel de
la méthode paint demande l’exécution de la méthode dessineLourd qui requière
le parcours (exigeant en terme de calcul) de la double boucle suivante :
for(int i=0;i<d.width;i++)
for(int j=0;j<d.height;j++)
g.drawLine(i,j,i,j);
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
11
}
/*
* Cette methode fait un calcul exigeant en calcul puisqu’elle
* dessine point par point un rectangle sur toute la surface
d’affichage
* dont la couleur alterne entre rouge et noir.
*/
public void dessineLourd(Graphics g) {
Dimension d = getContentPane().getSize(); // dimension de la zone
d’affichage
// alternance de la couleur d’affichage
if (b)
g.setColor(Color.black);
else
g.setColor(Color.red);
b = !b;
// dessin de toute la zone d’affichage point par point
for(int i=getInsets().left;i<d.width;i++)
for(int j=getInsets().top;j<d.height;j++)
g.drawLine(i,j,i,j); // ligne commencant et terminant au meme
point
}
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
// initialisation du buffer
12
Dimension dim = getSize(); // recupere la taille reelle de la
fenetre
monBuf = new
BufferedImage(dim.width,dim.height,BufferedImage.TYPE_INT_RGB);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
13
2 Notions facultatives
2.1 Liste chaînée pré-conçue
2.1.1 Principe général
La classe LinkedList permet d’utiliser des listes chaînées sans avoir à re-
programmer les méthodes d’insertion, de suppression, etc. Chaque instance de
LinkedList est une liste chaînée pour laquelle chaque nœud est associé à une
instance d’une certaine classe. Dans le cas où cette classe correspond à Point,
l’instanciation s’écrit comme suit :
LinkedList<Point> maListe = new LinkedList<Point>();
L’instance maListe est alors une liste chaînée pour laquelle chaque nœud est
associé à une instance de Point.
Remarque. Dans le cas où l’on souhaite associer un type primitif (int, char, etc)
aux nœuds de la liste, on utilisera les objets correspondants aux types primitifs
comme Integer pour le type int :
LinkedList<Integer> maListe = new LinkedList<Integer>();
import java.awt.Point;
import java.util.LinkedList;
// supression de ce noeud
maListe.remove(1);
14
2.2 Obtenir les dimensions de l’écran
2.2.1 Principe général
Comme un programme Java peut être affiché sur des écrans de différentes
tailles, il peut être intéressant, lors de la création de la fenêtre de récupérer les
informations sur la taille de l’écran.
Pour être plus précis, il est possible de prendre en compte les dimensions des
bordures des fenêtres, de la barre des tâches et donc de distinguer la dimension
physique et la dimension utile.
import java.awt.*;
import javax.swing.*;
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
15
2.3 Obtenir la taille d’un texte
2.3.1 Principe général
Le texte affiché sur une fenêtre a également une dimension que l’on peut
obtenir si nécessaire afin de placer des widgets correctement autour du texte.
import java.awt.*;
import javax.swing.*;
g.setColor(Color.black);
g.drawString("La hauteur de ce texte est de "+hauteurTexte+"
pixels", 100,100);
}
16
2.4 Gérer un fichier texte
2.4.1 Principe général
Il est possible de lire des informations contenues dans un fichier, d’écrire des
informations dans un fichier ou d’effacer un fichier. Les exemples ci dessous per-
mettent de lire les informations contenues dans un fichier monFichierLire.txt
et d’écrire dans un fichier monFichierEcrire.txt.
Pour cela il existe différentes méthodes. Le choix a été fait ici de passer par
des tampons (appelés BufferedReader pour la lecture et BufferedWriter pour
l’écriture) pour éviter d’avoir à lire et/ou écrire caractère par caractère afin de
limiter le nombre d’accès en lecture et/ou écriture du fichier.
Il est important de ne pas oublier de fermer le fichier une fois les opérations
terminées sous peine de ne plus pouvoir l’utiliser.
import java.io.*;
// Attributs
private String monFichier;
/** Constructeur
* @param leFichier : le nom du fichier
*/
public GestionFichiers(String leFichier) {
monFichier = leFichier;
}
17
/** Ecriture dans le fichier
*/
public void ecrire(int nombre) {
BufferedWriter fichier = null;
try {
String ligne ;
fichier = new BufferedWriter(new FileWriter(monFichier));
fichier.write("Hello World");
fichier.newLine();
fichier.write("Voici du texte");
fichier.write(", et un nombre : " + nombre);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fichier.close(); // Fermeture du fichier
System.out.println("Le fichier "+ monFichier +" a ete ecrit
!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
18
2.5 Méthode paint et JPanel
2.5.1 Principe général
Pour éviter d’avoir à redessiner la fenêtre entièrement à chaque fois, il est
possible de ne redessiner qu’une partie contenue dans un JPanel. Pour cela,
on peut créer notre propre JPanel et l’ajouter à notre fenêtre principale. La
méthode paint n’a besoin d’être redéfinie que dans ce nouveau JPanel.
public MonPaintJPanel(Color c) {
myColor=c;
}
// Conteneur1
JPanel monConteneur1 = new JPanel();
monConteneur1.setBounds(50,10,500,80);
monConteneur1.setLayout(null);
monConteneur1.setBackground(Color.magenta);
JLabel monTexte = new JLabel("Voici mon 1er conteneur");
19
monTexte.setBounds(10,0,200,80);
JButton monBouton = new JButton("GO ?");
monBouton.setBounds(250,10,100,60);
monConteneur1.add(monTexte);
monConteneur1.add(monBouton);
// Conteneur2
MonPaintJPanel monConteneur2 = new MonPaintJPanel(Color.yellow);
monConteneur2.setBounds(20,110,560,240);
monConteneur2.setLayout(null);
// Conteneur principal
JPanel monConteneurPrincipal = new JPanel();
monConteneurPrincipal.setBounds(0,0,getWidth(),getHeight());
monConteneurPrincipal.setLayout(null);
monConteneurPrincipal.add(monConteneur1);
monConteneurPrincipal.add(monConteneur2);
setContentPane(monConteneurPrincipal);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
20
2.6 Mettre une image de fond et/ou superposer plusieurs
images/widgets
2.6.1 Principe général
Pour égayer votre IHM, il est possible d’insérer une image en arrière plan au
lieu d’une couleur unie appliquée avec la méthode setBackground. Le principe
est de créer un JLabel contenant l’image. On peut aussi superposer plusieurs
images et ajouter d’autres widgets. Attention l’ordre dans lequel ces widgets
sont ajoutés a une influence sur leur superposition. Ainsi les premiers ajoutés
seront au premier plan et les suivants sur un plan derrière. Le dernier élément
ajouté sera donc en arrière plan.
public ImageFenetre(){
this.setTitle("mon IHM");
this.setSize(560,470);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/**
* Mon panneau qui contient l’image
*/
JPanel panneauImage = new JPanel();
panneauImage.setBounds(20,20,500,400);
panneauImage.setLayout(null);
21
// Mon JLabel qui contient une image
// Le fichier image doit se trouver dans le même dossier que les
fichiers java
JLabel monImage1 = new JLabel(new ImageIcon("insa_logo.png"));
monImage1.setBounds(340,20,140,55);
panneauImage.add(monImage1);
/**
* Mon panneau Global
*/
JPanel panneauGlobal = new JPanel();
panneauGlobal.setBounds(0,0,400,400);
panneauGlobal.setLayout(null);
panneauGlobal.setBackground(Color.yellow);
panneauGlobal.add(panneauImage);
/**
* La methode main est placee ici pour des raisons de simplicite
* mais elle devrait se trouver dans une autre classe
*/
public static void main(String[] args){
22
2.7 Gérer un groupe de JRadioButton
2.7.1 Principe général
Pour permettre de faciliter l’interaction avec l’utilisateur, il est possible de
lui proposer un groupe de JRadioButton. Ce dernier permet à l’utilisateur de
choisir une et unique option parmi celles proposées. Ainsi lorsque l’utilisateur
fait un choix en cliquant sur une option, les autres sont désélectionnées auto-
matiquement afin de ne pouvoir en choisir qu’une. Pour cela, il faut créer des
JRadioButton et les regrouper dans un ButtonGroup. Il faut penser aussi à ajouter
un écouteur à ces JRadioButton afin de récupérer l’action de l’utilisateur.
public RadioBoutonFenetre(){
this.setTitle("mon IHM");
this.setSize(560,470);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/**
* Mon panneau qui contient les radio boutons
*/
JPanel panneauRadio = new JPanel();
panneauRadio.setBounds(20,20,500,400);
panneauRadio.setLayout(null);
panneauRadio.setBackground(Color.blue);
23
monRadio1.addActionListener(this);
panneauRadio.add(monRadio1);
/**
* Mon panneau Global
*/
JPanel panneauGlobal = new JPanel();
panneauGlobal.setBounds(0,0,400,400);
panneauGlobal.setLayout(null);
panneauGlobal.setBackground(Color.yellow);
panneauGlobal.add(panneauRadio);
/**
* La methode appelee lorsqu’on clique sur un radiobouton
*/
public void actionPerformed(ActionEvent e){
if (e.getSource()==monRadio1){
monTexte.setText(monRadio1.getText());
}
else if (e.getSource()==monRadio2){
monTexte.setText(monRadio2.getText());
}
else if (e.getSource()==monRadio3){
monTexte.setText(monRadio3.getText());
}
24
}
/**
* La methode main est placee ici pour des raisons de simplicite
* mais elle devrait se trouver dans une autre classe
*/
public static void main(String[] args){
25
2.8 Tracé d’une fonction
2.8.1 Principe général
L’objectif ici est de tracer la suite de fonctions mathématiques suivante dans
un intervalle donné :
x
fn (x) = sin (2n + 1) ∗ π ∗ 20
La difficulté réside ici dans le fait que le repère “mathématique” classique-
ment utilisé a une origine au centre, l’axe des abscisses de la gauche vers la
droite et l’axe des ordonnées du bas vers le haut. Or le repère “graphique” sous
java est inversé pour l’axe des ordonnées et l’origine est en haut à gauche de la
fenêtre. Il faut donc faire une conversion pour passer de l’un à l’autre.
/**
* Classe permetttant de dessiner entre xA et xB
* la suite de fonction fn(x)=sin((2n+1)*PI*x/20)
*/
import java.awt.*;
import javax.swing.*;
/**
* Constructeur
* @param a et b l’intervalle d’etude de la fonction
*/
public Courbe(int a, int b) {
xA=a;
xB=b;
setTitle("Courbe fn(x)=sin((2n+1)*PI*x/20) entre "+xA+" et "+xB);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800,200);
setVisible(true);
}
/**
* Definition de la fonction mathematique
* @param n le nombre de courbes a dessiner
* @param x la valeur pour laquelle il faut calculer la fonction
* @return f_n(x)
* Les coordonnees sont calculees dans le repere "mathematique"
*/
private double fn(int n, double x) {
return Math.sin((2*n+1)*(Math.PI) * x/20);
}
/**
26
* Pour convertir les coordonnees par rapport a notre fenetre
graphique
* @param x la valeur en abscisse a mettre entre 0 et la largeur l
* @param y la valeur en ordonnee a mettre entr 0 et la hauteur h
* @return les coordonnees du point a tracer sur le graphique
*/
private Point ToScreen(double x, double y) {
// calcul la hauteur et largeur de la surface visible de la fenetre
int h=getSize().height-getInsets().top-getInsets().bottom;
int l=getSize().width-getInsets().left-getInsets().right;
// Conversion entre le repere "mathematique" et le repere
"graphique"
int xE=(int)((x-xA)/(xB-xA)*l);
int yE=(int)((y+1)/2*h);
return new Point(xE+getInsets().left,yE+getInsets().top);
}
/**
* La methode paint pour dessiner les fonctions
*/
public void paint(Graphics g) {
Color[] tabCouleur =
{Color.black,Color.gray,Color.blue,Color.cyan,Color.green,
Color.magenta,Color.orange,Color.pink,Color.red,Color.yellow};
Point a,b;
double x,y;
// Mettre le fond blanc
g.setColor(Color.white);
g.fillRect(0,0,getSize().width,getSize().height);
// Dessiner le repere centre
g.setColor(Color.black);
a=ToScreen(0,+1); b=ToScreen(0,-1); g.drawLine(a.x,a.y,b.x,b.y);
a=ToScreen(xA,0); b=ToScreen(xB,0); g.drawLine(a.x,a.y,b.x,b.y);
// Tracer 9 courbes fn(x)
for (int n=1; n<10; n++) {
g.setColor(tabCouleur[n]);
x=xA; y=fn(n,xA); a=ToScreen(x,y);
// Trace un courbe fn(x) avec x de xA à xB
while (x<=xB)
{
x+=0.05; y=fn(n,x);
b=ToScreen(x,y); g.drawLine(a.x,a.y,b.x,b.y);
a=b; // on sauve le point precedent
}
}
}
27
}
28