Date de première publication : 2016/02/09
Notions : Swing, thread, fil des événements
Le but de l'exercice est de montrer qu'une interface graphique simple peut se figer facilement mais surtout que l'on peut faire plusieurs choses en même temps (multithreading).
Voici la correction pas à pas (ou presque) de l'exercice intégré au support de cours...
Une interface qui se fige
Il faut un composant graphique capable d'afficher des rectangles, des ellipse ou des polygones, ou même tout en même temps, au choix !
class JCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(i = 0; i< MAX; ++i ) {
g.setColor(...);
g.fillRect(...);
}
}
}
- Il ne faut pas oublier de doter le JCanvas d'une taille préférée (ou alors que le canvas soit intégré dans un layout qui donne une taille non nulle)
- MAX est une constante de la classe. Plus elle est grande, plus le composant sera long à afficher
- Vous avez besoin d'un générateur de nombres aléatoires, je vous propose de faire un attribut de classe de type Random puis d'utiliser les méthodes comme rand.nextInt(255)
Ne pas oublier d'ajouter un menu avec au moins deux items : le premier pour redessiner l'interface et le second pour quitter.
Pour une grande valeur de MAX (et surtout avec un modèle de couleurs ARGB), vous devez constater le blocage de l'interface !
Une interface non bloquée
L'idée est de dessiner dans une mémoire tampon en arrière-plan et de l'afficher quand elle est terminée
Dessiner dans une image
Cela ne va pas changer grand-chose (enfin si, on va encore plus ralentir le processus) mais cela va vous permettre de vérifier que l'on dessine correctement dans l'image
class JCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage image = new BufferedImage(...);
Graphics g2 = image.getGraphics();
for(i = 0; i< MAX; ++i ) {
g2.setColor(...);
g2.fillRect(...);
}
g.drawImage(image, 0, 0, null);
}
}
L'idée est très simple : créer une image de la taille de la fenêtre, récupérer le contexte graphique associé à cette image et dessiner dedans
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
Il faut juste ne pas oublier de dessiner l'image sur l'écran.
Dessiner en arrière-plan
On veut dessiner une image en arrière-plan, alors voilà ce que je propose, on va doter le canvas d'un attribut image et le canvas sera la tâche qui permet de dessiner dedans
class Canvas extends JPanel implements Runnable {
private BuffredImage image;
}
Si l'image est non nulle, on va l'afficher sinon on va la calculer :
public void paintComponent(Graphics g) {
if (image==null)
(new Thread(this)).start();
else g.drawImage(image, 0, 0, null);
}
Vous pouvez améliorer cette méthode en affichant un petit quelquechose pour l'utilisateur (calcul en cours, lancer le calcul ...)
Il manque quand même la réalisation du calcul (la fameuse tâche à faire en fond)
public void run() {}
BufferedImage temp = new BufferedImage(...);
// le code du paintComponent() d'avant;
image = temp;
repaint();
}
Vous voulez redessiner l'image ? Il faut mettre l'attribut à null ...
Vous pouvez améliorer l'affichage en précisant que le calcul est en cours ou bien proposer une barre de progression.
Je me suis amusé à mettre un conteneur en bas de la fenêtre qui ajoute une barre de progression pour chaque calcul en cours :-)
Le reste
Le redimensionnement de la fenêtre
On va maintenant s'occuper du redimensionnement de la fenêtre. Quel est le listener qui gère le redimensionnement ?
ComponentListener
mais il faut d'abord choisir le comportement que l'on veut : afficher un morceau du dessin si la fenêtre est réduite, calculer un nouveau dessin ou encore appliquer un ratio quelque soit la nouvelle taille...
Si vous choisissez cette dernière option, pas besoin du listener, une option de drawImage() suffira !
public void paintComponent(Graphics g) {
if (image==null)
(new Thread(this)).start();
else g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
Un seul code
Il reste encore à défnir la sortie du programme en un seul point : un clic sur la croix et sur l'item de menu ...
C'est encore trop flou ? Vous voulez la correction ?
Le fichier s'appelle RectApp.java