Logo AND Algorithmique Numérique Distribuée

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