0

I need to set up a standard smiley face GUI where you can wink, blink, smile, and frown with JButtons. I need to do this with three separate classes: a class that draws the smiley face, a class with all my buttons and actionListeners that control the smiley face, and a class with the applet.

I keep getting NPE's on my buttons in the button class. I can't figure out why. Please go easy on me, I'm new to Java.

Here's my controls class:

public class SmileyControls extends JPanel implements ActionListener {

    Smiley smiley;

    JPanel controlPanel, eyePanel;
    JButton open, wink, shut; // make these an animation???? see loop chapter in text

    public SmileyControls(Smiley smileControl) {

        smiley = smileControl;
        controlLayout();
    }

    public void controlLayout() {

        eyePanel = new JPanel(new FlowLayout());
        open = new JButton("Open");
        wink = new JButton("Wink");
        shut = new JButton("Shut");

        open.addActionListener(this);
        wink.addActionListener(this);
        shut.addActionListener(this);

        eyePanel.add(open);
        eyePanel.add(wink);
        eyePanel.add(shut);
        add(eyePanel);
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if(e.getSource()==open){
            smiley.setEyeCondition(0);  // this calls the method setEyeCondition() from the smiley class that I created. I'm getting my NPE's here
        }
        if(e.getSource()==wink){
            smiley.setEyeCondition(1);  // and here
        }
        if(e.getSource()==shut){
            smiley.setEyeCondition(2);  // and here
        }
    }
}

Here's my smiley class:

public class Smiley extends JPanel {

    int locX, locY, height, width;
    Color moleColor;
    int eyeCondition;
    Graphics2D g2d;

    public Smiley(int x, int y, int w, int h) {

        locX = x;
        locY = y + 100; // needed to add 100 pixels to make room for hair
        height = h;
        width = w;

        moleColor = new Color(84,60,37);
        eyeCondition = 0;
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);

        g2d= (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

        setHair();
        setFace();
        setEyes();  // these methods paint the face
        setMole();
        setMouth();
    }

    // CONTROL METHODS

    public void setEyeCondition(int eye) {

        // the int values here are taken from the smileyControls class
        // I think they'd repaint my applet if it weren't for the NPE's

        if(eye == 0) {
            // draw eyes open
            g2d.fillOval(locX+width/5, locY+height/5,width/5, height/5); // left eye
            g2d.fillOval(locX+3*width/5, locY+height/5, width/5, height/5); // right eye
            repaint();
        } else if(eye == 1) {
            // draw wink
            g2d.fillRect(locX+width/5, locY+height/5,width/2, height/20); // left eye winking
            g2d.fillOval(locX+3*width/5, locY+height/5, width/5, height/5); // right eye open
            repaint();
        } else if(eye == 2) {
            // draw blink
            g2d.fillRect(locX+width/5, locY+height/5,width/2, height/20); // left eye blinking
            g2d.fillRect(locX+3*width/5, locY+height/5,width/2, height/20); // right eye blinking
            repaint();
        }
    }

    public void setEyes() { // this method paints the original eyes

        g2d.setColor(Color.black);
        g2d.fillOval(locX+width/5, locY+height/5,width/5, height/5); // left eye
        g2d.fillOval(locX+3*width/5, locY+height/5, width/5, height/5); // right eye
    }

}

And here's my applet:

public class SmileyApplet extends JApplet {

    Smiley smiley1;
    SmileyControls control1;

    JPanel container, smileyAndControls1, smileyAndControls2, smileyAndControls3;

    BorderLayout border;

    public void init() {

        border = new BorderLayout();
        setLayout(border);

        setUpContainer();

    }

    public void setUpContainer() {

        container = new JPanel(new FlowLayout());
        smileyAndControls1 = new JPanel(new FlowLayout());

        setUpControl();
        setUpSmiley();

        smiley1.setPreferredSize(new Dimension(450, 600));

        smileyAndControls1.add(control1);
        smileyAndControls1.add(smiley1);

        container.add(smileyAndControls1);  // add more controls to master container here

        add(container, BorderLayout.CENTER);
    }

    public void setUpSmiley() {

        smiley1 = new Smiley(0, 0, 400, 400);
        add(smiley1);
    }

    public void setUpControl() {

        control1 = new SmileyControls(smiley1);
    }

}
gprathour
  • 13,193
  • 5
  • 56
  • 85
Jake Doe
  • 35
  • 4

2 Answers2

0

At first you call setUpControl(), in there you create your SmileyControls and pass smiley1 to it (which is null at that time). After that you call setUpSmiley() which creates the instance of Smiley.

So you probably only have to call setUpSmiley() before you call setUpControl() and your problem should be solved.

Tom K
  • 321
  • 2
  • 9
  • That got rid of the NPE, thank you!! But now my buttons won't repaint the eyes. I'm thinking its because I'm painting in a method that's not paintComponent? – Jake Doe Jun 30 '17 at 08:01
0

Try changing the order of these lines, as you use your smiley1 variable before it gets its value:

    setUpControl(); // This uses smiley1
    setUpSmiley();  // This instantiates smiley1

EDIT

You should move the drawing to the paint*() methods, or methods called directly from them.

That is, your setEyeCondition() method should set a property on the smiley, and the drawing should go into your setEyes()method.

Usagi Miyamoto
  • 5,721
  • 1
  • 16
  • 28
  • That got rid of the NPE, thank you!! But now my buttons won't repaint the eyes. I'm thinking its because I'm painting in a method that's not paintComponent? – Jake Doe Jun 30 '17 at 08:01