Recently, while I was doodling with Java code, I wrote this simple tool for drawing basic geometric shapes. This tool is written using AWT components and elaborates features such as inner classes, event handling, polymorphism, and menu handling. In this article, we will step through the code chunk by chunk to build our simple drawing tool.
Step 1: An Empty Class Structure
First, we start with an empty class structure and we extend/inherit it from java.awt.Frame class. We set the frame’s title and size and make it visible.
//Title: A Simple Drawing Tool //Version: 1.0 //Copyright: Copyright (c) 2001 //Author: Yasir Feroze Minhas //Company: KAPS Computing (pvt) Ltd. //Description: This is a simple tool written using AWT for drawing basic shapes. package graph; import java.awt.*; public class SimpleDrawingTool extends Frame{ public SimpleDrawingTool() { //set frame's title super("Simple Drawing Tool"); //set frame size this.setSize(400, 400); //make this frame visible this.setVisible(true); } public static void main(String[] args) { SimpleDrawingTool simpleDrawingTool = new SimpleDrawingTool(); } }
Step 2: Adding Menus
Next, we attach a menu bar to our drawing tool and decorate it with the minimal required menu items.
//Title: A Simple Drawing Tool //Version: 1.0 //Copyright: Copyright (c) 2001 //Author: Yasir Feroze Minhas //Company: KAPS Computing (pvt) Ltd. //Description: This is a simple tool written using AWT for drawing basic shapes. package graph; import java.awt.*; public class SimpleDrawingTool extends Frame{ //constants for menu shortcuts private static final int kControlA = 65; private static final int kControlD = 68; private static final int kControlC = 67; private static final int kControlR = 82; private static final int kControlP = 80; private static final int kControlT = 84; private static final int kControlX = 88; public SimpleDrawingTool() { //set frame's title super("Simple Drawing Tool"); //add menu addMenu(); //set frame size this.setSize(400, 400); //make this frame visible this.setVisible(true); } public static void main(String[] args) { SimpleDrawingTool simpleDrawingTool = new SimpleDrawingTool(); } /** This method creates menu bar and menu items and then attach the menu bar with the frame of this drawing tool. */ private void addMenu() { //Add menu bar to our frame MenuBar menuBar = new MenuBar(); Menu file = new Menu("File"); Menu shape = new Menu("Shapes"); Menu about = new Menu("About"); //now add menu items to these Menu objects file.add(new MenuItem("Exit", new MenuShortcut(kControlX))); shape.add(new MenuItem("Rectangle", new MenuShortcut(kControlR))); shape.add(new MenuItem("Circle", new MenuShortcut(kControlC))); shape.add(new MenuItem("Triangle", new MenuShortcut(kControlT))); shape.add(new MenuItem("Polygon", new MenuShortcut(kControlP))); shape.add(new MenuItem("Draw Polygon", new MenuShortcut(kControlD))); about.add(new MenuItem("About", new MenuShortcut(kControlA))); //add menus to menubar menuBar.add(file); menuBar.add(shape); menuBar.add(about); //menuBar.setVisible(true); if(null == this.getMenuBar()) { this.setMenuBar(menuBar); } }//addMenu() }
Step 3: Adding Event Handlers
The menu bar is in place, and you can navigate different menus and menu items. But since they are not yet attached with any event handler, you can not do much more than navigation. Out next step is to add event handlers so we can trap user choices and act accordingly.
package graph; import java.awt.*; //import event package import java.awt.event.*; //import swing package for pop up message box import javax.swing.*; public class SimpleDrawingTool extends Frame{ ... private void addMenu() { ... file.add(new MenuItem("Exit", new MenuShortcut(kControlX))).addActionListener(new WindowHandler()); shape.add(new MenuItem("Rectangle", new MenuShortcut(kControlR))).addActionListener(new WindowHandler()); shape.add(new MenuItem("Circle", new MenuShortcut(kControlC))).addActionListener(new WindowHandler()); shape.add(new MenuItem("Triangle", new MenuShortcut(kControlT))).addActionListener(new WindowHandler()); shape.add(new MenuItem("Polygon", new MenuShortcut(kControlP))).addActionListener(new WindowHandler()); shape.add(new MenuItem("Draw Polygon", new MenuShortcut(kControlD))).addActionListener(new WindowHandler()); about.add(new MenuItem("About", new MenuShortcut(kControlA))).addActionListener(new WindowHandler()); ... } ... //Inner class to handle events private class WindowHandler extends WindowAdapter implements ActionListener { public void windowClosing(WindowEvent e) { System.exit(0); } public void actionPerformed(ActionEvent e) { System.out.println(e.getActionCommand()); //check to see if the action command is equal to exit if(e.getActionCommand().equalsIgnoreCase("exit")) { System.exit(0); } else if(e.getActionCommand().equalsIgnoreCase("About")) { JOptionPane.showMessageDialog(null, "This small freeware program is written by Yasir Feroze Minhas.", "About", JOptionPane.PLAIN_MESSAGE); } else { JOptionPane.showMessageDialog(null, "You asked for a "+e.getActionCommand(), "A Simple Drawing Tool", JOptionPane.PLAIN_MESSAGE); } }//actionPerformed() }//windowHandler - Inner Class ends here }
Step 4: Writing a Shapes Class
Now its time to write down our Shapes class. We define our Shapes class as abstract with one method, draw()
, and then extend it to concrete classes of Rectangle, Oval, Triangle, and Polygon. We then use polymorphism to draw different shapes depending upon the runtime object of the above concrete classes passed.
/** This is the abstract parent class for different shape classes, like rectangle, oval, polygon and triangle. It provides an abstract method draw(). */ package graph; import java.util.*; import java.awt.*; public abstract class Shapes { /**abstract method draw() @return void */ public abstract void draw(java.util.List list, Graphics g); } //different implementations of Shape class class RectangleShape extends Shapes { Point sPoint = null; Point ePoint = null; public void draw(java.util.List list, Graphics g) { Iterator it = list.iterator(); //if the list does not contain the required two points, return. if(list.size()<2) { return; } sPoint = (Point)it.next(); ePoint = (Point)it.next(); if(sPoint == null || ePoint == null) { return; } else { g.fillRect((int)sPoint.getX(), (int)sPoint.getY(), (int)(ePoint.getX()-sPoint.getX()), (int)(ePoint.getY()-sPoint.getY())); }//end of if list.clear(); }//end of draw for rectangle }//rectangle class OvalShape extends Shapes { Point sPoint = null; Point ePoint = null; public void draw(java.util.List list, Graphics g) { Iterator it = list.iterator(); //if the list does not contain the required two points, return. if(list.size()<2) { return; } sPoint = (Point)it.next(); ePoint = (Point)it.next(); if(sPoint == null || ePoint == null) { return; } else { g.fillOval((int)sPoint.getX(), (int)sPoint.getY(), (int)(ePoint.getX()-sPoint.getX()), (int)(ePoint.getY()-sPoint.getY())); }//end of if list.clear(); }//end of draw for Oval }//OvalShape class TriangleShape extends Shapes { public void draw(java.util.List list, Graphics g) { Point point = null; Iterator it = list.iterator(); //if the list does not contain the required two points, return. if(list.size()<3) { return; } Polygon p = new Polygon(); for(int i = 0; i < 3; i++) { point = (Point)it.next(); p.addPoint((int)point.getX(), (int)point.getY()); } g.fillPolygon(p); list.clear(); }//end of draw for Triangle }//Triangle class PolygonShape extends Shapes { public void draw(java.util.List list, Graphics g) { Point point = null; Iterator it = list.iterator(); //if the list does not contain the required two points, return. if(list.size()<3) { return; } Polygon p = new Polygon(); for(;it.hasNext();) { point = (Point)it.next(); p.addPoint((int)point.getX(), (int)point.getY()); } g.fillPolygon(p); list.clear(); }//end of draw for Polygon }//Polygon
Step 5: Add a Panel for Drawing Shapes and Write Proper Event Handlers
Now we add a panel to our simple drawing tool and rewrite our WindowHandler class so that it enables/disables menu selection and passes the corresponding Shapes object to panel for drawing. Here is a changed actionPerformed
method for the SimpleDrawingTool and DrawingPanel classes.
public void actionPerformed(ActionEvent e) { //check to see if the action command is equal to exit if(e.getActionCommand().equalsIgnoreCase("exit")) { System.exit(0); } else if(e.getActionCommand().equalsIgnoreCase("Rectangle")) { Menu menu = getMenuBar().getMenu(1); for(int i = 0;i < menu.getItemCount();menu.getItem(i).setEnabled(true),i++); getMenuBar().getShortcutMenuItem(new MenuShortcut(kControlR)).setEnabled(false); panel.drawShape(rectangle); } else if(e.getActionCommand().equalsIgnoreCase("Circle")) { Menu menu = getMenuBar().getMenu(1); for(int i = 0;i < menu.getItemCount();menu.getItem(i).setEnabled(true),i++); getMenuBar().getShortcutMenuItem(new MenuShortcut(kControlC)).setEnabled(false); panel.drawShape(oval); } else if(e.getActionCommand().equalsIgnoreCase("Triangle")) { Menu menu = getMenuBar().getMenu(1); for(int i = 0;i < menu.getItemCount();menu.getItem(i).setEnabled(true),i++); getMenuBar().getShortcutMenuItem(new MenuShortcut(kControlT)).setEnabled(false); panel.drawShape(triangle); } else if(e.getActionCommand().equalsIgnoreCase("Polygon")) { Menu menu = getMenuBar().getMenu(1); for(int i = 0;i < menu.getItemCount();menu.getItem(i).setEnabled(true),i++); getMenuBar().getShortcutMenuItem(new MenuShortcut(kControlP)).setEnabled(false); panel.drawShape(polygon); } else if(e.getActionCommand().equalsIgnoreCase("Draw Polygon")) { Menu menu = getMenuBar().getMenu(1); for(int i = 0;i < menu.getItemCount();menu.getItem(i).setEnabled(true),i++); getMenuBar().getShortcutMenuItem(new MenuShortcut(kControlP)).setEnabled(false); panel.repaint(); } else if(e.getActionCommand().equalsIgnoreCase("About")) { JOptionPane.showMessageDialog(null, "This small freeware program is written by Yasir Feroze Minhas.", "About", JOptionPane.PLAIN_MESSAGE); } }//actionPerformed() class DrawingPanel extends Panel implements MouseListener { private Point sPoint = null; private Point ePoint = null; private Shapes shape = null; private java.util.ArrayList list = new java.util.ArrayList(); //override panel paint method to draw shapes public void paint(Graphics g) { g.setColor(Color.green); shape.draw(list, g); } public void drawShape(Shapes shape) { this.shape = shape; } //define mouse handler public void mouseClicked(MouseEvent e) { //if user wants to draw triangle, call repaint after 3 clicks if(shape instanceof TriangleShape) { list.add(e.getPoint()); if(list.size() > 2) { repaint(); } } else if(shape instanceof PolygonShape) { list.add(e.getPoint()); } }//mouseClicked public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mousePressed(MouseEvent e) { sPoint = e.getPoint(); }//mousePressed public void mouseReleased(MouseEvent e) { ePoint = e.getPoint(); if(ePoint.getX() < sPoint.getX()) { Point temp = ePoint; ePoint = sPoint; sPoint = temp; } if(ePoint.getY() < sPoint.getY()) { int temp = (int)ePoint.getY(); ePoint.y = (int)sPoint.getY(); sPoint.y = temp; } if(shape instanceof RectangleShape || shape instanceof OvalShape) { list.clear(); list.add(sPoint); list.add(ePoint); repaint(); } }//mouseReleased }//DrawingPanel
Now we are done with our SimpleDrawingTool and can draw basic geometric shapes on its panel using a mouse. However, there are still some problems left in this code, and we will come back and revisit this code in the next release of SimpleDrawingTool and enhance it to include a fill color selection, and mouse movement tracing lines while drawing a shape object with better menu selection options.
Download
About the Author
Yasir Feroze Minhas is a principal software engineer with KAPS Computing Ltd. (Pakistan), currently
working on Enterprise Resource Planning systems.
Minhas has a B.S. in computer science from FAST ICS, Lahore, Pakistan.