Drawing Demo Second Extension

What do computer programmers do? I wrote the first page as a visual aid, and used it when I spoke at Career Day at my daughter's school. It runs a simple drawing applet, and also shows the source code. Today's kids being pretty familiar with computers, they pointed out a bunch of features it was lacking. I decided to grow it into a set of pages, adding the requested features, and hopefully showing something of the development process. This is the second extension. It added a few more features, but there is certainly still room for more. Later on this page, I give links to follow for resources if you want to go further, and extend this program on your own.

Doodle is taken from the DoodlePad example in Exploring Java, by Patrick Niemeyer and Joshua Peck, first edition copyright 1996 by O'Reilly and Associates. It lets you draw with the mouse. Use the buttons to clear the picture, or to select other features.

You cannot run applets

/** Extended from the DoodlePad example in Exploring Java,
 * by Patrick Niemeyer and Joshua Peck,
 * First edition Copyright 1996 O'Reilly Publishing.
 * 

* Object-oriented shape drawing from OOPDraw2.java, * Written By: Sunit Katkar * E-Mail:sunitkatkar@hotmail.com * Home-Page : www.vidyut.com/sunit * Java Page : www.vidyut.com/sunit/JavaPage.html */ import java.awt.*; import java.applet.*; public class Doodle2 extends Applet { DrawingPad2 dPad; Button clearButton, biggerButton, smallerButton, undoButton; Checkbox writeHButton, writeVButton, drawButton, lineButton, rectangleButton, ovalButton, redButton, yellowButton, greenButton, blueButton; CheckboxGroup writeHVGroup = new CheckboxGroup (), colorsGroup = new CheckboxGroup (), modesGroup = new CheckboxGroup (); /** To run as an application, * construct it and show it in a frame. * This must be a static (class not instance) method, * because the instance won't exist until we construct it here. * When run as an applet, * the browser provides the frame, * and calls the constructor and init methods. */ public static void main (String []argv) { Doodle2 cd = new Doodle2 (); Frame ff = new Frame ("Doodle"); ff.setBounds (100, 100, 600, 300); ff.add (cd); cd.init (); ff.show (); } /** Make everything, * a drawing surface and some controls. */ public void init () { /* A big central drawing area and some controls on the edges */ setLayout (new BorderLayout ()); add ("Center", dPad = new DrawingPad2 ()); Panel np = new Panel (); np.setLayout (new GridLayout (0, 1)); np.add (clearButton = new Button ("Clear")); np.add (drawButton = new Checkbox ("draw")); drawButton.setCheckboxGroup (modesGroup); np.add (lineButton = new Checkbox ("line")); lineButton.setCheckboxGroup (modesGroup); np.add (ovalButton = new Checkbox ("oval")); ovalButton.setCheckboxGroup (modesGroup); np.add (rectangleButton = new Checkbox ("rectangle")); rectangleButton.setCheckboxGroup (modesGroup); /* Note set/getCurrent deprecated now set/getSelectedCheckbox */ modesGroup.setCurrent (drawButton); add ("West", np); Panel sp = new Panel (); sp.setLayout (new GridLayout (0, 1)); sp.add (biggerButton = new Button ("bigger")); sp.add (smallerButton = new Button ("smaller")); sp.add (writeHButton = new Checkbox ("Write Horiz")); writeHButton.setCheckboxGroup (writeHVGroup); sp.add (writeVButton = new Checkbox ("Write Vert")); writeVButton.setCheckboxGroup (writeHVGroup); writeHVGroup.setCurrent (writeHButton); sp.add (yellowButton = new Checkbox ("yellow")); yellowButton.setCheckboxGroup (colorsGroup); sp.add (redButton = new Checkbox ("red")); redButton.setCheckboxGroup (colorsGroup); sp.add (greenButton = new Checkbox ("green")); greenButton.setCheckboxGroup (colorsGroup); sp.add (blueButton = new Checkbox ("blue")); blueButton.setCheckboxGroup (colorsGroup); colorsGroup.setCurrent (blueButton); add ("East", sp); } /** Handle the button and say we did */ public boolean action (Event e, Object o) { if (e.target == clearButton) dPad.clear (); if (e.target == biggerButton) dPad.bigger (); if (e.target == smallerButton) dPad.smaller (); if ((e.target == redButton) && redButton.getState ()) dPad.setPaint (Color.red); if ((e.target == yellowButton) && yellowButton.getState ()) dPad.setPaint (Color.yellow); if ((e.target == greenButton) && greenButton.getState ()) dPad.setPaint (Color.green); if ((e.target == blueButton) && blueButton.getState ()) dPad.setPaint (Color.blue); if ((e.target == writeHButton) && writeHButton.getState ()) dPad.setHV (0); if ((e.target == writeVButton) && writeVButton.getState ()) dPad.setHV (1); if ((e.target == drawButton) && drawButton.getState ()) dPad.setMode (0); if ((e.target == lineButton) && lineButton.getState ()) dPad.setMode (1); if ((e.target == rectangleButton) && rectangleButton.getState ()) dPad.setMode (2); if ((e.target == ovalButton) && ovalButton.getState ()) dPad.setMode (3); /* Must requestFocus to get key strokes */ dPad.requestFocus (); return true; } } class DrawingPad2 extends Canvas { Image di; Graphics dg; int xpos, ypos, xold, yold; int mode = 0, hv = 0; DragShape2 dragShape = null; DrawingPad2 () { setBackground (Color.white); setForeground (Color.blue); } public void setPaint (Color fg) { dg.setColor (fg); } public void setMode (int m) { mode = m; } public void setHV (int m) { hv = m; } public boolean mouseDown (Event e, int x, int y) { switch (mode) { case 0: dragShape = null; break; case 1: dragShape = new DragLine2 (x, y); break; case 2: dragShape = new DragRect2 (x, y); break; case 3: dragShape = new DragOval2 (x, y); break; } xold = x; yold = y; return true; } public boolean mouseDrag (Event e, int x, int y) { if (dg == null) return false; /* Any current dragShape, * update it but do not draw it yet, * we do that in the paint method. */ if (null != dragShape) dragShape.setEnd (x, y); /* Direct drawing mode, * add another line segment to the offscreen image. */ else { xpos = x; ypos = y; dg.drawLine (xold, yold, xpos, ypos); xold=xpos; yold=ypos; } /* Either way we need a repaint */ repaint (); return true; } /* Any current dragShape, * update it one last time, * draw it into the offscreen image, * and get rid of it. */ public boolean mouseUp (Event e, int x, int y) { if (null != dragShape) { dragShape.setEnd (x, y); dragShape.draw (dg); dragShape = null; repaint (); } return true; } /** Prevent pre-clear since we fill whole space anyway */ public void update (Graphics g) { paint (g); } public void paint (Graphics g) { if (di == null) { di = createImage (size ().width, size ().height); dg = di.getGraphics (); } /* Everything from the accumulated offscreen image */ g.drawImage (di, 0, 0, null); /* Any current dragShape, * draw it to screen in current color. */ if (null != dragShape) { g.setColor (dg.getColor ()); dragShape.draw (g); } g.setColor (Color.black); g.drawRect (0, 0, size ().width-1, size ().height-1); } public void clear () { di.getGraphics ().clearRect (0, 0, size ().width, size ().height); repaint (); } /* There is no keyClick just Down and Up. * "Keypress:C:NN" * C is String [1] for the key character if defined else "?". * NN is String [2 or more] for the numeric key code, * high numbers > 1000 are control keys. */ public boolean keyDown (Event evt, int key) { if (dg == null) return false; if (key > 1000) return false; // System.out.println ("Keypress:"+String.valueOf ((char)key)+":"+String.valueOf (key)); String ks = String.valueOf ((char)key); FontMetrics fm = dg.getFontMetrics (); dg.drawString (ks, xold, yold); /* Advance either across or down */ if (0 == hv) xold += fm.stringWidth (ks); else yold += fm.getHeight (); repaint (); return true; } /** Must requestFocus to get key strokes */ public synchronized boolean mouseEnter (Event me, int x, int y) { requestFocus (); return true; } /** This **always** gives a newFont with getSize as requested, * but they may be displayed as the same size anyway. * and NOT change size on our Unix box, * although fine on a Windows/NT box. */ public void bigger () { changeFont (2); } public void smaller () { changeFont (-2); } void changeFont (int delta) { Component pcomp = getParent (); Font oldFont = getFont (); if ((null == oldFont) && (null != pcomp)) oldFont = pcomp.getFont (); if (null == oldFont) return; Font newFont = new Font (oldFont.getName (), oldFont.getStyle (), oldFont.getSize () + delta); /* Existing dg won't see it so tell them */ setFont (newFont); dg.setFont (newFont); } } /** There's no such shape as ''Shape'' * just as there's no such bird as ''Bird'' * but they all have some things in common... */ abstract class DragShape2 { int x = 0, y = 0, xx = 0, yy = 0; DragShape2 (int x, int y) { this.x = x; this.y = y; } public void setEnd (int xx, int yy) { this.xx = xx; this.yy = yy; } public abstract void draw (Graphics g) ; } class DragLine2 extends DragShape2 { DragLine2 (int x, int y) { super (x, y); } public void draw (Graphics g) { g.drawLine (x, y, xx, yy); } } class DragOval2 extends DragShape2 { DragOval2 (int x, int y) { super (x, y); } // All this jugglery because we do not want to draw oval // outside the applet area. Also we should be able to draw // the oval even if our starting point is at bottom right // and end point is at top left of the applet. Note that // top-left to top right is the positive x axis and top left // to left bottom is the positive y axis. public void draw (Graphics g) { int minx = Math.min (x, xx), miny = Math.min (y, yy), maxx = Math.max (x, xx), maxy = Math.max (y, yy); g.drawOval (minx, miny, maxx-minx, maxy-miny); } } class DragRect2 extends DragShape2 { DragRect2 (int x, int y) { super (x, y); } public void draw (Graphics g) { int minx = Math.min (x, xx), miny = Math.min (y, yy), maxx = Math.max (x, xx), maxy = Math.max (y, yy); g.drawRect (minx, miny, maxx-minx, maxy-miny); } }

Download the Doodle2 source code. Now what? You may want to experiment with further changes and additions. You can copy and then edit the source files, then compile them and run them on your machine. To do that, you need to get The Java Development Kit, a free download JDK for PC from Sun or JDK for Apple from Apple. Have fun! The SDK downloads provide installation instructions, documentation, and even tutorials, plus there is lots more to be found on the web. Also many fine books to choose from.

My Other Java..

Please also visit my home page.

Was this Helpful?

Was this Helpful? Suggestions? Was it what you were looking for? How did you find this page? Search result, following a link, recommendation? Please let me know. morris_hirsch@brown.edu

Legalities

This software is provided free of charge with no support. Email if you do have a problem, and I will try to help, but I cannot promise to.

Except as otherwise noted, this work is Copyright (C) 2000 by Morris Hirsch. All rights reserved, except as granted here.

Redistribution and use in source and binary forms, with or without modification, for any purpose, are permitted, except as may be restricted by original copyright holders, provided that the following conditions are met:

DISCLAIMER

This software is provided free of charge with no support.
This software is provided in source format; You are advised to examine it and understand it, before putting it to use.
This software uses only algorithms and coding techniques that are available to the public in the open literature. You are however, advised to make your own determination of legality, for your intended use.
This software is provided by the Author and Contributors ``AS IS'' and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose, are disclaimed.
In no event shall the Author or Contributors, or their Agents, be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.