Logo AND Algorithmique Numérique Distribuée

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