Leon Ma
Leon Ma

Reputation: 303

A Swing novice, want to make a small moving eyes Java GUI practice but stuck

I want to implement a panel that draws two eyes that moving to look up, to the center, or down depending on whether the mouse cursor is above, inside, or below the eyes. I first used this code to make the eyes:

public class EyesPanel extends JPanel implements ActionListener {
    // images
    public void paintComponent(Graphics g) {
        super.paintComponents(g);
        g.drawOval(130, 100, 120, 120);
        g.drawOval(250, 100, 120, 120);
        g.fillOval(175, y, 30, 30);   // x: 175  y: 145
        g.fillOval(295, y, 30, 30);   // x: 295  y: 145
    }

Eyes

And then is time to add event listener to make this class works, but here is the part I stuck. I know how to make graphics move (ActionListener) and I know how to implement MouseInputListener (extends MouseInputListener). However, combining those two together make me feel frustrated. Can anybody tell me how to do it, give me a sample code can be really helpful.

The following is my code so far, not a functioning and complete code:

public class EyesPanel extends JPanel implements ActionListener {
    private JPanel panel;
    private int y;
    private int dy;
    private Timer t;
    private Mouse move;

    public EyesPanel() {
        dy = 5;
        y = 145;

        // mouse detector
        this.addMouseListener(new Mouse());
        this.addMouseMotionListener(new Mouse());

        // Timer 
        t = new Timer(100, this);
    }

    // images
    public void paintComponent(Graphics g) {
        super.paintComponents(g);
        g.drawOval(130, 100, 120, 120);
        g.drawOval(250, 100, 120, 120);
        g.fillOval(175, y, 30, 30);   // x: 175  y: 145
        g.fillOval(295, y, 30, 30);   // x: 295  y: 145
    }

    public void actionPerformed(ActionEvent event) {
        moveDown();     //➜ not complete, don't know how to implement
    }

    // move up
    private void moveUp() {
        if (move.move() == 1) {
            t.start();
            y = y + dy;
            repaint();
        } else {
            t.stop();
        }
    }

    // move down
    private void moveDown() {
        if (move.move() == -1) {
            t.start();
            y = y - dy;
            repaint();
        } else {
            t.stop();
        }
    }
    // ➜ not complete, trying, but no clue
}

My mouse event class:

public class Mouse extends MouseInputAdapter {
    private int y;

    public void mouseEntered(MouseEvent event) {
        JPanel pane =  (JPanel) event.getSource();
        y = pane.getHeight();      // ➜ not complete
    }
}

Upvotes: 4

Views: 2767

Answers (3)

Gilbert Le Blanc
Gilbert Le Blanc

Reputation: 51557

The math for having the eyes follow the cursor is not that complicated.

Here's what my GUI looks like.

Moving Eyes

  1. I created an Eye class to hold the center of the outer eye socket and the center of the inner eyeball.

  2. I created a MovingEyes class to create the JFrame and a DrawingPanel class to draw the eyes on the DrawingPanel. I created the Eye array to hold 2 eyes in the constructor of the MovingEyes class.

  3. The paintComponent method of the DrawingPanel class does nothing but draw the eyes. The calculation of the center of the black eyeballs happens in another class. I created a couple of convenience methods so that I could draw a circle and fill a circle using the center point and radius.

  4. The EyeballListener class performs the calculation of the two black eyeballs. We compute the theta angle (in radians) for the line that extends from the center of the eye socket to the mouse pointer. Then, we compute the x and y position of the black eyeball using the theta angle and the eyeball distance.

Here's the code.

package com.ggl.testing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class MovingEyes implements Runnable {

    private static final int drawingWidth = 400;
    private static final int drawingHeight = 400;
    private static final int eyeballHeight = 150;
    private static final int eyeballWidthMargin = 125;
    private static final int eyeballOuterRadius = 50;
    private static final int eyeballInnerRadius = 20;

    private DrawingPanel drawingPanel;

    private Eye[] eyes;

    private JFrame frame;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new MovingEyes());
    }

    public MovingEyes() {
        this.eyes = new Eye[2];
        this.eyes[0] = new Eye(new Point(eyeballWidthMargin, eyeballHeight));
        this.eyes[1] = new Eye(new Point(drawingWidth - eyeballWidthMargin,
                eyeballHeight));
    }

    @Override
    public void run() {
        frame = new JFrame("Moving Eyes");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        drawingPanel = new DrawingPanel();
        frame.add(drawingPanel);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = -2977860217912678180L;

        public DrawingPanel() {
            this.addMouseMotionListener(new EyeballListener());
            this.setBackground(Color.WHITE);
            this.setPreferredSize(new Dimension(drawingWidth, drawingHeight));
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            g.setColor(Color.BLACK);

            for (Eye eye : eyes) {
                drawCircle(g, eye.getOrigin(), eyeballOuterRadius);
                fillCircle(g, eye.getEyeballOrigin(), eyeballInnerRadius);
            }
        }

        private void drawCircle(Graphics g, Point origin, int radius) {
            g.drawOval(origin.x - radius, origin.y - radius, radius + radius,
                    radius + radius);
        }

        private void fillCircle(Graphics g, Point origin, int radius) {
            g.fillOval(origin.x - radius, origin.y - radius, radius + radius,
                    radius + radius);
        }

    }

    public class Eye {
        private final Point origin;
        private Point eyeballOrigin;

        public Eye(Point origin) {
            this.origin = origin;
            this.eyeballOrigin = origin;
        }

        public Point getEyeballOrigin() {
            return eyeballOrigin;
        }

        public void setEyeballOrigin(Point eyeballOrigin) {
            this.eyeballOrigin = eyeballOrigin;
        }

        public Point getOrigin() {
            return origin;
        }

    }

    public class EyeballListener extends MouseMotionAdapter {

        private final double eyeballDistance = eyeballOuterRadius
                - eyeballInnerRadius - 5;

        @Override
        public void mouseMoved(MouseEvent event) {
            Point p = event.getPoint();
            for (Eye eye : eyes) {
                Point origin = eye.getOrigin();
                double theta = Math.atan2((double) (p.y - origin.y),
                        (double) (p.x - origin.x));
                int x = (int) Math.round(Math.cos(theta) * eyeballDistance)
                        + origin.x;
                int y = (int) Math.round(Math.sin(theta) * eyeballDistance)
                        + origin.y;
                eye.setEyeballOrigin(new Point(x, y));
            }

            drawingPanel.repaint();
        }

    }

}

Upvotes: 2

JRowan
JRowan

Reputation: 7114

make your class like this, and your gota take the s off super.paintComponents(g);

    import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;

import java.awt.event.MouseMotionListener;
import java.util.Timer;

import javax.swing.JPanel;


public class EyesPanel extends JPanel implements ActionListener,MouseMotionListener{
    private JPanel panel;
    private int y;
    private int dy;
    private Timer t;


    public EyesPanel() {
        dy = 5;
        y = 145;

        // mouse detector
        this.addMouseMotionListener(this);


        // Timer 

    }

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

        g.drawOval(130, 100, 120, 120);
        g.drawOval(250, 100, 120, 120);
        g.fillOval(175, y, 30, 30);   // x: 175  y: 145
        g.fillOval(295, y, 30, 30);   // x: 295  y: 145
    }



    // move up

    // ➜ not complete, trying, but no clue




@Override
public void actionPerformed(ActionEvent arg0) {
    // TODO Auto-generated method stub

}

    @Override
    public void mouseDragged(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseMoved(MouseEvent arg0) {
        // TODO Auto-generated method stub
        System.out.println(arg0.getY());
        if(arg0.getY() > 101 && arg0.getY() < 187)
        y = arg0.getY();
        repaint();

    }


}

Upvotes: 3

Olivier Gr&#233;goire
Olivier Gr&#233;goire

Reputation: 35467

You're looking for the method mouseMoved instead of mouseEntered.

Upvotes: 0

Related Questions