Logo AND Algorithmique Numérique Distribuée

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