简体   繁体   中英

mouse motion listener only in one direction

i have been working on mouse motion listener in Java couldn't sort it out completely because i want the object to move towards the direction where ever on the screen the mouse is pointed at but unforunately when the mouse is inside the applet window, the object moves only towards a single direction. Here is my code below..

import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.applet.*;
import java.awt.event.*;
import javax.swing.*;

public class MouseOver extends Applet implements KeyListener, MouseListener,
      MouseMotionListener {
   private int[] Xpoints = { 0, -5, 5 };
   private int[] Ypoints = { -10, -2, -2 };
   private double xpos, ypos;
   private Polygon poly;
   int polyrot = 0;
   private int width; // !! added
   private int height; // !! added

   public void init() {
      poly = new Polygon(Xpoints, Ypoints, Xpoints.length);
      addKeyListener(this);
      addMouseListener(this);
      addMouseMotionListener(this);
   }

   public void paint(Graphics g) {
      Graphics2D g2d = (Graphics2D) g;
      AffineTransform id = new AffineTransform();
      width = getSize().width;
      height = getSize().height;
      g2d.setColor(Color.BLACK);
      g2d.fillRect(0, 0, width, height);
      g2d.setColor(Color.RED);
      g2d.draw(poly);
      g2d.translate(width / 2, height / 2);
      g2d.rotate(Math.toRadians(polyrot));
      g2d.scale(5, 5);
   }

   public void keyReleased(KeyEvent k) {
   }

   public void keyTyped(KeyEvent k) {
   }

   public void keyPressed(KeyEvent k) {
      switch (k.getKeyCode()) {
      case KeyEvent.VK_LEFT:
         if (polyrot < 0) {
            polyrot = 359;
            polyrot++;
         }
         repaint();
         break;
      case KeyEvent.VK_RIGHT:
         if (polyrot > 360) {
            polyrot = 0;
            polyrot--;
         }
         repaint();
         break;
      }
   }

   public void mouseEntered(MouseEvent m) {
   }

   public void mouseExited(MouseEvent m) {
   }

   public void mouseReleased(MouseEvent m) {
   }

   public void mouseClicked(MouseEvent m) {
   }

   public void mousePressed(MouseEvent m) {
      switch (m.getButton()) {
      case MouseEvent.BUTTON1:
         if (polyrot < 0) {
            polyrot = 359;
            polyrot--;
         }
         repaint();
         break;
      case MouseEvent.BUTTON2:
         if (polyrot > 360) {
            polyrot = 0;
            polyrot++;
         }
         repaint();
         break;
      }
   }

   public void mouseMoved(MouseEvent e) {
      xpos = getX();
      if (xpos < 0) {
         polyrot--;
      } else if (xpos > 0) {
         polyrot++;
      }
      repaint();
      // !! break; // Doesn't belong here
   }

   @Override
   public void mouseDragged(MouseEvent e) {
      // You forgot this method
   }
}

Your problem is with this line:

public void mouseMoved(MouseEvent e){
 xpos=getX(); // ******
 if(xpos<0){polyrot--;}
 else if(xpos>0){polyrot++;}
 repaint();
 break;
}

That returns the x position of the applet not the mouse cursor. You need to use your MouseEvent object, e and instead get the mouse's position. Change it to:

xpos = e.getX();

Please don't ignore the comment that I made to your question. Please remember that we're volunteers who help on our free time. Please don't make it any more difficult than it has to be to help you.


I've tried to edit your code so that it compiles, and now is indented. Consider creating a Swing application, not an AWT application, since Swing apps are more flexible, powerful and robust.

There are a few things...

In your keyPressed and mousePressed events, are are only ever process the out of bounds conditions, for example...

if (polyrot < 0) {
    polyrot = 359;
    polyrot++;
}
//...
if (polyrot > 360) {
    polyrot = 0;
    polyrot--;
}

But you never process what it should do when it's within the acceptable bounds (0-359)...

Instead, you could simply add or subtract the amount from polyrot and allow the API to deal with it (surprisingly, it's capable for dealing with angles < 0 and > 359), for example...

public void mousePressed(MouseEvent m) {
    switch (m.getButton()) {
        case MouseEvent.BUTTON1:
            polyrot--;
            repaint();
            break;
        case MouseEvent.BUTTON2:
            polyrot++;
            repaint();
            break;
    }
}

Now, I'm not sure what you mean by "object to move towards the direction where ever on the screen the mouse is pointed" . Does this mean that the object should actually change it's x/y coordinates or should it just "look" at the mouse cursor...

Based on the fact that you actually have no movement code and you basically have the object painted in a fixed location, I'm assuming "look at"...

Basically, you need to know where the mouse is and where the object is, then determine the angle between them...

public void mouseMoved(MouseEvent e) {
    int x = width / 2;
    int y = height / 2;

    Point mousePoint = e.getPoint();

    int deltaX = mousePoint.x - x;
    int deltaY = mousePoint.y - y;

    polyrot = -Math.atan2(deltaX, deltaY);
    polyrot = Math.toDegrees(polyrot) + 180;

    repaint();
}

You should note that I changed 'polyrot' to 'double'

Your paint method is also wrong. Basically, you are painting your object BEFORE you've transformed it, instead, you should be using something more like...

g2d.translate(width / 2, height / 2);
g2d.rotate(Math.toRadians(polyrot));
g2d.draw(poly);

You should also be calling super.paint(g) before you apply you own custom painting...

As a side note, you should avoid overriding paint of top level containers, like JApplet , but instead, create a custom component, extending from something like JPanel and override it's paintComponent method, performing your custom painting there (don't forget to call super.paintComponent ). Take a look at Performing Custom Painting for more details

You should also avoid using KeyListener and instead use the Key Bindings API as it doesn't suffer from the same focus issues that KeyListener does...

Updated with runnable example

So I had a play around with code and produced this simple example...

在此处输入图片说明

Basically, I tossed out Polygon in favour of Path2D , basically because it provides much greater functionality and is easy to deal with when scaling ;)

import java.applet.Applet;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;

public class MouseOver extends Applet implements KeyListener, MouseListener,
                MouseMotionListener {

    private double xpos, ypos;
    private Path2D poly;
    private double polyrot = 0;
    private int width; // !! added
    private int height; // !! added

    public void init() {
        poly = new Path2D.Double();
        poly.moveTo(0, 10);
        poly.lineTo(5, 0);
        poly.lineTo(10, 10);
        poly.lineTo(0, 10);
        poly.closePath();
        addKeyListener(this);
        addMouseListener(this);
        addMouseMotionListener(this);
    }

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

        Graphics2D g2d = (Graphics2D) g;
        AffineTransform id = new AffineTransform();
        width = getSize().width;
        height = getSize().height;
        g2d.setColor(Color.BLACK);
        g2d.fillRect(0, 0, width, height);
        g2d.setColor(Color.RED);

        id.scale(5, 5);
        Shape scaled = poly.createTransformedShape(id);

        Rectangle bounds = scaled.getBounds();        
        g2d.translate((width - bounds.width) / 2, (height - bounds.height) / 2);
        g2d.rotate(Math.toRadians(polyrot), bounds.width / 2, bounds.height / 2);

        g2d.setStroke(new BasicStroke(5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));

        g2d.draw(scaled);
    }

    public void keyReleased(KeyEvent k) {
    }

    public void keyTyped(KeyEvent k) {
    }

    public void keyPressed(KeyEvent k) {
        switch (k.getKeyCode()) {
            case KeyEvent.VK_LEFT:
                polyrot++;
                repaint();
                break;
            case KeyEvent.VK_RIGHT:
                polyrot--;
                repaint();
                break;
        }
    }

    public void mouseEntered(MouseEvent m) {
    }

    public void mouseExited(MouseEvent m) {
    }

    public void mouseReleased(MouseEvent m) {
    }

    public void mouseClicked(MouseEvent m) {
    }

    public void mousePressed(MouseEvent m) {
        switch (m.getButton()) {
            case MouseEvent.BUTTON1:
                polyrot--;
                repaint();
                break;
            case MouseEvent.BUTTON2:
                polyrot++;
                repaint();
                break;
        }
    }

    public void mouseMoved(MouseEvent e) {
        int x = width / 2;
        int y = height / 2;

        Point mousePoint = e.getPoint();

        int deltaX = mousePoint.x - x;
        int deltaY = mousePoint.y - y;

        polyrot = -Math.atan2(deltaX, deltaY);
        polyrot = Math.toDegrees(polyrot) + 180;

        repaint();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // You forgot this method
    }
}

This:

  if (xpos < 0) {

means "if the cursor is outside of the panel".

This:

  xpos = getX();

does not get a mouse coordinate.

Change your event to something like this:

public void mouseMoved(MouseEvent e) {
    xpos = e.getX();
    if (xpos < getWidth() / 2) {
        polyrot--;
    } else {
        polyrot++;
    }
    repaint();
}

Now it rotates counter-clockwise if the cursor is on the left side of the panel and clockwise if the cursor is on the right side.

This:

  g2d.draw(poly);
  g2d.translate(width / 2, height / 2);
  g2d.rotate(Math.toRadians(polyrot));
  g2d.scale(5, 5);

will not do anything to change the image because you are doing your transforming after drawing it.

This:

  Graphics2D g2d = (Graphics2D) g;

is a bad idea because you are applying transforms to the global graphics context which would carry on to subsequent repaints of other components.

Change your paint to something like this:

public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g.create();
    width = getSize().width;
    height = getSize().height;
    g2d.setColor(Color.BLACK);
    g2d.fillRect(0, 0, width, height);
    g2d.translate(width / 2, height / 2);
    g2d.rotate(Math.toRadians(polyrot));
    g2d.scale(5, 5);
    g2d.setColor(Color.RED);
    g2d.draw(poly);
    g2d.dispose();
}

Further reading:

From here:

public void mouseMoved(MouseEvent e){
 xpos=getX();
 if(xpos<0){polyrot--;}
 else if(xpos>0){polyrot++;}
 repaint();
 break;
}

It seems you update only the xpos. You should update also the variable ypos. You might want to do it with something like this:

ypos=e.getY();
if (this.ypos<0){
 this.polyrot--;
}else if (this.ypos>0) {
 this.polyrot++;
}
this.repaint();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM