Logo AND Algorithmique Numérique Distribuée

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