COMP 110-003 Fall 2008

Lab 5 Solution

Solution files: SmileyMain.java, UpgradedSmiley.java

  1. Step 1 asked you to set the variable smiley to be a new instance of UpgradedSmiley. This can be done with a single line of code inside of the initializeSmiley method:

        smiley = new UpgradedSmiley();

    Note that if you instead write this line:

        UpgradedSmiley smiley = new UpgradedSmiley(); // this is not what you want to do here

    then the program will still give you a NullPointerException. The reason for this is that in the second line above, you will have declared a local variable named smiley and set it to a new instance of UpgradedSmiley. However, you were already given a variable named smiley. If you look deeper at the code in SmileyMain.java you will see that the variable smiley (the one that was already given to you) is used inside the method showSmiley. If you declare a local variable smiley inside the initializeSmiley and modify that variable, those changes will not be seen in the other methods in the SmileyMain class.

  2. Step 2 said to add the drawing code to the draw methods in UpgradedSmiley.java. The code for the drawFace method was already filled in for you. We can find the corresponding code for the other draw methods in Smiley.java from Lab 3. If you look at the paint method from that lab, you will see:

        public void paint(Graphics graphics)
        {
            // Draw face circle:
            graphics.setColor(Color.YELLOW);
            graphics.fillOval(X_FACE, Y_FACE, FACE_DIAMETER, FACE_DIAMETER);
            graphics.setColor(Color.BLACK);
            graphics.drawOval(X_FACE, Y_FACE, FACE_DIAMETER, FACE_DIAMETER);
    
            // Draw eyes:
            graphics.setColor(eyeColor);
            graphics.fillOval(X_RIGHT_EYE, Y_RIGHT_EYE, EYE_WIDTH, EYE_HEIGHT);
            graphics.fillOval(X_LEFT_EYE, Y_LEFT_EYE, EYE_WIDTH, EYE_HEIGHT);
    
            // Draw nose:
            graphics.setColor(Color.BLACK);
            graphics.fillOval(xNose, Y_NOSE, noseDiameter, noseDiameter);
    
            // Draw mouth:
            graphics.setColor(Color.RED);
            graphics.drawArc(X_MOUTH, Y_MOUTH, MOUTH_WIDTH, MOUTH_HEIGHT,
                mouthStartAngle, MOUTH_DEGREES_SHOWN);
        }
    

    You had to copy the code from this method into the corresponding draw methods in the UpgradedSmiley class. This leads to this code (comments omitted here, see solution .java files):

        private void drawNose(Graphics graphics)
        {
            graphics.setColor(Color.BLACK);
            graphics.fillOval(xNose, Y_NOSE, noseDiameter, noseDiameter);
        }
    
        private void drawMouth(Graphics graphics)
        {
            graphics.setColor(Color.RED);
            graphics.drawArc(X_MOUTH, Y_MOUTH, MOUTH_WIDTH, MOUTH_HEIGHT,
                mouthStartAngle, MOUTH_DEGREES_SHOWN);
        }
    
        private void drawEyes(Graphics graphics)
        {
            graphics.setColor(eyeColor);
            graphics.fillOval(X_RIGHT_EYE, Y_RIGHT_EYE, EYE_WIDTH, EYE_HEIGHT);
            graphics.fillOval(X_LEFT_EYE, Y_LEFT_EYE, EYE_WIDTH, EYE_HEIGHT);
        }
    
  3. Step 3 asked you to call the draw methods from the paintComponent method. Because the draw methods are in the same class as the paintComponent method, we do not need to specify any object to call the method on. When we call a method, it is assumed to be called on the current object. Also, note that the paintComponent method takes a variable of type Graphics as a parameter. Each of the draw methods also take a variable of type Graphics as a parameter. This means that you need to pass a variable of type Graphics to each of the draw methods. Inside the paintComponent method, you have access to one: the paintComponent method's single parameter, graphics. This leads to the following code which calls each of the draw methods from inside the paintComponent method:

        public void paintComponent(Graphics graphics)
        {
            super.paintComponent(graphics);
    
            // ::: CALL THE METHODS TO DRAW THE FACE, NOSE, EYES, AND MOUTH HERE
            drawFace(graphics);
            drawNose(graphics);
            drawEyes(graphics);
            drawMouth(graphics);
        }
    

  4. Step 4 said to ask the user how to change the smiley face, and to call the appropriate set methods on your instance of UpgradedSmiley to change the face. You were also given variables that you were to use in your code:

            String eyeColor = "black";
            int noseSize = 1;
            boolean shouldSmile = false;
    
            Scanner keyboard = new Scanner(System.in);
    

    We have read input from the user in other programs; this time around it is not any different. The only thing to make sure of was the Gotcha in the book about the next and nextLine methods. We can read the necessary input from the user as follows:

            // ::: PROMPT THE USER FOR INPUT AND READ INPUT HERE
            System.out.println("What eye color would you like? (red, green, or blue)");
            eyeColor = keyboard.next();
            System.out.println("How big would you like the nose? (1-4)");
            noseSize = keyboard.nextInt();
            System.out.println("Would you like the smiley to smile? (yes, no)");
            shouldSmile = (keyboard.next().equalsIgnoreCase("yes"));
    

    The last line above will read the next item from the input (keyboard.next()), then check if that input equals "yes" (ignoring case). Everything to the right of the = sign in this line of code is a Boolean expression -- its value is true if the string is "yes" and false otherwise. I did not specifically check for "no" here. shouldSmile is set to the value of the Boolean expression.

    Then, at the bottom of the initializeSmiley method, you had to call the set methods on your instance of UpgradedSmiley, smiley:

            // ::: CALL THE APPROPRIATE METHODS ON smiley TO SET THE
            //     EYE COLOR, NOSE SIZE, AND SMILING OR FROWNING MOUTH
            smiley.setEyeColor(eyeColor);
            smiley.setNoseSize(noseSize);
            smiley.setMouth(shouldSmile);
    

    Note that all of these methods are called on the smiley object. Note also that the arguments passed to each method match the types of the parameters of each method as specified in the UpgradedSmiley class.

  5. Step 5, the last step, asked you to fill in the set methods in UpgradedSmiley, noting that most of your code could come from your own Lab 3 assignment. It is important to make sure that the code that you put in each method does what the comments above each method say to do -- remember that the comments are also part of the interface that a programmer using the UpgradedSmiley class needs to know about. The comments tell the programmer what a method is supposed to do; the body of a method should follow the documentation.

    The setMouth method:

        public void setMouth(boolean smile)
        {
            if (smile)
                mouthStartAngle = 180;
            else
                mouthStartAngle = 0;
        }
    

    Note that the comments (in UpgradedSmiley.java) above the setMouth method say the smiley should smile if the parameter smile is true, and the smiley should frown if the parameter smile is false.

    The setEyeColor method:

        public void setEyeColor(String color)
        {
            if (color.equalsIgnoreCase("red"))
                eyeColor = Color.RED;
            else if (color.equalsIgnoreCase("green"))
                eyeColor = Color.GREEN;
            else if (color.equalsIgnoreCase("blue"))
                eyeColor = Color.BLUE;
            else
                eyeColor = Color.WHITE;
        }
    

    The setNoseSize method:

        public void setNoseSize(int size)
        {
            if ((size >= 1) && (size <= 4))
            {
                int center = xNose + noseDiameter / 2;
                noseDiameter *= size;
                xNose = center - noseDiameter / 2;
            }
        }
    

    The comments for setNoseSize were not specific about what to do if the size parameter was > 4 or < 1, so just about anything reasonable was accepted.