2 import java.awt.event.*;
3 import java.awt.image.*;
10 * <p>Cette classe permet d'écrire des applications graphiques simples
11 * en dessinant dans une fenêtre.
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.
18 * <p>Un appui sur la touche <Esc> 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.
22 * @author Arnaud Giersch <arnaud.giersch@univ-fcomte.fr>
25 public class DrawingWindow {
27 /** Largeur de la fenêtre */
28 public final int width;
30 /** Hauteur de la fenêtre */
31 public final int height;
34 * Construit une nouvelle fenêtre de dessin avec le titre et les dimensions
35 * passés en paramètres.
37 * @param title titre de la fenêtre
38 * @param width largeur de la fenêtre
39 * @param height hauteur de la fenêtre
41 * @see javax.swing.JPanel
43 public DrawingWindow(String title, int width, int height) {
45 this.title = new String(title);
49 image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
50 graphics = image.createGraphics();
53 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
54 public void run() { createGUI(); }
58 System.err.println("Error: interrupted while creating GUI");
59 System.err.println("Got exception: " + e);
63 setColor(Color.BLACK);
64 setBgColor(Color.WHITE);
70 * Change la couleur de dessin.
72 * @param color couleur
76 * @see #setColor(String)
77 * @see #setColor(float, float, float)
78 * @see #setBgColor(Color)
80 public void setColor(Color color) {
81 graphics.setColor(color);
85 * Change la couleur de dessin.
87 * La couleur est un entier, tel que retourné par {@link #getPointColor}.
88 * Normalement de la forme #00RRGGBB.
92 * @see #setColor(String)
93 * @see #setColor(float, float, float)
94 * @see #setBgColor(int)
97 public void setColor(int rgb) {
98 setColor(new Color(rgb));
102 * Change la couleur de dessin.
104 * @param name nom de couleur
106 * @see #setColor(int)
107 * @see #setColor(float, float, float)
108 * @see #setBgColor(String)
109 * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">liste des noms de couleurs</a>
111 public void setColor(String name) {
112 Color color = colorMap.get(name);
116 System.err.println("Warning: color not found: " + name);
120 * Change la couleur de dessin.
122 * Les composantes de rouge, vert et bleu de la couleur doivent être
123 * compris entre 0 et 1. Si le trois composantes sont à 0, on obtient
124 * du noir; si les trois composantes sont à 1, on obtient du blanc.
126 * @param red composante de rouge
127 * @param green composante de vert
128 * @param blue composante de bleu
130 * @see #setColor(int)
131 * @see #setColor(String)
132 * @see #setBgColor(float, float, float)
134 public void setColor(float red, float green, float blue) {
135 setColor(new Color(red, green, blue));
139 * Change la couleur de fond.
141 * @param color couleur
143 * @see #setBgColor(int)
144 * @see #setBgColor(String)
145 * @see #setBgColor(float, float, float)
146 * @see #setColor(Color)
149 public void setBgColor(Color color) {
153 /** Change la couleur de fond.
157 * @see #setBgColor(String)
158 * @see #setBgColor(float, float, float)
159 * @see #setColor(int)
160 * @see #getPointColor
163 public void setBgColor(int rgb) {
164 setBgColor(new Color(rgb));
168 * Change la couleur de fond.
170 * @param name nom de couleur
172 * @see #setBgColor(int)
173 * @see #setBgColor(float, float, float)
174 * @see #setColor(String)
176 * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">liste des noms de couleurs</a>
178 public void setBgColor(String name) {
179 Color color = colorMap.get(name);
183 System.err.println("Warning: color not found: " + name);
186 /** Change la couleur de fond.
188 * @param red composante de rouge
189 * @param green composante de vert
190 * @param blue composante de bleu
192 * @see #setBgColor(int)
193 * @see #setBgColor(String)
194 * @see #setColor(float, float, float)
197 public void setBgColor(float red, float green, float blue) {
198 setBgColor(new Color(red, green, blue));
204 * La fenêtre est effacée avec la couleur de fond courante.
208 public void clearGraph() {
209 synchronized (image) {
210 Color c = graphics.getColor();
211 graphics.setColor(bgColor);
212 graphics.fillRect(0, 0, width, height);
213 graphics.setColor(c);
218 /** Dessine un point.
220 * Dessine un point (pixel) aux coordonnées (x, y), avec la couleur de
225 public void drawPoint(int x, int y) {
226 synchronized (image) {
227 image.setRGB(x, y, graphics.getColor().getRGB());
229 panel.repaint(x, y, 1, 1);
233 * Dessine un segment.
235 * Dessine un segement de droite entre les coordonnées (x1, y1) et
236 * (x2, y2), avec la couleur de dessin courante.
240 public void drawLine(int x1, int y1, int x2, int y2) {
241 synchronized (image) {
242 graphics.drawLine(x1, y1, x2, y2);
244 panel.repaint(Math.min(x1, x2), Math.min(y1, y2),
245 Math.abs(x1 - x2) + 1, Math.abs(y1 - y2) + 1);
248 /** Dessine un rectangle.
250 * Dessine le rectangle parallèle aux axes et défini par les
251 * coordonnées de deux sommets opposés (x1, y1) et (x2, y2). Utilise
252 * la couleur de dessin courante.
257 public void drawRect(int x1, int y1, int x2, int y2) {
258 int x = Math.min(x1, x2);
259 int y = Math.min(y1, y2);
260 int w = Math.abs(x1 - x2);
261 int h = Math.abs(y1 - y2);
262 synchronized (image) {
263 graphics.drawRect(x, y, w, h);
265 panel.repaint(x, y, w + 1, h + 1);
268 /** Dessine un rectangle plein.
270 * Dessine le rectangle plein parallèle aux axes et défini par les
271 * coordonnées de deux sommets opposés (x1, y1) et (x2, y2). Utilise
272 * la couleur de dessin courante.
277 public void fillRect(int x1, int y1, int x2, int y2) {
278 int x = Math.min(x1, x2);
279 int y = Math.min(y1, y2);
280 int w = Math.abs(x1 - x2) + 1;
281 int h = Math.abs(y1 - y2) + 1;
282 synchronized (image) {
283 graphics.fillRect(x, y, w, h);
285 panel.repaint(x, y, w, h);
291 * Dessine un cercle de centre (x, y) et de rayon r. Utilise la
292 * couleur de dessin courante.
297 public void drawCircle(int x, int y, int r) {
298 synchronized (image) {
299 graphics.drawOval(x - r, y - r, 2 * r, 2 * r);
301 panel.repaint(x - r, y - r, 2 * r + 1, 2 * r + 1);
307 * Dessine un disque (cercle plein) de centre (x, y) et de rayon r.
308 * Utilise la couleur de dessin courante.
313 public void fillCircle(int x, int y, int r) {
314 synchronized (image) {
315 graphics.drawOval(x - r, y - r, 2 * r, 2 * r);
316 graphics.fillOval(x - r, y - r, 2 * r, 2 * r);
318 panel.repaint(x - r, y - r, 2 * r + 1, 2 * r + 1);
322 * Dessine un triangle.
324 * Dessine un triangle défini par les coordonnées de ses sommets:
325 * (x1, y1), (x2, y2) et (x3, y3). Utilise la couleur de dessin
332 public void drawTriangle(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);
340 panel.repaint(poly.getBounds());
344 * Dessine un triangle plein.
346 * Dessine un triangle plein défini par les coordonnées de ses
347 * sommets: (x1, y1), (x2, y2) et (x3, y3). Utilise la couleur de
353 public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
354 Polygon poly = new Polygon();
355 poly.addPoint(x1, y1);
356 poly.addPoint(x2, y2);
357 poly.addPoint(x3, y3);
358 synchronized (image) {
359 graphics.drawPolygon(poly);
360 graphics.fillPolygon(poly);
362 panel.repaint(poly.getBounds());
368 * Écrit le texte text, aux coordonnées (x, y).
370 public void drawText(int x, int y, String text) {
371 synchronized (image) {
372 graphics.drawString(text, x, y);
374 panel.repaint(); // don't know how to calculate tighter bounding box
378 * Retourne la couleur d'un pixel.
380 * Retourne la couleur du pixel de coordonnées (x, y).
382 * @return couleur du pixel
384 * @see #setColor(int)
385 * @see #setBgColor(int)
387 public int getPointColor(int x, int y) {
388 return image.getRGB(x, y);
392 * Synchronise le contenu de la fenêtre.
394 * Pour des raisons d'efficacités, le résultat des fonctions de dessin
395 * n'est pas affiché immédiatement. L'appel à sync permet de
396 * synchroniser le contenu de la fenêtre. Autrement dit, cela bloque
397 * l'exécution du programme jusqu'à ce que le contenu de la fenêtre
401 // put an empty action on the event queue, and wait for its completion
403 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
404 public void run() { }
407 catch (Exception e) {
412 * Ferme la fenêtre graphique.
414 public void closeGraph() {
415 javax.swing.SwingUtilities.invokeLater(new Runnable() {
418 new WindowEvent(frame,
419 WindowEvent.WINDOW_CLOSING);
420 Toolkit.getDefaultToolkit()
421 .getSystemEventQueue().postEvent(ev);
428 * Suspend l'exécution pendant un certain temps.
430 * @param secs temps d'attente en seconde
432 static void sleep(long secs) {
434 Thread.sleep(secs * 1000);
436 catch (Exception e) {
441 * Suspend l'exécution pendant un certain temps.
443 * @param msecs temps d'attente en millisecondes
445 static void msleep(long msecs) {
449 catch (Exception e) {
454 * Suspend l'exécution pendant un certain temps.
456 * @param usecs temps d'attente en microsecondes
458 static void usleep(long usecs) {
460 Thread.sleep(usecs / 1000, (int)(usecs % 1000) * 1000);
462 catch (Exception e) {
466 /* PRIVATE STUFF FOLLOWS */
468 private static final Map<String, Color> colorMap;
471 Map<String, Color> m = new HashMap<String, Color>();
472 // From http://www.w3.org/TR/SVG/types.html#ColorKeywords
473 m.put("aliceblue", new Color(0x00f0f8ff));
474 m.put("antiquewhite", new Color(0x00faebd7));
475 m.put("aqua", new Color(0x0000ffff));
476 m.put("aquamarine", new Color(0x007fffd4));
477 m.put("azure", new Color(0x00f0ffff));
478 m.put("beige", new Color(0x00f5f5dc));
479 m.put("bisque", new Color(0x00ffe4c4));
480 m.put("black", new Color(0000000000));
481 m.put("blanchedalmond", new Color(0x00ffebcd));
482 m.put("blue", new Color(0x000000ff));
483 m.put("blueviolet", new Color(0x008a2be2));
484 m.put("brown", new Color(0x00a52a2a));
485 m.put("burlywood", new Color(0x00deb887));
486 m.put("cadetblue", new Color(0x005f9ea0));
487 m.put("chartreuse", new Color(0x007fff00));
488 m.put("chocolate", new Color(0x00d2691e));
489 m.put("coral", new Color(0x00ff7f50));
490 m.put("cornflowerblue", new Color(0x006495ed));
491 m.put("cornsilk", new Color(0x00fff8dc));
492 m.put("crimson", new Color(0x00dc143c));
493 m.put("cyan", new Color(0x0000ffff));
494 m.put("darkblue", new Color(0x0000008b));
495 m.put("darkcyan", new Color(0x00008b8b));
496 m.put("darkgoldenrod", new Color(0x00b8860b));
497 m.put("darkgray", new Color(0x00a9a9a9));
498 m.put("darkgreen", new Color(0x00006400));
499 m.put("darkgrey", new Color(0x00a9a9a9));
500 m.put("darkkhaki", new Color(0x00bdb76b));
501 m.put("darkmagenta", new Color(0x008b008b));
502 m.put("darkolivegreen", new Color(0x00556b2f));
503 m.put("darkorange", new Color(0x00ff8c00));
504 m.put("darkorchid", new Color(0x009932cc));
505 m.put("darkred", new Color(0x008b0000));
506 m.put("darksalmon", new Color(0x00e9967a));
507 m.put("darkseagreen", new Color(0x008fbc8f));
508 m.put("darkslateblue", new Color(0x00483d8b));
509 m.put("darkslategray", new Color(0x002f4f4f));
510 m.put("darkslategrey", new Color(0x002f4f4f));
511 m.put("darkturquoise", new Color(0x0000ced1));
512 m.put("darkviolet", new Color(0x009400d3));
513 m.put("deeppink", new Color(0x00ff1493));
514 m.put("deepskyblue", new Color(0x0000bfff));
515 m.put("dimgray", new Color(0x00696969));
516 m.put("dimgrey", new Color(0x00696969));
517 m.put("dodgerblue", new Color(0x001e90ff));
518 m.put("firebrick", new Color(0x00b22222));
519 m.put("floralwhite", new Color(0x00fffaf0));
520 m.put("forestgreen", new Color(0x00228b22));
521 m.put("fuchsia", new Color(0x00ff00ff));
522 m.put("gainsboro", new Color(0x00dcdcdc));
523 m.put("ghostwhite", new Color(0x00f8f8ff));
524 m.put("gold", new Color(0x00ffd700));
525 m.put("goldenrod", new Color(0x00daa520));
526 m.put("gray", new Color(0x00808080));
527 m.put("grey", new Color(0x00808080));
528 m.put("green", new Color(0x00008000));
529 m.put("greenyellow", new Color(0x00adff2f));
530 m.put("honeydew", new Color(0x00f0fff0));
531 m.put("hotpink", new Color(0x00ff69b4));
532 m.put("indianred", new Color(0x00cd5c5c));
533 m.put("indigo", new Color(0x004b0082));
534 m.put("ivory", new Color(0x00fffff0));
535 m.put("khaki", new Color(0x00f0e68c));
536 m.put("lavender", new Color(0x00e6e6fa));
537 m.put("lavenderblush", new Color(0x00fff0f5));
538 m.put("lawngreen", new Color(0x007cfc00));
539 m.put("lemonchiffon", new Color(0x00fffacd));
540 m.put("lightblue", new Color(0x00add8e6));
541 m.put("lightcoral", new Color(0x00f08080));
542 m.put("lightcyan", new Color(0x00e0ffff));
543 m.put("lightgoldenrodyellow", new Color(0x00fafad2));
544 m.put("lightgray", new Color(0x00d3d3d3));
545 m.put("lightgreen", new Color(0x0090ee90));
546 m.put("lightgrey", new Color(0x00d3d3d3));
547 m.put("", new Color(0000000000));
548 m.put("lightpink", new Color(0x00ffb6c1));
549 m.put("lightsalmon", new Color(0x00ffa07a));
550 m.put("lightseagreen", new Color(0x0020b2aa));
551 m.put("lightskyblue", new Color(0x0087cefa));
552 m.put("lightslategray", new Color(0x00778899));
553 m.put("lightslategrey", new Color(0x00778899));
554 m.put("lightsteelblue", new Color(0x00b0c4de));
555 m.put("lightyellow", new Color(0x00ffffe0));
556 m.put("lime", new Color(0x0000ff00));
557 m.put("limegreen", new Color(0x0032cd32));
558 m.put("linen", new Color(0x00faf0e6));
559 m.put("magenta", new Color(0x00ff00ff));
560 m.put("maroon", new Color(0x00800000));
561 m.put("mediumaquamarine", new Color(0x0066cdaa));
562 m.put("mediumblue", new Color(0x000000cd));
563 m.put("mediumorchid", new Color(0x00ba55d3));
564 m.put("mediumpurple", new Color(0x009370db));
565 m.put("mediumseagreen", new Color(0x003cb371));
566 m.put("mediumslateblue", new Color(0x007b68ee));
567 m.put("mediumspringgreen", new Color(0x0000fa9a));
568 m.put("mediumturquoise", new Color(0x0048d1cc));
569 m.put("mediumvioletred", new Color(0x00c71585));
570 m.put("midnightblue", new Color(0x00191970));
571 m.put("mintcream", new Color(0x00f5fffa));
572 m.put("mistyrose", new Color(0x00ffe4e1));
573 m.put("moccasin", new Color(0x00ffe4b5));
574 m.put("navajowhite", new Color(0x00ffdead));
575 m.put("navy", new Color(0x00000080));
576 m.put("oldlace", new Color(0x00fdf5e6));
577 m.put("olive", new Color(0x00808000));
578 m.put("olivedrab", new Color(0x006b8e23));
579 m.put("orange", new Color(0x00ffa500));
580 m.put("orangered", new Color(0x00ff4500));
581 m.put("orchid", new Color(0x00da70d6));
582 m.put("palegoldenrod", new Color(0x00eee8aa));
583 m.put("palegreen", new Color(0x0098fb98));
584 m.put("paleturquoise", new Color(0x00afeeee));
585 m.put("palevioletred", new Color(0x00db7093));
586 m.put("papayawhip", new Color(0x00ffefd5));
587 m.put("peachpuff", new Color(0x00ffdab9));
588 m.put("peru", new Color(0x00cd853f));
589 m.put("pink", new Color(0x00ffc0cb));
590 m.put("plum", new Color(0x00dda0dd));
591 m.put("powderblue", new Color(0x00b0e0e6));
592 m.put("purple", new Color(0x00800080));
593 m.put("red", new Color(0x00ff0000));
594 m.put("rosybrown", new Color(0x00bc8f8f));
595 m.put("royalblue", new Color(0x004169e1));
596 m.put("saddlebrown", new Color(0x008b4513));
597 m.put("salmon", new Color(0x00fa8072));
598 m.put("sandybrown", new Color(0x00f4a460));
599 m.put("seagreen", new Color(0x002e8b57));
600 m.put("seashell", new Color(0x00fff5ee));
601 m.put("sienna", new Color(0x00a0522d));
602 m.put("silver", new Color(0x00c0c0c0));
603 m.put("skyblue", new Color(0x0087ceeb));
604 m.put("slateblue", new Color(0x006a5acd));
605 m.put("slategray", new Color(0x00708090));
606 m.put("slategrey", new Color(0x00708090));
607 m.put("snow", new Color(0x00fffafa));
608 m.put("springgreen", new Color(0x0000ff7f));
609 m.put("steelblue", new Color(0x004682b4));
610 m.put("tan", new Color(0x00d2b48c));
611 m.put("teal", new Color(0x00008080));
612 m.put("thistle", new Color(0x00d8bfd8));
613 m.put("tomato", new Color(0x00ff6347));
614 m.put("turquoise", new Color(0x0040e0d0));
615 m.put("violet", new Color(0x00ee82ee));
616 m.put("wheat", new Color(0x00f5deb3));
617 m.put("white", new Color(0x00ffffff));
618 m.put("whitesmoke", new Color(0x00f5f5f5));
619 m.put("yellow", new Color(0x00ffff00));
620 m.put("yellowgreen", new Color(0x009acd32));
621 colorMap = Collections.unmodifiableMap(m);
624 private final String title; // window's title
625 private JFrame frame; // the frame (window)
626 private DWPanel panel; // the panel showing the image
627 private BufferedImage image; // the image we draw into
628 private Graphics2D graphics; // graphics associated with image
629 private Color bgColor; // background color, for clearGraph()
631 // To be run on the Event Dispatching Thread
633 panel = new DWPanel(this);
635 frame = new JFrame(title);
638 frame.setResizable(false);
639 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
640 frame.addKeyListener(panel);
641 frame.setLocationByPlatform(true);
642 frame.setVisible(true);
645 private class DWPanel extends JPanel implements KeyListener {
647 private static final long serialVersionUID = 0;
649 final DrawingWindow w;
651 DWPanel(DrawingWindow w) {
653 Dimension dimension = new Dimension(w.width, w.height);
654 super.setMinimumSize(dimension);
655 super.setMaximumSize(dimension);
656 super.setPreferredSize(dimension);
659 public void paint(Graphics g) {
660 synchronized (w.image) {
661 g.drawImage(w.image, 0, 0, null);
665 public void keyPressed(KeyEvent e) {
666 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
671 public void keyReleased(KeyEvent e) { }
672 public void keyTyped(KeyEvent e) { }