July 24, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

A Simple Java Drawing Tool

  • August 28, 2001
  • By Yasir Minhas
  • Send Email »
  • More Articles »

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.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel