Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
4cb330d0d743250d4b03b979e214c332b1274b48
[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 Thu Oct 9 16:03:46 2014 +0200
32  */
33 public class DrawingWindow {
34
35     /** Largeur de la fenêtre */
36     public final int width;
37
38     /** Hauteur de la fenêtre */
39     public final int height;
40
41     /**
42      * Construit une nouvelle fenêtre de dessin avec le titre et les dimensions
43      * passés en paramètres.
44      *
45      * @param title             titre de la fenêtre
46      * @param width             largeur de la fenêtre
47      * @param height            hauteur de la fenêtre
48      *
49      * @see javax.swing.JPanel
50      */
51     public DrawingWindow(String title, int width, int height) {
52
53         this.title = new String(title);
54         this.width = width;
55         this.height = height;
56
57         image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
58         graphics = image.createGraphics();
59
60         try {
61             javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
62                     public void run() { createGUI(); }
63                 });
64         }
65         catch (Exception e) {
66             System.err.println("Error: interrupted while creating GUI");
67             System.err.println("Got exception: " + e);
68             System.exit(1);
69         }
70
71         setColor(Color.BLACK);
72         setBgColor(Color.WHITE);
73         clearGraph();
74         sync();
75     }
76
77     /**
78      * Change la couleur de dessin.
79      *
80      * @param color         couleur
81      *
82      * @see java.awt.Color
83      * @see #setColor(String)
84      * @see #setColor(float, float, float)
85      * @see #setBgColor(Color)
86      */
87     public void setColor(Color color) {
88         graphics.setColor(color);
89     }
90
91     /**
92      * Change la couleur de dessin.
93      *
94      * Le nom de couleur peut être "black", "blue", "cyan",
95      * "darkGray", "gray", "green", "lightGray", "magenta", "orange",
96      * "pink", "red", "white", ou "yellow".
97      *
98      * @param name          nom de couleur
99      *
100      * @see #setColor(Color)
101      * @see #setColor(float, float, float)
102      * @see #setBgColor(String)
103      */
104     public void setColor(String name) {
105         try {
106             Field field = Class.forName("java.awt.Color").getField(name);
107             graphics.setColor((Color)field.get(null));
108         } catch (Exception e) {
109             System.err.println("Warning: color not found: " + name);
110         }
111     }
112
113     /**
114      * Change la couleur de dessin.
115      *
116      * Les composantes de rouge, vert et bleu de la couleur doivent être
117      * compris entre 0 et 1.  Si le trois composantes sont à 0, on obtient
118      * du noir; si les trois composantes sont à 1, on obtient du blanc.
119      *
120      * @param red           composante de rouge
121      * @param green         composante de vert
122      * @param blue          composante de bleu
123      *
124      * @see #setColor(Color)
125      * @see #setColor(String)
126      * @see #setBgColor(float, float, float)
127      */
128     public void setColor(float red, float green, float blue) {
129         setColor(new Color(red, green, blue));
130     }
131
132     /**
133      * Change la couleur de fond.
134      *
135      * @param color         couleur
136      *
137      * @see #setBgColor(String)
138      * @see #setBgColor(float, float, float)
139      * @see #setColor(Color)
140      * @see #clearGraph()
141      */
142     public void setBgColor(Color color) {
143         bgColor = color;
144     }
145
146     /**
147      * Change la couleur de fond.
148      *
149      * @param name          nom de couleur
150      *
151      * @see #setBgColor(Color)
152      * @see #setBgColor(float, float, float)
153      * @see #setColor(String)
154      * @see #clearGraph()
155      */
156     public void setBgColor(String name) {
157         try {
158             Field field = Class.forName("java.awt.Color").getField(name);
159             bgColor = (Color)field.get(null);
160         } catch (Exception e) {
161             System.err.println("Warning: color not found: " + name);
162         }
163     }
164
165     /** Change la couleur de fond.
166      *
167      * @param red           composante de rouge
168      * @param green         composante de vert
169      * @param blue          composante de bleu
170      *
171      * @see #setBgColor(Color)
172      * @see #setBgColor(String)
173      * @see #setColor(float, float, float)
174      * @see #clearGraph()
175      */
176     public void setBgColor(float red, float green, float blue) {
177         bgColor = new Color(red, green, blue);
178     }
179
180     /**
181      * Efface la fenêtre.
182      *
183      * La fenêtre est effacée avec la couleur de fond courante.
184      *
185      * @see #setBgColor
186      */
187     public void clearGraph() {
188         synchronized (image) {
189             Color c = graphics.getColor();
190             graphics.setColor(bgColor);
191             graphics.fillRect(0, 0, width, height);
192             graphics.setColor(c);
193         }
194         panel.repaint();
195     }
196
197     /** Dessine un point.
198      *
199      * Dessine un point (pixel) aux coordonnées (x, y), avec la couleur de
200      * dessin courante.
201      *
202      * @see #setColor
203      */
204     public void drawPoint(int x, int y) {
205         synchronized (image) {
206             image.setRGB(x, y, graphics.getColor().getRGB());
207         }
208         panel.repaint(x, y, 1, 1);
209     }
210
211     /**
212      * Dessine un segment.
213      *
214      * Dessine un segement de droite entre les coordonnées (x1, y1) et
215      * (x2, y2), avec la couleur de dessin courante.
216      *
217      * @see #setColor
218      */
219     public void drawLine(int x1, int y1, int x2, int y2) {
220         synchronized (image) {
221             graphics.drawLine(x1, y1, x2, y2);
222         }
223         panel.repaint(Math.min(x1, x2), Math.min(y1, y2),
224                       Math.abs(x1 - x2) + 1, Math.abs(y1 - y2) + 1);
225     }
226
227     /** Dessine un rectangle.
228      *
229      * Dessine le rectangle parallèle aux axes et défini par les
230      * coordonnées de deux sommets opposés (x1, y1) et (x2, y2).  Utilise
231      * la couleur de dessin courante.
232      *
233      * @see #fillRect
234      * @see #setColor
235      */
236     public void drawRect(int x1, int y1, int x2, int y2) {
237         int x = Math.min(x1, x2);
238         int y = Math.min(y1, y2);
239         int w = Math.abs(x1 - x2);
240         int h = Math.abs(y1 - y2);
241         synchronized (image) {
242             graphics.drawRect(x, y, w, h);
243         }
244         panel.repaint(x, y, w + 1, h + 1);
245     }
246
247     /** Dessine un rectangle plein.
248      *
249      * Dessine le rectangle plein parallèle aux axes et défini par les
250      * coordonnées de deux sommets opposés (x1, y1) et (x2, y2).  Utilise
251      * la couleur de dessin courante.
252      *
253      * @see #drawRect
254      * @see #setColor
255      */
256     public void fillRect(int x1, int y1, int x2, int y2) {
257         int x = Math.min(x1, x2);
258         int y = Math.min(y1, y2);
259         int w = Math.abs(x1 - x2) + 1;
260         int h = Math.abs(y1 - y2) + 1;
261         synchronized (image) {
262             graphics.fillRect(x, y, w, h);
263         }
264         panel.repaint(x, y, w, h);
265     }
266
267     /**
268      * Dessine un cercle.
269      *
270      * Dessine un cercle de centre (x, y) et de rayon r.  Utilise la
271      * couleur de dessin courante.
272      *
273      * @see #fillCircle
274      * @see #setColor
275      */
276     public void drawCircle(int x, int y, int r) {
277         synchronized (image) {
278             graphics.drawOval(x - r, y - r, 2 * r, 2 * r);
279         }
280         panel.repaint(x - r, y - r, 2 * r + 1, 2 * r + 1);
281     }
282
283     /**
284      * Dessine un disque.
285      *
286      * Dessine un disque (cercle plein) de centre (x, y) et de rayon r.
287      * Utilise la couleur de dessin courante.
288      *
289      * @see #drawCircle
290      * @see #setColor
291      */
292     public void fillCircle(int x, int y, int r) {
293         synchronized (image) {
294             graphics.drawOval(x - r, y - r, 2 * r, 2 * r);
295             graphics.fillOval(x - r, y - r, 2 * r, 2 * r);
296         }
297         panel.repaint(x - r, y - r, 2 * r + 1, 2 * r + 1);
298     }
299
300     /**
301      * Dessine un triangle.
302      *
303      * Dessine un triangle défini par les coordonnées de ses sommets:
304      * (x1, y1), (x2, y2) et (x3, y3).  Utilise la couleur de dessin
305      * courante.
306      *
307      * @see #fillTriangle
308      * @see #setColor
309      */
310
311     public void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
312         Polygon poly = new Polygon();
313         poly.addPoint(x1, y1);
314         poly.addPoint(x2, y2);
315         poly.addPoint(x3, y3);
316         synchronized (image) {
317             graphics.drawPolygon(poly);
318         }
319         panel.repaint(poly.getBounds());
320     }
321
322     /**
323      * Dessine un triangle plein.
324      *
325      * Dessine un triangle plein défini par les coordonnées de ses
326      * sommets: (x1, y1), (x2, y2) et (x3, y3).  Utilise la couleur de
327      * dessin courante.
328      *
329      * @see #drawTriangle
330      * @see #setColor
331      */
332     public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
333         Polygon poly = new Polygon();
334         poly.addPoint(x1, y1);
335         poly.addPoint(x2, y2);
336         poly.addPoint(x3, y3);
337         synchronized (image) {
338             graphics.drawPolygon(poly);
339             graphics.fillPolygon(poly);
340         }
341         panel.repaint(poly.getBounds());
342     }
343
344     /**
345      * Écrit du texte.
346      *
347      * Écrit le texte text, aux coordonnées (x, y).
348      */
349     public void drawText(int x, int y, String text) {
350         synchronized (image) {
351             graphics.drawString(text, x, y);
352         }
353         panel.repaint(); // don't know how to calculate tighter bounding box
354     }
355
356     /**
357      * Retourne la couleur d'un pixel.
358      *
359      * Retourne la couleur du pixel de coordonnées (x, y).
360      *
361      * @return              couleur du pixel
362      */
363     public int getPointColor(int x, int y) {
364         return image.getRGB(x, y);
365     }
366
367     /**
368      * Synchronise le contenu de la fenêtre.
369      *
370      * Pour des raisons d'efficacités, le résultat des fonctions de dessin
371      * n'est pas affiché immédiatement.  L'appel à sync permet de
372      * synchroniser le contenu de la fenêtre.  Autrement dit, cela bloque
373      * l'exécution du programme jusqu'à ce que le contenu de la fenêtre
374      * soit à jour.
375      */
376     public void sync() {
377         // put an empty action on the event queue, and  wait for its completion
378         try {
379             javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
380                     public void run() { }
381                 });
382         }
383         catch (Exception e) {
384         }
385     }
386
387     /**
388      *  Ferme la fenêtre graphique.
389      */
390     public void closeGraph() {
391         javax.swing.SwingUtilities.invokeLater(new Runnable() {
392                 public void run() {
393                     WindowEvent ev =
394                         new WindowEvent(frame,
395                                         WindowEvent.WINDOW_CLOSING);
396                     Toolkit.getDefaultToolkit()
397                         .getSystemEventQueue().postEvent(ev);
398                 }
399             });
400     }
401
402
403     /**
404      * Suspend l'exécution pendant un certain temps.
405      *
406      * @param secs          temps d'attente en seconde
407      */
408     static void sleep(long secs) {
409         try {
410             Thread.sleep(secs * 1000);
411         }
412         catch (Exception e) {
413         }
414     }
415
416     /**
417      * Suspend l'exécution pendant un certain temps.
418      *
419      * @param msecs          temps d'attente en millisecondes
420      */
421     static void msleep(long msecs) {
422         try {
423             Thread.sleep(msecs);
424         }
425         catch (Exception e) {
426         }
427     }
428
429     /**
430      * Suspend l'exécution pendant un certain temps.
431      *
432      * @param usecs          temps d'attente en microsecondes
433      */
434     static void usleep(long usecs) {
435         try {
436             Thread.sleep(usecs / 1000, (int)(usecs % 1000) * 1000);
437         }
438         catch (Exception e) {
439         }
440     }
441
442     /* PRIVATE STUFF FOLLOWS */
443
444     private final String title; // window's title
445     private JFrame frame;       // the frame (window)
446     private DWPanel panel;      // the panel showing the image
447     private BufferedImage image; // the image we draw into
448     private Graphics2D graphics; // graphics associated with image
449     private Color bgColor;       // background color, for clearGraph()
450
451     // To be run on the Event Dispatching Thread
452     void createGUI() {
453         panel = new DWPanel(this);
454
455         frame = new JFrame(title);
456         frame.add(panel);
457         frame.pack();
458         frame.setResizable(false);
459         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
460         frame.addKeyListener(panel);
461         frame.setLocationByPlatform(true);
462         frame.setVisible(true);
463     }
464
465     private class DWPanel extends JPanel implements KeyListener {
466
467         private static final long serialVersionUID = 0;
468
469         final DrawingWindow w;
470
471         DWPanel(DrawingWindow w) {
472             this.w = w;
473             Dimension dimension = new Dimension(w.width, w.height);
474             super.setMinimumSize(dimension);
475             super.setMaximumSize(dimension);
476             super.setPreferredSize(dimension);
477         }
478
479         public void paint(Graphics g) {
480             synchronized (w.image) {
481                 g.drawImage(w.image, 0, 0, null);
482             }
483         }
484
485         public void keyPressed(KeyEvent e) {
486             if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
487                 w.closeGraph();
488             }
489         }
490
491         public void keyReleased(KeyEvent e) { }
492         public void keyTyped(KeyEvent e) { }
493
494     }
495 }