Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add proper Makefile for Graphlib.
[graphlib_java.git] / DrawingWindow.java
1 import java.awt.*;
2 import java.awt.event.*;
3 import java.awt.image.*;
4 import javax.swing.*;
5 import java.lang.reflect.*;
6
7 /**
8  * Fenêtre de dessin
9  *
10  * <p>Cette classe permet d'écrire des applications graphiques simples
11  * en dessinant dans une fenêtre.
12  *
13  * <p><b>NB.</b> Pour toutes les méthodes de dessin, le coin en haut à
14  * gauche de la fenêtre a les coordonnées (0, 0).  Le coin en bas à
15  * droite de la fenêtre a les coordonnées (largeur - 1, hauteur - 1),
16  * si la fenêtre est de dimension largeur × hauteur.
17  *
18  * <p>Un appui sur la touche &lt;Esc&gt; provoque la fermeture de la
19  * fenêtre.  Comme pour la plupart des applications, il est également
20  * possible de fermer la fenêtre via le gestionnaire de fenêtres.
21  *
22  * <p>Télécharger le code: <a href="DrawingWindow.java">DrawingWindow.java</a>
23  *
24  * <p>Télécharger des exemples d'utilisation:
25  * <a href="Hello.java">Hello.java</a>
26  * <a href="Exemple1.java">Exemple1.java</a>
27  * <a href="Exemple2.java">Exemple2.java</a>
28  * <a href="Exemple3.java">Exemple3.java</a>
29  *
30  * @author Arnaud Giersch &lt;arnaud.giersch@univ-fcomte.fr&gt;
31  * @version 20141008
32  */
33 public class DrawingWindow
34     extends JPanel
35     implements KeyListener {
36
37     /** Titre de la fenêtre */
38     public final String title;
39
40     /** Largeur de la fenêtre */
41     public final int width;
42
43     /** Hauteur de la fenêtre */
44     public final int height;
45
46     /**
47      * Construit une nouvelle fenêtre de dessin avec le titre et les dimensions
48      * passés en paramètres.
49      *
50      * @param title             titre de la fenêtre
51      * @param width             largeur de la fenêtre
52      * @param height            hauteur de la fenêtre
53      *
54      * @see javax.swing.JPanel
55      */
56     public DrawingWindow(String title, int width, int height) {
57         this.title = new String(title);        
58         this.width = width;
59         this.height = height;
60
61         Dimension dimension = new Dimension(width, height);
62         super.setMinimumSize(dimension);
63         super.setMaximumSize(dimension);
64         super.setPreferredSize(dimension);
65
66         image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
67         graphics = image.createGraphics();
68
69         setColor(Color.BLACK);
70         setBgColor(Color.WHITE);
71         clearGraph();
72
73         try {
74             javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
75                     public void run() {
76                         frame = new JFrame(DrawingWindow.this.title);
77
78                         frame.add(DrawingWindow.this);
79                         frame.pack();
80                         frame.setResizable(false);
81
82                         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
83                         frame.addKeyListener(DrawingWindow.this);
84
85                         frame.setLocationByPlatform(true);
86                         frame.setVisible(true);
87                     }
88                 });
89         }
90         catch (Exception e) {
91             System.err.println("Warning: caught spurious exception: " + e);
92         }
93         sync();
94     }
95
96     /**
97      * Change la couleur de dessin.
98      *
99      * @param color         couleur
100      *
101      * @see java.awt.Color
102      * @see #setColor(String)
103      * @see #setColor(float, float, float)
104      * @see #setBgColor(Color)
105      */
106     public void setColor(Color color) {
107         graphics.setColor(color);
108     }
109
110     /**
111      * Change la couleur de dessin.
112      *
113      * Le nom de couleur est de la forme "black", "white", "red", "blue", ...
114      *
115      * @param name          nom de couleur
116      *
117      * @see #setColor(Color)
118      * @see #setColor(float, float, float)
119      * @see #setBgColor(String)
120      */
121     public void setColor(String name) {
122         try {
123             Field field = Class.forName("java.awt.Color").getField(name);
124             graphics.setColor((Color)field.get(null));
125         } catch (Exception e) {
126             System.err.println("Warning: color not found: " + name);
127         }
128     }
129
130     /**
131      * Change la couleur de dessin.
132      *
133      * Les composantes de rouge, vert et bleu de la couleur doivent être
134      * compris entre 0 et 1.  Si le trois composantes sont à 0, on obtient
135      * du noir; si les trois composantes sont à 1, on obtient du blanc.
136      *
137      * @param red           composante de rouge
138      * @param green         composante de vert
139      * @param blue          composante de bleu
140      *
141      * @see #setColor(Color)
142      * @see #setColor(String)
143      * @see #setBgColor(float, float, float)
144      */
145     public void setColor(float red, float green, float blue) {
146         setColor(new Color(red, green, blue));
147     }
148
149     /**
150      * Change la couleur de fond.
151      *
152      * @param color         couleur
153      *
154      * @see #setBgColor(String)
155      * @see #setBgColor(float, float, float)
156      * @see #setColor(Color)
157      * @see #clearGraph()
158      */
159     public void setBgColor(Color color) {
160         bgColor = color;
161     }
162
163     /**
164      * Change la couleur de fond.
165      *
166      * @param name          nom de couleur
167      *
168      * @see #setBgColor(Color)
169      * @see #setBgColor(float, float, float)
170      * @see #setColor(String)
171      * @see #clearGraph()
172      */
173     public void setBgColor(String name) {
174         try {
175             Field field = Class.forName("java.awt.Color").getField(name);
176             bgColor = (Color)field.get(null);
177         } catch (Exception e) {
178             System.err.println("Warning: color not found: " + name);
179         }
180     }
181
182     /** Change la couleur de fond.
183      *
184      * @param red           composante de rouge
185      * @param green         composante de vert
186      * @param blue          composante de bleu
187      *
188      * @see #setBgColor(Color)
189      * @see #setBgColor(String)
190      * @see #setColor(float, float, float)
191      * @see #clearGraph()
192      */
193     public void setBgColor(float red, float green, float blue) {
194         bgColor = new Color(red, green, blue);
195     }
196
197     /**
198      * Efface la fenêtre.
199      *
200      * La fenêtre est effacée avec la couleur de fond courante.
201      *
202      * @see #setBgColor
203      */
204     public void clearGraph() {
205         synchronized (image) {
206             Color c = graphics.getColor();
207             graphics.setColor(bgColor);
208             graphics.fillRect(0, 0, width, height);
209             graphics.setColor(c);
210         }
211         repaint();
212     }
213
214     /** Dessine un point.
215      *
216      * Dessine un point (pixel) aux coordonnées (x, y), avec la couleur de
217      * dessin courante.
218      *
219      * @see #setColor
220      */
221     public void drawPoint(int x, int y) {
222         synchronized (image) {
223             image.setRGB(x, y, graphics.getColor().getRGB());
224         }
225         repaint(x, y, 1, 1);
226     }
227
228     /**
229      * Dessine un segment.
230      *
231      * Dessine un segement de droite entre les coordonnées (x1, y1) et
232      * (x2, y2), avec la couleur de dessin courante.
233      *
234      * @see #setColor
235      */
236     public void drawLine(int x1, int y1, int x2, int y2) {
237         synchronized (image) {
238             graphics.drawLine(x1, y1, x2, y2);
239         }
240         repaint(Math.min(x1, x2), Math.min(y1, y2),
241                 Math.abs(x1 - x2) + 1, Math.abs(y1 - y2) + 1);
242     }
243
244     /** Dessine un rectangle.
245      *
246      * Dessine le rectangle parallèle aux axes et défini par les
247      * coordonnées de deux sommets opposés (x1, y1) et (x2, y2).  Utilise
248      * la couleur de dessin courante.
249      *
250      * @see #fillRect
251      * @see #setColor
252      */
253     public void drawRect(int x1, int y1, int x2, int y2) {
254         int x = Math.min(x1, x2);
255         int y = Math.min(y1, y2);
256         int w = Math.abs(x1 - x2);
257         int h = Math.abs(y1 - y2);
258         synchronized (image) {
259             graphics.drawRect(x, y, w, h);
260         }
261         repaint(x, y, w, h);
262     }
263
264     /** Dessine un rectangle plein.
265      *
266      * Dessine le rectangle plein parallèle aux axes et défini par les
267      * coordonnées de deux sommets opposés (x1, y1) et (x2, y2).  Utilise
268      * la couleur de dessin courante.
269      *
270      * @see #drawRect
271      * @see #setColor
272      */
273     public void fillRect(int x1, int y1, int x2, int y2) {
274         int x = Math.min(x1, x2);
275         int y = Math.min(y1, y2);
276         int w = Math.abs(x1 - x2);
277         int h = Math.abs(y1 - y2);
278         synchronized (image) {
279             graphics.fillRect(x, y, w, h);
280         }
281         repaint(x, y, w, h);
282     }
283
284     /**
285      * Dessine un cercle.
286      *
287      * Dessine un cercle de centre (x, y) et de rayon r.  Utilise la
288      * couleur de dessin courante.
289      *
290      * @see #fillCircle
291      * @see #setColor
292      */
293     public void drawCircle(int x, int y, int r) {
294         synchronized (image) {
295             graphics.drawOval(x - r, y - r, 2 * r, 2 * r);
296         }
297         repaint(x - r, y - r, 2 * r, 2 * r);
298     }
299
300     /**
301      * Dessine un disque.
302      *
303      * Dessine un disque (cercle plein) de centre (x, y) et de rayon r.
304      * Utilise la couleur de dessin courante.
305      *
306      * @see #drawCircle
307      * @see #setColor
308      */
309     public void fillCircle(int x, int y, int r) {
310         synchronized (image) {
311             graphics.fillOval(x - r, y - r, 2 * r, 2 * r);
312         }
313         repaint(x - r, y - r, 2 * r, 2 * r);
314     }
315
316     /**
317      * Écrit du texte.
318      *
319      * Écrit le texte text, aux coordonnées (x, y).
320      */
321     public void drawText(int x, int y, String text) {
322         synchronized (image) {
323             graphics.drawString(text, x, y);
324         }
325         repaint(); // don't know how to calculate tighter bounding box
326     }
327
328     /**
329      * Retourne la couleur d'un pixel.
330      *
331      * Retourne la couleur du pixel de coordonnées (x, y).
332      *
333      * @return              couleur du pixel
334      */
335     public int getPointColor(int x, int y) {
336         return image.getRGB(x, y);
337     }
338
339     /**
340      * Synchronise le contenu de la fenêtre.
341      *
342      * Pour des raisons d'efficacités, le résultat des fonctions de dessin
343      * n'est pas affiché immédiatement.  L'appel à sync permet de
344      * synchroniser le contenu de la fenêtre.  Autrement dit, cela bloque
345      * l'exécution du programme jusqu'à ce que le contenu de la fenêtre
346      * soit à jour.
347      */
348     public void sync() {
349         // put an empty action on the event queue, and  wait for its completion
350         try {
351             javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
352                     public void run() { }
353                 });
354         }
355         catch (Exception e) {
356         }
357     }
358
359     /**
360      *  Ferme la fenêtre graphique.
361      */
362     public void closeGraph() {
363         javax.swing.SwingUtilities.invokeLater(new Runnable() {
364                 public void run() {
365                     WindowEvent ev =
366                         new WindowEvent(frame,
367                                         WindowEvent.WINDOW_CLOSING);
368                     Toolkit.getDefaultToolkit()
369                         .getSystemEventQueue().postEvent(ev);
370                 }
371             });
372     }
373
374
375     /**
376      * Suspend l'exécution pendant un certain temps.
377      *
378      * @param secs          temps d'attente en seconde
379      */
380     static void sleep(long secs) {
381         try {
382             Thread.sleep(secs * 1000);
383         }
384         catch (Exception e) {
385         }
386     }
387
388     /**
389      * Suspend l'exécution pendant un certain temps.
390      *
391      * @param msecs          temps d'attente en millisecondes
392      */
393     static void msleep(long msecs) {
394         try {
395             Thread.sleep(msecs);
396         }
397         catch (Exception e) {
398         }
399     }
400
401     /**
402      * Suspend l'exécution pendant un certain temps.
403      *
404      * @param usecs          temps d'attente en microsecondes
405      */
406     static void usleep(long usecs) {
407         try {
408             Thread.sleep(usecs / 1000, (int)(usecs % 1000) * 1000);
409         }
410         catch (Exception e) {
411         }
412     }
413
414     public void paint(Graphics g) {
415         synchronized (image) {
416             g.drawImage(image, 0, 0, null);
417         }
418     }
419
420     public void keyPressed(KeyEvent e) {
421         if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
422             closeGraph();
423         }
424     }
425
426     public void keyReleased(KeyEvent e) { }
427     public void keyTyped(KeyEvent e) { }
428
429     /* PRIVATE STUFF FOLLOW */
430
431     private static final long serialVersionUID = 0;
432
433     private JFrame frame;
434     private BufferedImage image;
435     private Graphics2D graphics;
436     private Color bgColor;
437
438 }