Reputation: 303
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
}
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
Reputation: 51557
The math for having the eyes follow the cursor is not that complicated.
Here's what my GUI looks like.
I created an Eye class to hold the center of the outer eye socket and the center of the inner eyeball.
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.
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.
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
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
Reputation: 35467
You're looking for the method mouseMoved
instead of mouseEntered
.
Upvotes: 0