Programming Resources
For Fun and Learning
Charles Cusack
Computer Science
Hope College
main

Python
C++

JAVA


PHP
SQL
Assignments

SamplePicture


PicturePanel.java

/**
 * PicturePanel.java
 * Author: Chuck Cusack
 * Date: August 22, 2007
 * Version: 2.0
 * 
 * Modified August 22, 2008
 *
 * This class draws a picture of me.  The hair grows when the mouse is
 * clicked.  There is a 1% chance every click for a haircut.  If you
 * drag the head with the mouse, the whole picture moves.
 *
 * This class is really stupid, but it demonstrates how to do some drawing
 * using the Graphics object, how to handle mouse events, how to create
 * and use inner classes, how to use ArrayLists with generics, etc.
 *
 */
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;

/**
 * A class draws a picture on a panel
 *
 */
public class PicturePanel extends JPanel 
{
    // The width and height of the JPanel upon which things are drawn
    public static final int width = 400;
    public static final int height = 400;
    
    
    // The rest of the fields are specific to my implementation
    int numberClicks=1; // The number of times the mouse has been clicked since it was reset.
    int days=1;         // Total number of mouse clicks.
    Color Browns[]=new Color[4]; // An array of colors for the hair. To give it variation.

    int xCoordinate=0; // The x-coordinate where the mouse entered the window
    int yCoordinate=0; // The y-coordinate where the mouse entered the window

    ArrayList<HairLock> standardHair; // All of the short hair
    ArrayList<LongHairLock> longHair; // All of the long hair

    int originX=75;  // The center x-coordinate of the face.
    int originY=138; // the center y-coordinate of the face.
    // End of fields
    
    
    /**
     * Get stuff ready so when paintComponent is called, it can draw stuff.
     * Depending on how complicated you want to get, your constructor may be blank.
     */
    public PicturePanel() 
    {
        
        // If you want to handle mouse events, you will need the following
        // 3 lines of code.  Just leave them as is and modify the methods
        // with "mouse" in the name toward the end of the class.
        MouseHandler mh=new MouseHandler();
        addMouseListener(mh);
        addMouseMotionListener(mh);
        
        // Various shades of brown. Used for hair color.
        Browns[0]=new Color(50,50,0);
        Browns[1]=new Color(75,75,0);
        Browns[2]=new Color(100,100,0);
        Browns[3]=new Color(150,150,0);

        //Create Standard Haircut.
        // This simply creates some randomish locks of hair to cover the head with.
        // This list remains static once it is created.
        // When I get a haircut, the lonHairs are removed, but these remain.
        standardHair=new ArrayList<HairLock>();
         for(int i=-26;i<26;i+=2) {
             for(int j=0;j<20;j+=2) {
                 int theColor=(int) (Math.random()*4);
                 Color lockColor = Browns[theColor];
                 int x1=75 + i + (int) (Math.random()*4);
                 int y1=105 + (int) (Math.random()*6) + (i*i+j*j)/30;
                 int x2=x1+(int)(Math.random()*8)-4;
                 int y2=y1-6;
                 HairLock l = new HairLock(x1,y1,x2,y2,lockColor);
                 standardHair.add(l);
             }
         }

         // The longer hair.  Every day, more hair is added to this list.
        longHair=new ArrayList<LongHairLock>();
    }

    /**
     * This method is called whenever the applet needs to be drawn.
     * This is the most important method of this class, since without
     * it, we don't see anything.
     * 
     * This is the method where you will most likely do all of your coding.
     */
    public void paintComponent(Graphics g) 
    {
        // Always place this as the first line in paintComponent.
        super.paintComponent(g);
        
        // Translate the drawing according to where the new origin is.
        // The original origin is (75,138), so translation occures
        // relative to that point.
        // You will probably NOT need this line in your code.
        g.translate(originX-75,originY-138);
        
        // Draw the various parts of the screen.
        // I have separated the work of drawing into several methods so
        // it is easier to see what is going on.
        drawStuff(g);
        drawFace(g);
        drawStandardHair(g);
        drawLongHair(g);
    }

    /**
     * The method that draws the face
     * Notice that the Graphics object is passed to the method.
     * This is like passing a canvas to a friend and saying 
     * "Hey, can you paint something on this for me?"
     * Then you can take the canvas back and give it to someone
     * else so they can paint more stuff on it.
     */
    private void drawFace(Graphics g)
    {
        // Head
         g.setColor(new Color(240,240,100));
         g.fillOval(50,105,50,65);
         // Ears
         g.fillOval(45,130,10,16);
         g.fillOval(96,130,10,16);
         // Eyes
         g.setColor(Color.white);
         g.fillOval(55,130,16,10);
         g.fillOval(80,130,16,10);
         //Black part of eyes
         g.setColor(Color.black);
         g.fillOval(58,131,8,8);
         g.fillOval(83,131,8,8);
         // colored part of eyes
         g.setColor(new Color(0,150,0));
         g.fillOval(59,132,5,5);
         g.fillOval(84,132,5,5);
         
         //Mouth
         g.setColor(new Color(200,100,100));
         g.fillArc(65,152,20,5,160,220);
         //Nose
         g.setColor(new Color(200,200,80));
         g.fillArc(68,120,15,30,250,60);
         

    }
   /**
     * The method that draws the standard haircut.
     * It simply iterates through the list of hair
     * and asks each to draw itself.
     */
    private void drawStandardHair(Graphics g)
    {
        Color old=g.getColor();
        for(HairLock a: standardHair) {
            a.drawLock(g);
        }
        g.setColor(old);
    }    
    /** 
     * The method that draws the longer hair.
     * It simply iterates through the list of hair
     * and asks each to draw itself.
     */
    private void drawLongHair(Graphics g)
    {
        Color old=g.getColor();
        for(LongHairLock a: longHair) {
            a.drawLock(g);
        }
        g.setColor(old);
    }
    
    /**
     * A method to draw other stuff on the applet.
     * This is all of the text on the screen.
     */
    private void drawStuff(Graphics g)
    {
        // Change the font and color.
        g.setFont(new Font("Times Roman",Font.BOLD,24));
        g.setColor(Color.BLUE);
        
        g.drawString("Dr. Cusack",10,30);
        
        
        // Change color/font again.
        g.setColor(Color.BLACK);
        g.setFont(new Font("Times Roman",Font.PLAIN,12));

        // If numClocks is 0, a haircut occurred, so we inform the user.
        if(numberClicks==0) 
        {
            g.drawString("Haircut!",120,120);
        }

        g.drawString("Day "+days,120,150);
        g.drawString("Click the mouse button and the hair will grow",10,180);
        g.drawString("There is a 1% chance of a haircut each click",10,200);
        
        // Change the font and color
        g.setColor(new Color(50,150,100));
        g.setFont(new Font("Arial",Font.ITALIC,16));
        
        g.drawString("Mouse Entered at ("+xCoordinate+", "+yCoordinate+")",10,220);
        
        // Change the font and color
        g.setColor(new Color(.75f,.25f,.1f));
        g.setFont(new Font("Arial",Font.ITALIC,16));
        g.drawString("Drag the head around the screen",10,240);
        
    }

    /**
     * This method adds more hair of a given length
     * It adds about 52 locks of the given length.
     */
    private void addLocks(int length) 
    {
        for(int j=-26;j<26;j+=1) 
        {
            int x1=75 + (j) + (int) (Math.random()*4);
            int y1=105 + (int) (Math.random()*6) + (j*j)/30;
            int theColor=(int) (Math.random()*4);
            Color lockColor = Browns[theColor];
            LongHairLock a = new LongHairLock(x1,y1,length,lockColor);
            longHair.add(a);
        }
    }
    
    //------------------------------------------------------------------------------------------
    // HairLock class.  Stores 1 strand of straight hair of a given color.
    // Each hair is stored by the endpoints of a line.
    private class HairLock {
        int x1,y1, x2, y2;
        Color myColor;

        public HairLock(int x1,int y1,int x2,int y2,Color c) {
            this.x1=x1;
            this.y1=y1;
            this.x2=x2;
            this.y2=y2;
            myColor=c;
        }

        public void drawLock(Graphics g) {
            g.setColor(myColor);
            g.drawLine(x1,y1,x2,y2);
            
        }
    }
    //------------------------------------------------------------------------------------------
    // LongHairLock class.  Stores a longer "curvey" lock of hair.
    // Each hair is stored by a set of n points, and the hair is the polyline connected by the points.
    private class LongHairLock {
        int[] x;
        int[] y;
        int length;
        Color myColor;

        public LongHairLock(int xStart,int yStart, int length, Color c) {
            myColor=c;
            this.length=length;

            x=new int[length];
            y=new int[length];

            // (xStart,yStart) is the root of the hair.  The rest is random.
            x[0]=xStart;
            y[0]=yStart;
            // Attempting to create strands of hair that go in "normal"
            // directions.  That is, trying to make the hair look right.
        // Most of this code is trial-and-error, and it could be done
        // much better if I applied a little mathematics...
            for(int i=1;i<length;i++)
            {
                if(x[i-1]>100) {
                   x[i]=x[i-1] + (int) (Math.random()*17)-6;
                }
                else if(x[i-1]<50) {
                   x[i]=x[i-1] + (int) (Math.random()*17)-10;
                }
                else {
                   x[i]=x[i-1] + (int) (Math.random()*17)-8;
                }
                y[i]=y[i-1] - (int) (Math.random()*11)+3;
            }
        }

        public void drawLock(Graphics g) {
            g.setColor(myColor);
            g.drawPolyline(x,y,length);
        }
    } 
    //------------------------------------------------------------------------------------------
    /**
     * The main method, which allows us to run the application 
     * without using a webpage.  In other words, this is the method
     * that is called when you run a Java application. 
     */
    public static void main(String[] args) {  
        PicturePanel panel = new PicturePanel();
        JFrame theFrame = new JFrame();
        theFrame.setTitle("A Picture");
        
        // Place all of the graphical components on the main window
        Container cont=theFrame.getContentPane();
        cont.add(panel,BorderLayout.CENTER);
  
        // Finish setting up the main window
        theFrame.setBackground(Color.white);
        theFrame.pack(); 
        theFrame.setSize(new Dimension(width,height));
        theFrame.setVisible(true);         
        
        // Add window listener so it closes properly.
        theFrame.addWindowListener
        (
            new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            }
        );  
    }
    
     //---------------------------------------------------------------
    // A class to handle the mouse events for the applet.
    // This is one of several ways of handling mouse events.
    // Another is to make this class implement a MouseListener
    // interface.
    // There are advantages and disadvantages of doing each.
    //
    private class MouseHandler extends MouseAdapter implements MouseMotionListener
    {
        /**
         * Overridden from MouseAdapter
         * This grows hair or gives a haircut.
         */
        public void mouseClicked(MouseEvent e) 
        {
            // There is a  1% chance of a haircut each click
            if(Math.random()*101 > 99) {
                 numberClicks=0;
                 longHair.clear();
            } else { // Otherwise, the hair gets longer.
                 numberClicks++;
                 addLocks(numberClicks);
            }
            days++;
            // After making any changes that will affect the way the screen is drawn,
            // you have to call repaint.
            repaint();
        }

        /**
         * Overridden from MouseAdapter
         * Just updates the coordinates with where the mouse entered the window.
         * Stupid really, but it is just another example of how a mouse event can be handled.
         */
        public void mouseEntered(MouseEvent e)
        {
            xCoordinate = e.getX();
            yCoordinate = e.getY();
            // After making any changes that will affect the way the screen is drawn,
            // you have to call repaint.
            repaint();
        }
        /**
         * Three additional methods from the MouseAdapter class.
         * I don't use them, so when invoked, they don't do anything.
         */
        public void mouseExited(MouseEvent e) {
        }        
        public void mousePressed(MouseEvent e) {
        }        
        public void mouseReleased(MouseEvent e) {
        }
        
        
        /**
         * Implemented from the MouseMotionListener interface.
         * I don't want this to do anything, but I need to implement it.
         * (Every method of an interface needs to be implemented.)
         * So, I implement it doing nothing.
         */
        public void mouseMoved(MouseEvent e) {
        }

        /**
         * Implemented from the MouseMotionListener interface
         * This allows us to move the drawing around the screen.  Cool.
         */
        public void mouseDragged(MouseEvent e) {
            // Get the current position of the mouse.
            int x = e.getX();
            int y = e.getY();
            
            // If the mouse is over the head, then we want to move the origin to the
        // current (x,y) location of the mouse, so the head moves.
        // It turns out there is probably a better way to do this, but I am using
        // this method becuase it uses MouseMotionListener interface.  The other way uses
        // two methods from the MouseListener.  Can you figure it out?
            if(Math.sqrt(Math.pow(Math.abs(x-originX),2)+Math.pow(Math.abs(y-originY),2))<25) {
                originX=x;
                originY=y;
                // After making any changes that will affect the way the screen is drawn,
                // you have to call repaint.
                repaint();
            }
        }
    }
}