Chapter 15. Exercise Solutions For Previous Chapters

Table of Contents

Solutions to Java Exercises
Chess Applet with Parameters Solution
Images, Sound and Mouse! Solution
The Colour Chooser Applet Solution
The Updated Client/Server Application Solution
The Random Draw Thread Solution
The Image Loader Exercise Solution

Solutions to Java Exercises

Chess Applet with Parameters Solution

Here is the solution for Chapter 7, Java™ Applets - An Introduction in the section called “An Exercise For You! Passing parameters to an Applet.” The Exercise was to modify the Chess Applet, written earlier in the section called “ChessApplet - An Applet for you to try!” to:

  • Draw a rectangle around the outside of the board.

  • Accept a chess board single square size (in pixels) as a parameter called squareSize to the applet.

  • Accept a parameter firstSquare that sets either a black or white square first.

It should look like Figure 15.1, “The ChessSolution applet with a square Size of 2, 10, 20 with a reversal in starting colour”.

Figure 15.1. The ChessSolution applet with a square Size of 2, 10, 20 with a reversal in starting colour

The ChessSolution applet with a square Size of 2, 10, 20 with a reversal in starting colourThe ChessSolution applet with a square Size of 2, 10, 20 with a reversal in starting colourThe ChessSolution applet with a square Size of 2, 10, 20 with a reversal in starting colour

The Solution is at: ChessSolution.html and the source code is at: ChessSolution.java

  
// Chess board Exercise - source code
// by Derek Molloy 2000

import java.awt.Graphics;
import java.applet.Applet;
import java.awt.Color;			//must import the color class to use it!

public class ChessSolution extends Applet
{
	private boolean whiteFirst = true;
	private int squareSize = 20;

	public void init()
	{
		// try to read in the parameters from the HTML file

		String tempFirstSquare = this.getParameter("firstSquare");
		if (tempFirstSquare!=null)
		{
			if (tempFirstSquare.toLowerCase().equals("black")) this.whiteFirst = false;
			else this.whiteFirst = true;
		}
		String tempSquareSize = this.getParameter("squareSize");
		if (tempSquareSize!=null)
		{
			this.squareSize = (new Integer(tempSquareSize)).intValue();
		}
	}


	public void paint(Graphics g)
	{
		
		// this boolean is key to the solution, it must remember if the square is a black
		// or white square. The first square is black so it is set to true.

		boolean blackSquare = !this.whiteFirst;
		
		for (int y=0; y<8; y++) // for each row
		{
			for (int x=0; x<8; x++) // for each column
			{
				if (blackSquare) g.setColor(Color.black);  //if a blacksquare set the color black
				else g.setColor(Color.white); // otherwise set the colour white
				
				blackSquare = !blackSquare; // invert for the next square
				
				g.fillRect((x*squareSize ),(y*squareSize ),squareSize,squareSize);
				// fill the box with color
			}
			blackSquare = !blackSquare; // each row starts with a different colour!
		}
	}
	
	
}
  

Images, Sound and Mouse! Solution

Here is the solution for the section called “An Exercise for You. Images, Sound and Mouse!” in Chapter 8, Java™ Applets - Images and Audio The Exercise was to Write an applet that plays a sound and displays an image wherever you press the mouse on the applet. When the applet first starts it should display the image at (x,y) = (20,20). See Figure 15.2, “Mouse Exercise Applet” for an example of how the applet works.

Figure 15.2. Mouse Exercise Applet

Mouse Exercise Applet

You can see my solution working here - MouseSolution.html and the source code is at: MouseSolution.java


  // An Outline Application for Handling Mouse Events

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


  public class MouseSolution extends Applet implements MouseListener
  {
	
	private AudioClip theSound;
	private Image theImage;
	private int x,y;
	
	public void init()
	{
	  this.theSound = this.getAudioClip( this.getDocumentBase(), "start.wav" );
	  this.theImage = this.getImage( this.getDocumentBase(), "test.gif" );
	  this.addMouseListener(this);
	}
	
	public void mousePressed(MouseEvent e) {}
	public void mouseReleased(MouseEvent e) {}
	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
	public void mouseClicked(MouseEvent e) 
	{ 
	   this.theSound.play();
	   this.x = e.getX();
	   this.y = e.getY();
	   this.repaint();
	}
	
	public void paint(Graphics g)
	{
	   g.drawImage(theImage, this.x, this.y, this);
	}

  }
  

The Colour Chooser Applet Solution

Here is the solution for the exercise give in the section called “An Exercise For You. The Colour Chooser Applet” in Chapter 9, Java™ Graphical User Interface(GUI) Components. The Task Was: Write a Colour Chooser Applet that allows the user to choose a colour to be displayed, using the scrollbars or by entering the values directly. The applet should check that the user has not inputted invalid values. Figure 15.3, “The Colour Chooser Applet Exercise Solution” shows my user-interface and you can see it working here - ColorChooserApplet.html.

Figure 15.3. The Colour Chooser Applet Exercise Solution

The Colour Chooser Applet Exercise Solution

The source code is at: ColorChooserApplet.java and as below.

  
  // The Colour Chooser Applet Exercise

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


  public class ColorChooserApplet extends Applet implements ActionListener, AdjustmentListener
  {
	
	private Scrollbar rBar, gBar, bBar;
	private TextField rField, gField, bField;
	private ColorCanvas cs;
	
	public void init()
	{
	  //For the layout I used a 3x3 grid with the canvas and grid added to FlowLayout
	  Panel rightPanel = new Panel(new GridLayout(3,3));
	  
	  rightPanel.add(new Label("Red:"));
	  rBar = new Scrollbar(Scrollbar.HORIZONTAL, 128, 10, 0, 265);
	  rBar.addAdjustmentListener(this);
	  rightPanel.add(rBar);
	  rField = new TextField("128",10);
	  rField.addActionListener(this);
	  rightPanel.add(rField);

	  rightPanel.add(new Label("Green:"));
	  gBar = new Scrollbar(Scrollbar.HORIZONTAL, 128, 10, 0, 265);
	  gBar.addAdjustmentListener(this);
	  rightPanel.add(gBar);
	  gField = new TextField("128");
	  gField.addActionListener(this);
	  rightPanel.add(gField);

	  rightPanel.add(new Label("Blue:"));
	  bBar = new Scrollbar(Scrollbar.HORIZONTAL, 128, 10, 0, 265);
	  bBar.addAdjustmentListener(this);
	  rightPanel.add(bBar);
	  bField = new TextField("128");
	  bField.addActionListener(this);
	  rightPanel.add(bField);

	  cs = new ColorCanvas();
	  cs.setSize(100,100);
	  this.add(cs);
	  this.add(rightPanel);
	  this.updateColor();
	}

	// Since no invalid value is possible with the scrollbar error checking is not required.
	public void adjustmentValueChanged(AdjustmentEvent e) 
	{
	  rField.setText(new Integer(rBar.getValue()).toString());
	  gField.setText(new Integer(gBar.getValue()).toString());
	  bField.setText(new Integer(bBar.getValue()).toString());
	  this.updateColor();
	}

	//actionPerformed is a little complex as the user could type in values
	//>255 <0 or even enter an invalid string
	public void actionPerformed(ActionEvent e) 
	{
	  try
	  {
	    Integer rVal = new Integer(rField.getText());
	    Integer gVal = new Integer(gField.getText());
	    Integer bVal = new Integer(bField.getText());
	    int rValInt = rVal.intValue();
	    int gValInt = gVal.intValue();
	    int bValInt = bVal.intValue();

	    if(rValInt>=0 && rValInt<=255) rBar.setValue(rValInt);
		else throw(new NumberFormatException());
	    if(gValInt>=0 && gValInt<=255) gBar.setValue(gValInt);
		else throw(new NumberFormatException());
	    if(bValInt>=0 && bValInt<=255) bBar.setValue(bValInt);
		else throw(new NumberFormatException());
	  } 
	  catch (NumberFormatException nfe)
	  {
	    rField.setText(new Integer(rBar.getValue()).toString());
	    gField.setText(new Integer(gBar.getValue()).toString());
	    bField.setText(new Integer(bBar.getValue()).toString());
	  }
	  updateColor();
	}

	// I use the scrollbars as storage rather than states
	private void updateColor()
	{
	   Color c = new Color(rBar.getValue(), gBar.getValue(), bBar.getValue());
	   cs.updateColor(c);
	}
  }
  

  class ColorCanvas extends Canvas
  {
	private Color col;

	public void updateColor(Color c)
	{
	  this.col = c;
	  repaint();
	}

	public void paint(Graphics g)
	{
	  g.setColor(col);
	  g.fillRect(0,0,100,100);
	}
  }
  
  

The Updated Client/Server Application Solution

Task: This exercise in the section called “An Exercise For You. The Updated Client/Server Application” was to update the code for the client/server example in the section called “The TCP Client/Server” to do the following:

  • Change the port that the application works on 6060.
  • Allow the client to shutdown the server by sending the command "ShutDown".
  • Get the server to display (on the server) the hostname of the client that has sent any request and its local port number.

Hint: No hints, just get rid of that infinite loop!

See my application working below with the client in Figure 15.4, “My Date Client Exercise Solution” and the server in Figure 15.5, “My Date Server Exercise Solution”. I have run it twice in this case to show you that the client port is different every time that it connects.

Figure 15.4. My Date Client Exercise Solution

My Date Client Exercise Solution

Figure 15.5. My Date Server Exercise Solution

My Date Server Exercise Solution

The Source files are below and as in DateClient.java , DateServer.java , HandleConnection.java and DateTimeService.java .

  

 // The Date Client - The date client connects to the server, sends the "GetDate" command and
// waits for a response.
// by Derek Molloy

import java.net.*;
import java.io.*;
import java.util.*;

public class DateClient 
{

    private Socket socket = null;
    private ObjectOutputStream os = null;
    private ObjectInputStream is = null;

    // the constructor expects the IP address of the server - the port is fixed at 6060
    public DateClient(String serverIP) 
    {
	if (!connectToServer(serverIP)) 
        {
	   System.out.println("Cannot open socket connection...");            
	}
    }

    private boolean connectToServer(String serverIP) 
    {
	try  // open a new socket to port 6060 and create streams
        {
	   this.socket = new Socket(serverIP,6060);
	   this.os = new ObjectOutputStream(this.socket.getOutputStream());
	   this.is = new ObjectInputStream(this.socket.getInputStream());
	   System.out.print("Connected to Server\n");
	} 
        catch (Exception ex) 
        {
	  System.out.print("Failed to Connect to Server\n" + ex.toString());	
	  System.out.println(ex.toString());
	  return false;
	}
	return true;
    }

    private void getDate() 
    {
       String theDate;
       System.out.println("Sending GetDate Command:");
       this.send("GetDate");
       theDate = (String)receive();
       if (theDate != null)
       {
	  System.out.println("The Server's date is " + theDate);
       }
    }

   private void shutdown()
    {
       String response = new String();
       System.out.println("Sending Shutdown Command:");
       this.send("ShutDown");
       response = (String)receive();
       if (response != null)
       {
	  System.out.println("The Server said: " + response);
       }
    }
	
    // method to send a generic object.
    private void send(Object o) 
    {
	try 
        {
	   System.out.println("Sending " + o);
	   os.writeObject(o);
	   os.flush();
	} 
        catch (Exception ex) 
        {
	   System.out.println(ex.toString());
	}
    }

    // method to receive a generic object.
    private Object receive() 
    {
	Object o = null;
	try 
        {
	   o = is.readObject();
	} 
        catch (Exception ex) 
        {
	   System.out.println(ex.toString());
	}
	return o;
    }

    public static void main(String args[]) 
    {
	if(args.length>0)
	{
	   DateClient theApp = new DateClient(args[0]);
	   try
           {
              theApp.getDate();
		
	      theApp.shutdown();
 	   } 
           catch (Exception ex)
           {
	      System.out.println(ex.toString());
	   }
	}
	else
	{
	   System.out.println("Error: you must provide the IP of the server");
	   System.exit(1);
	}
	System.exit(0);
    }
}
 
  
  

// The DateServer - The server application that passes control to the Handle Connection
// by Derek Molloy

import java.net.*;
import java.io.*;

public class DateServer 
{
    public static void main(String args[]) 
    {
	boolean stillAlive = true;

        ServerSocket serverSocket = null;
        try 
        {
            serverSocket = new ServerSocket(6060);
            System.out.println("Server has started listening on port 6060");
        } 
        catch (IOException e) 
        {
            System.out.println("Error: Cannot listen on port 6060: " + e);
            System.exit(1);
        }
        while (stillAlive) // infinite loop - loops once for each client
        {
            Socket clientSocket = null;
            try 
            {
                clientSocket = serverSocket.accept(); //waits here (forever) until a client connects
                System.out.println("Server has just accepted socket connection from a client");
            } 
            catch (IOException e) 
            {
                System.out.println("Accept failed: 6060 " + e);
                break;
            }	

	    // Create the Handle Connection object - only create it
            HandleConnection con = new HandleConnection(clientSocket);

            if (con == null) //If it failed send and error message
            {
                try 
                {
                    ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
                    os.writeObject("error: Cannot open socket thread");
                    os.flush();
                    os.close();
                } 
                catch (Exception ex)  //failed to even send an error message
                {
                    System.out.println("Cannot send error back to client: 6060 " + ex);
                }
            }
            else { stillAlive = con.init(); } 
		// change to shutdown if con.init() returns false
        }
        try  // do not get here at the moment 
        {
            System.out.println("Closing server socket.");
            serverSocket.close();
        } 
        catch (IOException e) 
        {
            System.err.println("Could not close server socket. " + e.getMessage());
        }
    }
}

  
  

 // The Handle connection class - that deals will all client requests directly
// by Derek Molloy

import java.net.*;
import java.io.*;
import java.util.*;


public class HandleConnection
{

    private Socket clientSocket;			// Client socket object
    private ObjectInputStream is;			// Input stream
    private ObjectOutputStream os;			// Output stream
    private DateTimeService theDateService; 
    private boolean shutDownSet = false;
    private String hostname = "";
    private String portnumber = "";
    
    // The constructor for the connecton handler

    public HandleConnection(Socket clientSocket) 
    {
        this.clientSocket = clientSocket;

	//Get the client details
	
	InetAddress a = clientSocket.getInetAddress();
	this.hostname = a.getHostName();
	this.portnumber = "" + clientSocket.getPort();
	

        //Set up a service object to get the current date and time
        theDateService = new DateTimeService();
    }

    // The main execution method 

    public boolean init() 
    {
        String inputLine;

        try 
        {
            this.is = new ObjectInputStream(clientSocket.getInputStream());
            this.os = new ObjectOutputStream(clientSocket.getOutputStream());
            while (this.readCommand()) {}

         } 
         catch (IOException e) 
         {
                e.printStackTrace();
         }
	 if (shutDownSet == true) return false;
	 else return true;
    }

    // Receive and process incoming command from client socket 

    private boolean readCommand() 
    {
        String s = null;

	System.out.println("Just Received a command from: "+this.hostname+" at port:"+portnumber);

        try 
        {
            s = (String)is.readObject();
        } 
        catch (Exception e) 
        {
            s = null;
        }
        if (s == null) 
        {
            this.closeSocket();
            return false;
        }

        // invoke the appropriate function based on the command 
        if (s.equals("GetDate")) 
        { 
            this.getDate(); 
        }     
	else if(s.equals("ShutDown"))
	{
	    System.out.println("Received a shutdown command - shutting down server");
	    this.send("Received a shutdown command - shutting down server");
	    this.shutDownSet = true;
	    return false;
	}  
        else 
        { 
            this.sendError("Invalid command: " + s); 
        }
        return true;
    }

    private void getDate()	// uses the date service to get the date
    {        
        String currentDateTime = theDateService.getDateAndTime();
        this.send(currentDateTime);
    }


    // Send a message back through to the client socket as an Object
    private void send(Object o) 
    {
        try 
        {
            System.out.println("Sending " + o);
            this.os.writeObject(o);
            this.os.flush();
        } 
        catch (Exception ex) 
        {
            ex.printStackTrace();
        }
    }
    
    // Send a pre-formatted error message to the client 
    public void sendError(String msg) 
    {
        this.send("error:" + msg);	//remember a string IS-A object!
    }
    
    // Close the client socket 
    public void closeSocket()		//close the socket connection
    {
        try 
        {
            this.os.close();
            this.is.close();
            this.clientSocket.close();
        } 
        catch (Exception ex) 
        {
            System.err.println(ex.toString());
        }
    }

}
 
  
  

 // The DateTimeService class that provides the current date
// by Derek Molloy.

import java.util.*;

public class DateTimeService
{
   private Date theDate;

   //constructor gets the current date/time

   public DateTimeService()
   {
     this.theDate = new Date();
   }

   //method returns date/time as a formatted string

   public String getDateAndTime()
   {
     return "The date is:" + this.theDate.toString();	
   }	
}
 
  

The Random Draw Thread Solution

Task: Write an applet that when you press the "start" button draws, and keeps drawing random coloured and sized filled ovals, as can be seen in Figure 15.6, “A Random Draw Thread Exercise Screen Capture - Solution.” until the "stop" button is pressed. The applet should only display one oval at a time at each loop of the thead. You can see my version here - RandomDrawThread.html

Figure 15.6. A Random Draw Thread Exercise Screen Capture - Solution.

A Random Draw Thread Exercise Screen Capture - Solution.

Hint: You can use the code from the section called “A Functional Canvas Example” to get you started.

Solution: My Solution is as below and in RandomDrawThread.java


  import java.awt.*;
  import java.awt.event.*;
  import java.applet.*;
	
	
  public class RandomDrawThread extends Applet implements ActionListener
  {
    MyCanvas c;
    Thread thePainter;
    Button theStart, theStop;
		
    public void init()
    {
	theStart = new Button("Start");
	theStart.addActionListener(this);
	theStop = new Button("Stop");
	theStop.addActionListener(this);


	c = new MyCanvas();
	thePainter = new Thread(c);	

	this.setLayout(new BorderLayout());
	Panel p = new Panel(new FlowLayout());
	p.add(theStart);
	p.add(theStop);
	this.add("North", p);
	this.add("Center",this.c);
    }

    public void actionPerformed(ActionEvent e)
    {
	  if (e.getSource().equals(theStart))
	  {
		thePainter.start();
	  }
	  else if (e.getSource().equals(theStop))
	  {
		c.stopDrawing();
	  }
    }
  }
	
	
  class MyCanvas extends Canvas implements Runnable
  {
     private boolean running = true;

     public void paint(Graphics g)
     {	
	   g.setColor(new Color((float)Math.random(),(float)Math.random(),(float)Math.random()));
	   g.fillOval((int)(Math.random()*400), (int)(Math.random()*400), 
		   (int)(Math.random()*200), (int)(Math.random()*200)); 
     }

     public void run() 
     {
	  while (running) 
	  {
	       this.repaint();
	       try 
	       { 
	         Thread.currentThread().sleep(100); 
	       } 
	       catch (InterruptedException e)
	       {  
	         System.out.println("Interupted!");
	       }
	  }
     }
	
     public void stopDrawing()
     {
	    this.running = false;
     }

  }

The Image Loader Exercise Solution

This is the exercise from the section called “ An Exercise for You. The Image Loader Application”.

Task: Write an Image Loader Application as shown in Figure 12.31, “The Image Loader Application”. The Toolbar should have two functions, Load Image and Close all Images. The Load Image should call up a file chooser as shown in Figure 12.32, “The Image Loader Application (with File Chooser open)”. The internal windows should display the name of the file, the image size and the size of the file from which it was loaded. The internal windows should be minimizable, maximizable, closable and iconifable. The main window should have a status label that displays details of the application as it runs.

Figure 15.7. The Image Loader Solution

The Image Loader Solution

Figure 15.8. The Image Loader Solution (with File Chooser)

The Image Loader Solution (with File Chooser)

Solution: My Solution is as below and in ImageLoaderApplication.java


   // Swing Image Loader Application Loader Application 
  // - Derek Molloy

  import javax.swing.*;
  import java.awt.*; 
  import java.awt.event.*;
  import java.io.*;
  import java.util.*;

  public class ImageLoaderApplication extends JFrame implements ActionListener
  {	
	private JToolBar theToolBar;
	private JButton loadButton, closeButton;
	private JDesktopPane desktop;
	private JLabel status;
	private Vector theFrames;

	public ImageLoaderApplication()
	{
		super("Image Loader Application");
		this.desktop = new JDesktopPane();		

		theToolBar = new JToolBar("Loader");
		loadButton = new JButton("Load Image",new ImageIcon("load.gif"));
		loadButton.addActionListener(this);
		closeButton = new JButton("Close All");
		closeButton.addActionListener(this);
		theToolBar.add(loadButton);
		theToolBar.add(closeButton);
		status = new JLabel();

		theFrames = new Vector();

		this.getContentPane().add("North", theToolBar);
		this.getContentPane().add("Center", desktop);
		this.getContentPane().add("South", status);
	
		this.setSize(400,400);	// set the size to 400 x 400
		this.show();		// display the frame
		this.setStatus("Application Started");
	}
	
	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource().equals(loadButton))
		{
			JFileChooser chooser = new JFileChooser();
			int returnVal = chooser.showOpenDialog(this);
    			if(returnVal == JFileChooser.APPROVE_OPTION) {
            			File f = chooser.getSelectedFile();
				ImageLoader imgldr = new ImageLoader(f);
				this.desktop.add(imgldr);
				this.theFrames.add(imgldr);
				this.setStatus("Loading Image "+f.getName());
    			}
		}
		if (e.getSource().equals(closeButton))
		{
		  int selected = JOptionPane.showConfirmDialog(this, 
			"This will close all Windows. Are you sure?", 
	           	"Confirmation Required", JOptionPane.YES_NO_CANCEL_OPTION,
	           	JOptionPane.INFORMATION_MESSAGE);
		  if (selected == JOptionPane.YES_OPTION)
		  {
			for (int i=0; i<theFrames.size(); i++)
			{
				ImageLoader imgldr = (ImageLoader) theFrames.elementAt(i);
				imgldr.destroy();
				theFrames.removeElementAt(i);
			}
			this.setStatus("Closed all images");
		  }
		  else { this.setStatus("Close All not confirmed"); }
		}
	}
	
	private void setStatus(String s)
	{
		this.status.setText("Status: "+s);
	}
	
	public static void main(String[] args)
	{
		new ImageLoaderApplication();
	}
  }


  class ImageLoader extends JInternalFrame
  {
	private String filename;
	private String directory;
	private Image theImage;
	private int width, height;
	private long fileLength;

	public ImageLoader(File f)
	{
		super(f.getName(), true, true, true, true);
		
		filename = f.getName();
		directory = f.getPath();	
		fileLength = f.length();	

	 	this.theImage = this.getToolkit().getImage(directory);
		JScrollPane scroll = new JScrollPane(new JLabel(new ImageIcon(this.theImage)));

		this.getContentPane().setLayout(new BorderLayout());
		this.getContentPane().add("North", new JLabel(filename));
		this.getContentPane().add("Center",scroll);
		
		width = this.theImage.getWidth(null);
		height = this.theImage.getHeight(null);
		String details = new String(" Details: Image Size("+width+","+height+") File Size "+fileLength+" bytes");
		this.getContentPane().add("South", new JLabel(details));
		
		this.setSize(300,300);
		this.show();	
	}

	public void destroy()
	{
		this.dispose();
	}
  }