CIS 121 Friday March 3, 2000


Recall the example applet from Wednesday.



Let us again look at the source code.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

// The purpose of this applet is to draw the graph of the function
// f(x)=ax^2+bx+c.

// This applet will divide a 500x500 panel into two seperate panels. One
// panel will be a control panel where the user inputs the coefficients
// and clicks a button to have the graph drawn. The other panel will be
// a drawing area.

public class QuadraticGrapher extends Applet implements ActionListener {

// Since I want to be able to use the components in the method actionPerformed,
// I make the three components instance variables.

   TextField acoefficient;
   TextField bcoefficient;
   TextField ccoefficient;
   Button graph;

// I need to control the drawing region from the paint method so I also
// make it an instance variable.

   Panel graphRegion = new Panel(null);

   public QuadraticGrapher() {
// I want to be able to lay the two panels where I want them so I set the
// layout manager of this container to null.

      setLayout(null);

// For the control panel I use the flow layout.

      Panel controlPanel = new Panel(new FlowLayout());

// Since I am not using a layout manager in this container I must specify
// the location and size of the panels I place into it.

      graphRegion.setSize(500,300);
      graphRegion.setLocation(0,0);

// I now create three labels.

      Label a = new Label("a ");
      Label b = new Label("b ");
      Label c = new Label("c ");

// I now create the three text fields into which the user will place
// the coefficients.

      acoefficient = new TextField(5);
      bcoefficient = new TextField(5);
      ccoefficient = new TextField(5);

// I supply a default value into the text fields.

      acoefficient.setText("1");
      bcoefficient.setText("1");
      ccoefficient.setText("1");

// I now create a button the user will click to draw the graph.

      graph = new Button("Draw Graph");

// I must add an action listener to the button.

      graph.addActionListener(this);

// Since I have created all the components I want to place into
// the control panel I now add them one by one in the order they
// should appear in the panel.

      controlPanel.add(a);
      controlPanel.add(acoefficient);
      controlPanel.add(b);
      controlPanel.add(bcoefficient);
      controlPanel.add(c);
      controlPanel.add(ccoefficient);
      controlPanel.add(graph);

// Since I'm not using a layout manager in the container I must
// specify a location and size for the control panel.

      controlPanel.setSize(500,100);
      controlPanel.setLocation(0,300);

// I now add the two panels to the container.

      add(controlPanel);
      add(graphRegion);

   }

   public void actionPerformed(ActionEvent e) {
// When a button click is detected, an action event object is created and this method
// is called. In this method, we use the getSource method to see whether or not
// the component that caused the event to occur is the button graph. If it is, then
// we create a new Graphics object using the getGraphics method and call the paint
// method.

      if (e.getSource() == graph) {
         Graphics g = graphRegion.getGraphics();
         paint(g);
      }

   }

   public void paint(Graphics g) {
// In the paint method we first get the coefficients from the text fields.
// Since they are strings we must convert them to floats. We do this by
// using the valueOf method in the Float class to turn the strings into
// Float objects, and then use the floatValue method to get the float values
// and store them in the variables a, b, and c.
 
      int i;

      float a = Float.valueOf(acoefficient.getText()).floatValue();
      float b = Float.valueOf(bcoefficient.getText()).floatValue();
      float c = Float.valueOf(ccoefficient.getText()).floatValue();

// We now use the clearRect method from the Graphics class to clear the drawing
// area.

      g.clearRect(0,0,500,300);

// We now draw the axes in blue.

      g.setColor(Color.blue);

// In this for loop we draw the horizontal axis.

      for (i=0;i<499;i++) {
         g.fillRect(i,150,2,2);
      }

// In this for loop we draw the vertical axis.

      for (i=0;i<299;i++) {
         g.fillRect(250,i,2,2);
      }

// We now change the color to red to plot the points.
         
      g.setColor(Color.red);

// In order to plot the points on the graph, we begin at -500,
// divide by 100, so that the first x coordinate will be -5. We
// evaluate the function. In order for the point to be seen on the
// screen we multiply it by 100 cast it as an integer. We then plot
// the plot remembering that the reference point in a container is its
// upper left hand corner. So we have to translate the point so it is
// visible in our drawing area.

      for (i=-500;i<=500;i+=1) {
         float x=i/(100f);
         int y = (int)((a*x*x+b*x+c)*100);
         g.fillRect(i+250,150-y,2,2);

// When debugging an applet when using appletviewer it is helpful to use
// a print statement because it will display information at the prompt where we
// ran appletviewer.

         System.out.println(i + " " + y);
      }
   }

}


We also looked at another applet.



Let us look at the source code.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class ColorTester extends Applet implements ActionListener {
   TextField redComponent;
   TextField greenComponent;
   TextField blueComponent;
   TextField hexEquivalent;
   Button displayColor;
   Panel displayArea;

   public ColorTester() {
      setLayout(null);

      Panel controlPanel = new Panel(null);
      displayArea = new Panel(null);

      Label redLabel = new Label("Red ");
      Label greenLabel = new Label("Green ");
      Label blueLabel = new Label("Blue ");

      redLabel.setSize(30,20);
      greenLabel.setSize(40,20);
      blueLabel.setSize(30,20);

      redComponent = new TextField();
      greenComponent = new TextField();
      blueComponent = new TextField();

      hexEquivalent = new TextField();

      redComponent.setSize(30,20);
      greenComponent.setSize(30,20);
      blueComponent.setSize(30,20);

      redLabel.setLocation(20,50);
      redComponent.setLocation(60,50);
      greenLabel.setLocation(100,50);
      greenComponent.setLocation(150,50);
      blueLabel.setLocation(190,50);
      blueComponent.setLocation(230,50);

      hexEquivalent.setSize(100,20);
      hexEquivalent.setLocation(20,75);

      redComponent.setText("0");
      greenComponent.setText("0");
      blueComponent.setText("0");

      displayColor = new Button("Display Color");

      displayColor.setSize(100,20);
      displayColor.setLocation(270,50);

      controlPanel.add(redLabel);
      controlPanel.add(redComponent);
      controlPanel.add(greenLabel);
      controlPanel.add(greenComponent);
      controlPanel.add(blueLabel);
      controlPanel.add(blueComponent);

      controlPanel.add(displayColor);

      controlPanel.add(hexEquivalent);

      displayColor.addActionListener(this);

      controlPanel.setSize(500,100);
      controlPanel.setLocation(0,300);

      displayArea.setSize(500,300);
      displayArea.setLocation(0,0);

      add(displayArea);
      add(controlPanel);
   }

   private String toHex(int a) {
      String[] hex = {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};

      int first = a/16;
      int second = a-16*first;

      String firstChar=hex[first];
      String secondChar=hex[second];

      return(firstChar + secondChar);
   }
      

   public void actionPerformed(ActionEvent e) {
      if (e.getSource() == displayColor) {
         int red = (Integer.valueOf(redComponent.getText())).intValue();
         int green = (Integer.valueOf(greenComponent.getText())).intValue();
         int blue = (Integer.valueOf(blueComponent.getText())).intValue();

         System.out.println(red + " " + green + " " + blue);
         Color c = new Color(red,green,blue);

         displayArea.setBackground(c);

         String redEquiv = toHex(red);
         String greenEquiv = toHex(green);
         String blueEquiv = toHex(blue);

         hexEquivalent.setText(redEquiv + greenEquiv + blueEquiv);   
      }
   }

}


ColorTester.java

Applets are very different from applications because they don't control themselves. They are controlled by either the browser or the AppletViewer. You will see in examples of applets a call to the method repaint(); The method repaint will make a call to the paint method of the applet as soon as it can. So if we for example try to have a continuous loop occur in the start method in the applet, then repaint will not be able to make a call to paint because there is an infinite loop. Consider the following example. You will find on your X: drive in a directory called lynn files called DigitalClock.java and DigitalClock.html. Copy these to your c:\java directory and at the command prompt compile the program and run appletviewer. Recall that appletviewer must be given the name of the html file, not the java file. You may also download the files here.

  • DigitalClock.java

  • DigitalClock.html

    Notice that when we run this applet, nothing happens. The reason for this is that the web browser or applet viewer called the start method from the applet but was not able to regain control of the applet in order for repaint to call paint. Since we have an infinite loop, repaint will not have a chance to call paint. We must have a solution to this problem.

    The solution to the problem is a concept called Threads. Normally in the programs we have written we have a single sequential flow of control in our program that might have been interrupted if an exception occurred. This single sequential flow of control is called a thread. Since we want the applet to do something different than the browser we must make the applet and the browser run at the same time, that is give each process its own thread.

    Thread is an object found in the java.lang package. However since Java only support single inheritance we are not able to extend both Applet and Thread. To get around this problem we implement an interface called Runnable. An applet which implements runnable can be given its own thread. There are methods associated with Threads, some of the more important to us now are the start and stop methods. Once we create a new thread and start it the applet runs in its own thread in parallel to the web browser or appletviewer. The Runnable interface has only one method, run().

    The following applet implements the Runnable interface and creates a thread for the applet to run in.



    Let us look at the source code.

    import java.applet.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.util.*;
    
    public class DigitalClock2 extends Applet implements Runnable {
       Font font = new Font("Monospaced",Font.BOLD,16);
       int hours,mins,secs;
       Thread appletThread;
    
       public void init() {
          if (appletThread == null) {
             appletThread = new Thread(this);
             appletThread.start();
          }
       }   
    
       public void run() {
          while (true) {
             Calendar time = Calendar.getInstance();
    
             hours = time.get(Calendar.HOUR);
             mins = time.get(Calendar.MINUTE);
             secs = time.get(Calendar.SECOND);
    
             repaint();
    
             try {
                Thread.sleep(1000);
             } catch (InterruptedException i) {
                System.exit(1);
             }
          }
       }
    
       public void destroy() {
          if (appletThread != null) {
             appletThread.stop();
             appletThread = null;
          }
       }
    
       public void paint(Graphics g) {
          g.setFont(font);
          g.drawString(String.valueOf(hours) + ":" +
                       String.valueOf(mins) + ":" +
                       String.valueOf(secs),50,50);
       }
    }
    


    DigitalClock2.java

    We may also enhance this applet with components.



    Let us look at the source code.

    import java.applet.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.util.*;
    
    public class DigitalClock3 extends Applet implements Runnable,ActionListener {
       Font font = new Font("Monospaced",Font.BOLD,16);
       int hours,mins,secs;
       Thread appletThread;
       Panel drawingArea = new Panel(null);
       Button eastern = new Button("Eastern");
       Button central = new Button("Central");
       Button mountain = new Button("Mountain");
       Button pacific = new Button("Pacific");
       int adjustment = 0;
    
       public DigitalClock3() {
          setLayout(null);
    
          drawingArea.setSize(300,100);
          drawingArea.setLocation(0,0);
    
          Panel controlPanel = new Panel(new FlowLayout());
    
          controlPanel.add(pacific);
          controlPanel.add(mountain);
          controlPanel.add(central);
          controlPanel.add(eastern);
    
          pacific.addActionListener(this);
          mountain.addActionListener(this);
          central.addActionListener(this);
          eastern.addActionListener(this);
    
          controlPanel.setSize(300,100);
          controlPanel.setLocation(0,100);
    
          add(drawingArea);
          add(controlPanel);
       }
    
       public void init() {
          if (appletThread == null) {
             appletThread = new Thread(this);
             appletThread.start();
          }
       }   
    
       public void run() {
          while (true) {
             Calendar time = Calendar.getInstance();
    
             hours = time.get(Calendar.HOUR)+adjustment;
             mins = time.get(Calendar.MINUTE);
             secs = time.get(Calendar.SECOND);
    
             Graphics g = drawingArea.getGraphics();
    
             paint(g);
    
             try {
                Thread.sleep(1000);
             } catch (InterruptedException i) {
                System.exit(1);
             }
          }
       }
    
       public void destroy() {
          if (appletThread != null) {
             appletThread.stop();
             appletThread = null;
          }
       }
    
       public void paint(Graphics g) {
          g.clearRect(0,0,200,100);
          g.setFont(font);
          g.drawString(String.valueOf(hours) + ":" +
                       String.valueOf(mins) + ":" +
                       String.valueOf(secs),50,50);
       }
    
       public void actionPerformed(ActionEvent e) {
          if (e.getSource() == pacific) {
             adjustment = -2;
          }
          if (e.getSource() == mountain) {
             adjustment = -1;
          }
          if (e.getSource() == central) {
             adjustment = 0;
          }
          if (e.getSource() == eastern) {
             adjustment = 1;
          }
       }
    }
    


    DigitalClock3.java

    Let us consider a slightly more complicated example.

    The purpose of this example is to demonstrate how to draw an object on the screen and make it move. We create a figure and have it move either east, north, west or south, based on what the user chooses. When the figures hits a border an exception handler is called to display a message.



    Let us look at the source code.

    import java.awt.*;
    import java.awt.event.*;
    import java.applet.*;
    
    public class Walker extends Applet implements Runnable,ActionListener,ItemListener {
       int        scale=1;
       Panel      drawingArea = new Panel(null);
       Thread     appletThread;
       Button     north;
       Button     west;
       Button     south;
       Button     east;
       Panel      messageArea = new Panel(null);
       TextField  message = new TextField();
       String     direction="South";
       int        x = 250;
       int        y = 0;
       Choice     speedChoice = new Choice();
       int        speed = 5;
       TextField  directionArea;
    
       public class MyException extends Exception {
          public String message;
    
          public MyException(String s) {
             super(s);
    
             message = s;
          }
    
       }
    
       public Walker() {
          setLayout(null);
    
          drawingArea.setSize(500,200);
          drawingArea.setLocation(0,0);
    
          Panel controlPanel = new Panel(new FlowLayout());
    
          Font font = new Font("Sanserif",Font.BOLD,12);
    
          Label directionLabel = new Label("Direction ");
          directionLabel.setFont(font);
    
          directionArea = new TextField("South",10);
    
          controlPanel.add(directionLabel);
          controlPanel.add(directionArea);
    
          north = new Button("North");
          west = new Button("West");
          south = new Button("South");
          east = new Button("East");
    
          controlPanel.add(north);
          controlPanel.add(west);
          controlPanel.add(south);
          controlPanel.add(east);
    
          Label speedLabel = new Label(" Speed ");
          speedLabel.setFont(font);
          
          speedChoice.add("5");
          speedChoice.add("10");
          speedChoice.add("15");
          speedChoice.add("20");
          speedChoice.add("25");
          speedChoice.add("30");
          speedChoice.add("35");
          speedChoice.add("40");
          speedChoice.add("45");
          speedChoice.add("50");
    
          speedChoice.addItemListener(this);
    
          controlPanel.add(speedLabel);
          controlPanel.add(speedChoice);
    
          north.addActionListener(this);
          west.addActionListener(this);
          south.addActionListener(this);
          east.addActionListener(this);
    
          controlPanel.setSize(500,50);
          controlPanel.setLocation(0,200);
    
          message.setSize(490,30);
          message.setLocation(5,10);
    
          messageArea.add(message);
    
          messageArea.setSize(500,50);
          messageArea.setLocation(0,250);
    
          add(drawingArea);
          add(controlPanel);
          add(messageArea);
       }
    
       public void init() {
          setBackground(Color.white);
    
          if (appletThread == null) {
             appletThread = new Thread(this);
             appletThread.start();
          }
       }
    
       public void run() {
          Graphics g = drawingArea.getGraphics();
    
          while (true) {
             if (direction.equals("South")) {
                try {
                   y+=speed;
                   if ((y+40*scale)>=195) {
                      y-=speed;
                      throw new MyException("You can't go any farther South. Please choose another direction.");
                   }
                } catch (MyException exc) {
                   System.out.println("Hello");
                   message.setText(exc.message);
                }
                drawFigure(g,Color.white,x,y-speed);
                drawFigure(g,Color.black,x,y);
             }
             if (direction.equals("West")) {
                try {
                   x-=speed;
                   if ((x-20*scale)<=5) {
                      x+=speed;
                      throw new MyException("You can't go any farther West. Please choose another direction.");
                   }
                } catch (MyException exc) {
                   message.setText(exc.message);
                }
                drawFigure(g,Color.white,x+speed,y);
                drawFigure(g,Color.black,x,y);
             }
             if (direction.equals("North")) {
                try {
                   y-=speed;
                   if (y<=5) {
                      y+=speed;
                      throw new MyException("You can't go any farther North. Please choose another direction.");
                   }
                } catch (MyException exc) {
                   message.setText(exc.message);
                }
                drawFigure(g,Color.white,x,y+speed);
                drawFigure(g,Color.black,x,y);
             }
             if (direction.equals("East")) {
                try {
                   x+=speed;
                   if ((x+20*scale)>=495) {
                      x-=speed;
                      throw new MyException("You can't go any farther East. Please choose another direction.");
                   }
                } catch (MyException exc) {
                   message.setText(exc.message);
                }
                drawFigure(g,Color.white,x-speed,y);
                drawFigure(g,Color.black,x,y);
             }
             try {
                Thread.sleep(1000);
             } catch (InterruptedException e) {
             }
          }
      
       }
    
       public void paint(Graphics g) {
       }
    
       public void drawFigure(Graphics g,Color c,int x,int y) {
          g.setColor(c);
          g.fillRect(x-10*scale,y,20*scale,10*scale);
          g.fillRect(x-scale,y+10*scale,2*scale,10*scale);
          g.fillRect(x-20*scale,y+20*scale,40*scale,2*scale);
          g.fillRect(x-20*scale,y+22*scale,2*scale,8*scale);
          g.fillRect(x+18*scale,y+22*scale,2*scale,8*scale);
          g.fillRect(x-16*scale,y+22*scale,32*scale,18*scale);
          g.fillRect(x-16*scale,y+40*scale,2*scale,10*scale);
          g.fillRect(x+14*scale,y+40*scale,2*scale,10*scale);
       }
    
       public void actionPerformed(ActionEvent e) {
          direction = e.getActionCommand();
          directionArea.setText(direction);
       }
    
       public void itemStateChanged(ItemEvent e) {
          if (e.getStateChange() == ItemEvent.SELECTED) { 
             speed = (Integer.valueOf((e.getItem().toString()))).intValue();
             System.out.println(speed);
          }
       }
    
    }
    


    Walker.java