1 import java.util.Collections;
2 import java.util.HashMap;
5 import java.awt.Dimension;
6 import java.awt.Graphics2D;
7 import java.awt.Graphics;
9 import java.awt.Polygon;
10 import java.awt.Rectangle;
11 import java.awt.Toolkit;
12 import java.awt.event.KeyAdapter;
13 import java.awt.event.KeyEvent;
14 import java.awt.event.MouseAdapter;
15 import java.awt.event.MouseEvent;
16 import java.awt.event.WindowAdapter;
17 import java.awt.event.WindowEvent;
18 import java.awt.image.BufferedImage;
19 import javax.swing.JFrame;
20 import javax.swing.JPanel;
25 * <p>Cette classe permet d'écrire des applications graphiques simples
26 * en dessinant dans une fenêtre.
28 * <p><b>NB.</b> Pour toutes les méthodes de dessin, le coin en haut à
29 * gauche de la fenêtre a les coordonnées (0, 0). Le coin en bas à
30 * droite de la fenêtre a les coordonnées (largeur - 1, hauteur - 1),
31 * si la fenêtre est de dimension largeur × hauteur.
33 * <p>Un appui sur la touche <Esc> provoque la fermeture de la
34 * fenêtre. Comme pour la plupart des applications, il est également
35 * possible de fermer la fenêtre via le gestionnaire de fenêtres.
37 * @author Arnaud Giersch <arnaud.giersch@univ-fcomte.fr>
40 public class DrawingWindow {
42 /** Largeur de la fenêtre */
43 public final int width;
45 /** Hauteur de la fenêtre */
46 public final int height;
49 * Construit une nouvelle fenêtre de dessin avec le titre et les dimensions
50 * passés en paramètres.
52 * @param title titre de la fenêtre
53 * @param width largeur de la fenêtre
54 * @param height hauteur de la fenêtre
56 * @see javax.swing.JPanel
58 public DrawingWindow(String title, int width, int height) {
60 this.title = new String(title);
64 mouseLock = new Object();
66 mousePos = new Point(0, 0);
69 image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
70 graphics = image.createGraphics();
73 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
74 public void run() { createGUI(); }
78 System.err.println("Error: interrupted while creating GUI");
79 System.err.println("Got exception: " + e);
83 setColor(Color.BLACK);
84 setBgColor(Color.WHITE);
90 * Change la couleur de dessin.
92 * @param color couleur
96 * @see #setColor(String)
97 * @see #setColor(float, float, float)
98 * @see #setBgColor(Color)
100 public void setColor(Color color) {
101 graphics.setColor(color);
105 * Change la couleur de dessin.
107 * La couleur est un entier, tel que retourné par {@link #getPointColor}.
108 * Normalement de la forme #00RRGGBB.
112 * @see #setColor(String)
113 * @see #setColor(float, float, float)
114 * @see #setBgColor(int)
115 * @see #getPointColor
117 public void setColor(int rgb) {
118 setColor(new Color(rgb));
122 * Change la couleur de dessin.
124 * @param name nom de couleur
126 * @see #setColor(int)
127 * @see #setColor(float, float, float)
128 * @see #setBgColor(String)
129 * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">liste des noms de couleurs</a>
131 public void setColor(String name) {
132 Color color = colorMap.get(name);
136 System.err.println("Warning: color not found: " + name);
140 * Change la couleur de dessin.
142 * Les composantes de rouge, vert et bleu de la couleur doivent être
143 * compris entre 0 et 1. Si le trois composantes sont à 0, on obtient
144 * du noir; si les trois composantes sont à 1, on obtient du blanc.
146 * @param red composante de rouge
147 * @param green composante de vert
148 * @param blue composante de bleu
150 * @see #setColor(int)
151 * @see #setColor(String)
152 * @see #setBgColor(float, float, float)
154 public void setColor(float red, float green, float blue) {
155 setColor(new Color(red, green, blue));
159 * Change la couleur de fond.
161 * @param color couleur
163 * @see #setBgColor(int)
164 * @see #setBgColor(String)
165 * @see #setBgColor(float, float, float)
166 * @see #setColor(Color)
169 public void setBgColor(Color color) {
173 /** Change la couleur de fond.
177 * @see #setBgColor(String)
178 * @see #setBgColor(float, float, float)
179 * @see #setColor(int)
180 * @see #getPointColor
183 public void setBgColor(int rgb) {
184 setBgColor(new Color(rgb));
188 * Change la couleur de fond.
190 * @param name nom de couleur
192 * @see #setBgColor(int)
193 * @see #setBgColor(float, float, float)
194 * @see #setColor(String)
196 * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">liste des noms de couleurs</a>
198 public void setBgColor(String name) {
199 Color color = colorMap.get(name);
203 System.err.println("Warning: color not found: " + name);
206 /** Change la couleur de fond.
208 * @param red composante de rouge
209 * @param green composante de vert
210 * @param blue composante de bleu
212 * @see #setBgColor(int)
213 * @see #setBgColor(String)
214 * @see #setColor(float, float, float)
217 public void setBgColor(float red, float green, float blue) {
218 setBgColor(new Color(red, green, blue));
224 * La fenêtre est effacée avec la couleur de fond courante.
228 public void clearGraph() {
229 synchronized (image) {
230 Color c = graphics.getColor();
231 graphics.setColor(bgColor);
232 graphics.fillRect(0, 0, width, height);
233 graphics.setColor(c);
238 /** Dessine un point.
240 * Dessine un point (pixel) aux coordonnées (x, y), avec la couleur de
245 public void drawPoint(int x, int y) {
246 if (x < 0 || y < 0 || x >= width || y >= height)
248 synchronized (image) {
249 image.setRGB(x, y, graphics.getColor().getRGB());
251 panel.repaint(x, y, 1, 1);
255 * Dessine un segment.
257 * Dessine un segement de droite entre les coordonnées (x1, y1) et
258 * (x2, y2), avec la couleur de dessin courante.
262 public void drawLine(int x1, int y1, int x2, int y2) {
263 synchronized (image) {
264 graphics.drawLine(x1, y1, x2, y2);
266 panel.repaint(Math.min(x1, x2), Math.min(y1, y2),
267 Math.abs(x1 - x2) + 1, Math.abs(y1 - y2) + 1);
270 /** Dessine un rectangle.
272 * Dessine le rectangle parallèle aux axes et défini par les
273 * coordonnées de deux sommets opposés (x1, y1) et (x2, y2). Utilise
274 * la couleur de dessin courante.
279 public void drawRect(int x1, int y1, int x2, int y2) {
280 int x = Math.min(x1, x2);
281 int y = Math.min(y1, y2);
282 int w = Math.abs(x1 - x2);
283 int h = Math.abs(y1 - y2);
284 synchronized (image) {
285 graphics.drawRect(x, y, w, h);
287 panel.repaint(x, y, w + 1, h + 1);
290 /** Dessine un rectangle plein.
292 * Dessine le rectangle plein parallèle aux axes et défini par les
293 * coordonnées de deux sommets opposés (x1, y1) et (x2, y2). Utilise
294 * la couleur de dessin courante.
299 public void fillRect(int x1, int y1, int x2, int y2) {
300 int x = Math.min(x1, x2);
301 int y = Math.min(y1, y2);
302 int w = Math.abs(x1 - x2) + 1;
303 int h = Math.abs(y1 - y2) + 1;
304 synchronized (image) {
305 graphics.fillRect(x, y, w, h);
307 panel.repaint(x, y, w, h);
313 * Dessine un cercle de centre (x, y) et de rayon r. Utilise la
314 * couleur de dessin courante.
319 public void drawCircle(int x, int y, int r) {
320 synchronized (image) {
321 graphics.drawOval(x - r, y - r, 2 * r, 2 * r);
323 panel.repaint(x - r, y - r, 2 * r + 1, 2 * r + 1);
329 * Dessine un disque (cercle plein) de centre (x, y) et de rayon r.
330 * Utilise la couleur de dessin courante.
335 public void fillCircle(int x, int y, int r) {
336 synchronized (image) {
337 graphics.drawOval(x - r, y - r, 2 * r, 2 * r);
338 graphics.fillOval(x - r, y - r, 2 * r, 2 * r);
340 panel.repaint(x - r, y - r, 2 * r + 1, 2 * r + 1);
344 * Dessine un triangle.
346 * Dessine un triangle défini par les coordonnées de ses sommets:
347 * (x1, y1), (x2, y2) et (x3, y3). Utilise la couleur de dessin
354 public void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
355 Polygon poly = new Polygon();
356 poly.addPoint(x1, y1);
357 poly.addPoint(x2, y2);
358 poly.addPoint(x3, y3);
359 synchronized (image) {
360 graphics.drawPolygon(poly);
362 Rectangle bounds = poly.getBounds();
363 bounds.setSize(bounds.width + 1, bounds.height + 1);
364 panel.repaint(bounds);
368 * Dessine un triangle plein.
370 * Dessine un triangle plein défini par les coordonnées de ses
371 * sommets: (x1, y1), (x2, y2) et (x3, y3). Utilise la couleur de
377 public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
378 Polygon poly = new Polygon();
379 poly.addPoint(x1, y1);
380 poly.addPoint(x2, y2);
381 poly.addPoint(x3, y3);
382 synchronized (image) {
383 graphics.drawPolygon(poly);
384 graphics.fillPolygon(poly);
386 Rectangle bounds = poly.getBounds();
387 bounds.setSize(bounds.width + 1, bounds.height + 1);
388 panel.repaint(poly.getBounds());
394 * Écrit le texte text, aux coordonnées (x, y).
396 public void drawText(int x, int y, String text) {
397 synchronized (image) {
398 graphics.drawString(text, x, y);
400 panel.repaint(); // don't know how to calculate tighter bounding box
404 * Retourne la couleur d'un pixel.
406 * Retourne la couleur du pixel de coordonnées (x, y).
408 * @return couleur du pixel
410 * @see #setColor(int)
411 * @see #setBgColor(int)
413 public int getPointColor(int x, int y) {
414 return (x < 0 || y < 0 || x >= width || y >= height) ?
415 0 : image.getRGB(x, y) & 0x00ffffff;
419 * Attend l'appui sur un des boutons de la souris.
421 * @return vrai (true) si un bouton a été pressé
423 * @see #waitMousePress(long)
426 * @see #getMouseButton
428 public boolean waitMousePress() {
429 return waitMousePress(-1);
433 * Attend l'appui sur un des boutons de la souris.
435 * @param timeout temps maximal d'attente (millisecondes)
437 * @return vrai (true) si un bouton a été pressé
439 * @see #waitMousePress()
442 * @see #getMouseButton
444 public boolean waitMousePress(long timeout) {
445 boolean result = false;
446 synchronized (mouseLock) {
451 mouseLock.wait(timeout);
452 else // (timeout < 0)
455 catch (InterruptedException e) {
458 if (mouseEvent != null) {
459 mousePos.setLocation(mouseEvent.getPoint());
460 mouseButton = mouseEvent.getButton();
469 * Retourne la position (x) de la souris la dernière fois qu'un
470 * bouton a été pressé pendant l'appel à {@link #waitMousePress()}.
472 * @return position (x)
474 public int getMouseX() {
479 * Retourne la position (y) de la souris la dernière fois qu'un
480 * bouton a été pressé pendant l'appel à {@link #waitMousePress()}.
482 * @return position (y)
484 public int getMouseY() {
489 * Retourne le numéro du bouton de la souris pressé pendant
490 * le dernier appel à {@link #waitMousePress()}.
492 * @return numéro de bouton (1: gauche, 2: milieu, 3: droit)
494 public int getMouseButton() {
499 * Synchronise le contenu de la fenêtre.
501 * Pour des raisons d'efficacités, le résultat des fonctions de dessin
502 * n'est pas affiché immédiatement. L'appel à sync permet de
503 * synchroniser le contenu de la fenêtre. Autrement dit, cela bloque
504 * l'exécution du programme jusqu'à ce que le contenu de la fenêtre
508 // put an empty action on the event queue, and wait for its completion
510 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
511 public void run() { }
514 catch (Exception e) {
519 * Ferme la fenêtre graphique.
521 public void closeGraph() {
522 javax.swing.SwingUtilities.invokeLater(new Runnable() {
525 new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
526 Toolkit.getDefaultToolkit()
527 .getSystemEventQueue().postEvent(ev);
534 * Suspend l'exécution pendant un certain temps.
536 * @param secs temps d'attente en seconde
541 public static void sleep(long secs) {
543 Thread.sleep(secs * 1000);
545 catch (Exception e) {
550 * Suspend l'exécution pendant un certain temps.
552 * @param msecs temps d'attente en millisecondes
557 public static void msleep(long msecs) {
561 catch (Exception e) {
566 * Suspend l'exécution pendant un certain temps.
568 * @param usecs temps d'attente en microsecondes
573 public static void usleep(long usecs) {
575 Thread.sleep(usecs / 1000, (int)(usecs % 1000) * 1000);
577 catch (Exception e) {
581 /* PRIVATE STUFF FOLLOWS */
583 private static final Map<String, Color> colorMap;
586 Map<String, Color> m = new HashMap<String, Color>();
587 // From http://www.w3.org/TR/SVG/types.html#ColorKeywords
588 m.put("aliceblue", new Color(0x00f0f8ff));
589 m.put("antiquewhite", new Color(0x00faebd7));
590 m.put("aqua", new Color(0x0000ffff));
591 m.put("aquamarine", new Color(0x007fffd4));
592 m.put("azure", new Color(0x00f0ffff));
593 m.put("beige", new Color(0x00f5f5dc));
594 m.put("bisque", new Color(0x00ffe4c4));
595 m.put("black", new Color(0000000000));
596 m.put("blanchedalmond", new Color(0x00ffebcd));
597 m.put("blue", new Color(0x000000ff));
598 m.put("blueviolet", new Color(0x008a2be2));
599 m.put("brown", new Color(0x00a52a2a));
600 m.put("burlywood", new Color(0x00deb887));
601 m.put("cadetblue", new Color(0x005f9ea0));
602 m.put("chartreuse", new Color(0x007fff00));
603 m.put("chocolate", new Color(0x00d2691e));
604 m.put("coral", new Color(0x00ff7f50));
605 m.put("cornflowerblue", new Color(0x006495ed));
606 m.put("cornsilk", new Color(0x00fff8dc));
607 m.put("crimson", new Color(0x00dc143c));
608 m.put("cyan", new Color(0x0000ffff));
609 m.put("darkblue", new Color(0x0000008b));
610 m.put("darkcyan", new Color(0x00008b8b));
611 m.put("darkgoldenrod", new Color(0x00b8860b));
612 m.put("darkgray", new Color(0x00a9a9a9));
613 m.put("darkgreen", new Color(0x00006400));
614 m.put("darkgrey", new Color(0x00a9a9a9));
615 m.put("darkkhaki", new Color(0x00bdb76b));
616 m.put("darkmagenta", new Color(0x008b008b));
617 m.put("darkolivegreen", new Color(0x00556b2f));
618 m.put("darkorange", new Color(0x00ff8c00));
619 m.put("darkorchid", new Color(0x009932cc));
620 m.put("darkred", new Color(0x008b0000));
621 m.put("darksalmon", new Color(0x00e9967a));
622 m.put("darkseagreen", new Color(0x008fbc8f));
623 m.put("darkslateblue", new Color(0x00483d8b));
624 m.put("darkslategray", new Color(0x002f4f4f));
625 m.put("darkslategrey", new Color(0x002f4f4f));
626 m.put("darkturquoise", new Color(0x0000ced1));
627 m.put("darkviolet", new Color(0x009400d3));
628 m.put("deeppink", new Color(0x00ff1493));
629 m.put("deepskyblue", new Color(0x0000bfff));
630 m.put("dimgray", new Color(0x00696969));
631 m.put("dimgrey", new Color(0x00696969));
632 m.put("dodgerblue", new Color(0x001e90ff));
633 m.put("firebrick", new Color(0x00b22222));
634 m.put("floralwhite", new Color(0x00fffaf0));
635 m.put("forestgreen", new Color(0x00228b22));
636 m.put("fuchsia", new Color(0x00ff00ff));
637 m.put("gainsboro", new Color(0x00dcdcdc));
638 m.put("ghostwhite", new Color(0x00f8f8ff));
639 m.put("gold", new Color(0x00ffd700));
640 m.put("goldenrod", new Color(0x00daa520));
641 m.put("gray", new Color(0x00808080));
642 m.put("grey", new Color(0x00808080));
643 m.put("green", new Color(0x00008000));
644 m.put("greenyellow", new Color(0x00adff2f));
645 m.put("honeydew", new Color(0x00f0fff0));
646 m.put("hotpink", new Color(0x00ff69b4));
647 m.put("indianred", new Color(0x00cd5c5c));
648 m.put("indigo", new Color(0x004b0082));
649 m.put("ivory", new Color(0x00fffff0));
650 m.put("khaki", new Color(0x00f0e68c));
651 m.put("lavender", new Color(0x00e6e6fa));
652 m.put("lavenderblush", new Color(0x00fff0f5));
653 m.put("lawngreen", new Color(0x007cfc00));
654 m.put("lemonchiffon", new Color(0x00fffacd));
655 m.put("lightblue", new Color(0x00add8e6));
656 m.put("lightcoral", new Color(0x00f08080));
657 m.put("lightcyan", new Color(0x00e0ffff));
658 m.put("lightgoldenrodyellow", new Color(0x00fafad2));
659 m.put("lightgray", new Color(0x00d3d3d3));
660 m.put("lightgreen", new Color(0x0090ee90));
661 m.put("lightgrey", new Color(0x00d3d3d3));
662 m.put("lightpink", new Color(0x00ffb6c1));
663 m.put("lightsalmon", new Color(0x00ffa07a));
664 m.put("lightseagreen", new Color(0x0020b2aa));
665 m.put("lightskyblue", new Color(0x0087cefa));
666 m.put("lightslategray", new Color(0x00778899));
667 m.put("lightslategrey", new Color(0x00778899));
668 m.put("lightsteelblue", new Color(0x00b0c4de));
669 m.put("lightyellow", new Color(0x00ffffe0));
670 m.put("lime", new Color(0x0000ff00));
671 m.put("limegreen", new Color(0x0032cd32));
672 m.put("linen", new Color(0x00faf0e6));
673 m.put("magenta", new Color(0x00ff00ff));
674 m.put("maroon", new Color(0x00800000));
675 m.put("mediumaquamarine", new Color(0x0066cdaa));
676 m.put("mediumblue", new Color(0x000000cd));
677 m.put("mediumorchid", new Color(0x00ba55d3));
678 m.put("mediumpurple", new Color(0x009370db));
679 m.put("mediumseagreen", new Color(0x003cb371));
680 m.put("mediumslateblue", new Color(0x007b68ee));
681 m.put("mediumspringgreen", new Color(0x0000fa9a));
682 m.put("mediumturquoise", new Color(0x0048d1cc));
683 m.put("mediumvioletred", new Color(0x00c71585));
684 m.put("midnightblue", new Color(0x00191970));
685 m.put("mintcream", new Color(0x00f5fffa));
686 m.put("mistyrose", new Color(0x00ffe4e1));
687 m.put("moccasin", new Color(0x00ffe4b5));
688 m.put("navajowhite", new Color(0x00ffdead));
689 m.put("navy", new Color(0x00000080));
690 m.put("oldlace", new Color(0x00fdf5e6));
691 m.put("olive", new Color(0x00808000));
692 m.put("olivedrab", new Color(0x006b8e23));
693 m.put("orange", new Color(0x00ffa500));
694 m.put("orangered", new Color(0x00ff4500));
695 m.put("orchid", new Color(0x00da70d6));
696 m.put("palegoldenrod", new Color(0x00eee8aa));
697 m.put("palegreen", new Color(0x0098fb98));
698 m.put("paleturquoise", new Color(0x00afeeee));
699 m.put("palevioletred", new Color(0x00db7093));
700 m.put("papayawhip", new Color(0x00ffefd5));
701 m.put("peachpuff", new Color(0x00ffdab9));
702 m.put("peru", new Color(0x00cd853f));
703 m.put("pink", new Color(0x00ffc0cb));
704 m.put("plum", new Color(0x00dda0dd));
705 m.put("powderblue", new Color(0x00b0e0e6));
706 m.put("purple", new Color(0x00800080));
707 m.put("red", new Color(0x00ff0000));
708 m.put("rosybrown", new Color(0x00bc8f8f));
709 m.put("royalblue", new Color(0x004169e1));
710 m.put("saddlebrown", new Color(0x008b4513));
711 m.put("salmon", new Color(0x00fa8072));
712 m.put("sandybrown", new Color(0x00f4a460));
713 m.put("seagreen", new Color(0x002e8b57));
714 m.put("seashell", new Color(0x00fff5ee));
715 m.put("sienna", new Color(0x00a0522d));
716 m.put("silver", new Color(0x00c0c0c0));
717 m.put("skyblue", new Color(0x0087ceeb));
718 m.put("slateblue", new Color(0x006a5acd));
719 m.put("slategray", new Color(0x00708090));
720 m.put("slategrey", new Color(0x00708090));
721 m.put("snow", new Color(0x00fffafa));
722 m.put("springgreen", new Color(0x0000ff7f));
723 m.put("steelblue", new Color(0x004682b4));
724 m.put("tan", new Color(0x00d2b48c));
725 m.put("teal", new Color(0x00008080));
726 m.put("thistle", new Color(0x00d8bfd8));
727 m.put("tomato", new Color(0x00ff6347));
728 m.put("turquoise", new Color(0x0040e0d0));
729 m.put("violet", new Color(0x00ee82ee));
730 m.put("wheat", new Color(0x00f5deb3));
731 m.put("white", new Color(0x00ffffff));
732 m.put("whitesmoke", new Color(0x00f5f5f5));
733 m.put("yellow", new Color(0x00ffff00));
734 m.put("yellowgreen", new Color(0x009acd32));
735 colorMap = Collections.unmodifiableMap(m);
738 private static int instances = 0;
740 private final String title; // window's title
741 private JFrame frame; // the frame (window)
742 private DWPanel panel; // the panel showing the image
743 private BufferedImage image; // the image we draw into
744 private Graphics2D graphics; // graphics associated with image
745 private Color bgColor; // background color, for clearGraph()
746 private boolean isClosed; // is the window closed ?
747 private Object mouseLock; // lock for mouse events
748 private MouseEvent mouseEvent; // last mouse event
749 private Point mousePos; // last mouse position
750 private int mouseButton; // last mouse click
752 // To be run on the Event Dispatching Thread
754 panel = new DWPanel();
755 frame = new JFrame(title);
758 frame.setResizable(false);
759 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
760 frame.addWindowListener(new DWWindowHandler());
761 frame.addKeyListener(new DWKeyHandler());
762 panel.addMouseListener(new DWMouseHandler());
763 frame.setLocationByPlatform(true);
764 frame.setVisible(true);
767 private class DWWindowHandler extends WindowAdapter {
768 public void windowOpened(WindowEvent ev) {
769 DrawingWindow w = DrawingWindow.this;
770 DrawingWindow.instances++;
774 public void windowClosed(WindowEvent ev) {
775 DrawingWindow w = DrawingWindow.this;
778 if (DrawingWindow.instances <= 0)
779 throw new AssertionError("Bad instance counter: " +
780 DrawingWindow.instances);
781 DrawingWindow.instances--;
782 if (DrawingWindow.instances == 0)
788 private class DWKeyHandler extends KeyAdapter {
789 public void keyPressed(KeyEvent ev) {
790 DrawingWindow w = DrawingWindow.this;
791 if (ev.getKeyCode() == KeyEvent.VK_ESCAPE) {
797 private class DWMouseHandler extends MouseAdapter {
798 public void mousePressed(MouseEvent ev) {
799 DrawingWindow w = DrawingWindow.this;
800 synchronized (w.mouseLock) {
802 mouseLock.notifyAll();
807 private class DWPanel extends JPanel {
809 DrawingWindow w = DrawingWindow.this;
810 Dimension dimension = new Dimension(w.width, w.height);
811 super.setMinimumSize(dimension);
812 super.setMaximumSize(dimension);
813 super.setPreferredSize(dimension);
816 public void paint(Graphics g) {
817 DrawingWindow w = DrawingWindow.this;
818 synchronized (w.image) {
819 g.drawImage(w.image, 0, 0, null);
823 private static final long serialVersionUID = 0;