【问题标题】:mouse motion listener only in one direction仅在一个方向上的鼠标运动侦听器
【发布时间】:2013-12-06 09:55:41
【问题描述】:

我一直在研究 Java 中的鼠标运动侦听器,但无法完全解决它,因为我希望对象朝着屏幕上鼠标指向的方向移动,但不幸的是,当鼠标位于小程序窗口内时,对象仅向一个方向移动。下面是我的代码..

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
   }
}

【问题讨论】:

  • 您的代码没有任何缩进,这让我们几乎无法阅读、理解和调试。请重新格式化您发布的代码,给它适当的缩进,通常每个块 3 个空格,并确保同一块上的所有代码处于相同的缩进级别。非常感谢您在这方面的合作,并可能会增加您获得体面和及时答复的机会。
  • 如果这是你对幽默的看法,那就太不受欢迎了。
  • 好吧,我不是在开玩笑。那么代码可以正确阅读我不知道你为什么感到困难?
  • 现在我希望它是什么预期的?
  • 我已尝试添加您遗漏的字段和变量,以便您的代码现在可以编译。我现在缩进了你的代码。同样,请记住,我们是志愿者,在此处寻求建议时,您应该努力使您的代码具有可展示性和可读性。

标签: java applet awt keylistener mouselistener


【解决方案1】:

从这里开始:

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

您似乎只更新了 xpos。您还应该更新变量 ypos。 你可能想这样做:

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

【讨论】:

    【解决方案2】:

    你的问题在于这一行:

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

    返回小程序的 x 位置而不是鼠标光标。您需要使用 MouseEvent 对象 e 来获取鼠标的位置。将其更改为:

    xpos = e.getX();
    

    请不要忽略我对您的问题所做的评论。请记住,我们是帮助我们空闲时间的志愿者。请不要让它变得比帮助你更困难。


    我已尝试编辑您的代码以使其编译,现在已缩进。考虑创建一个 Swing 应用程序,而不是 AWT 应用程序,因为 Swing 应用程序更加灵活、强大和健壮。

    【讨论】:

    • @Hovercraft..感谢您在没有理解您之前的意思时缩进道歉,您能告诉我如何使用 swing 来完成吗?
    【解决方案3】:

    有几件事...

    在您的 keyPressedmousePressed 事件中,仅处理越界条件,例如...

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

    但是当它在可接受的范围内 (0-359) 时,你永远不会处理它应该做什么......

    相反,您可以简单地从 polyrot 中添加或减去数量,并允许 API 处理它(令人惊讶的是,它能够处理角度 359),例如...

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

    现在,我不确定您所说的“对象向屏幕上鼠标指向的方向移动”是什么意思。这是否意味着对象实际上应该改变它的 x/y 坐标,或者它应该只是“看”鼠标光标...

    基于您实际上没有移动代码并且基本上将对象绘制在固定位置的事实,我假设“看”...

    基本上,你需要知道鼠标在哪里,物体在哪里,然后确定它们之间的角度……

    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();
    }
    

    你应该注意到我把 'polyrot' 改成了 'double'

    您的paint 方法也是错误的。基本上,您是在转换对象之前绘制对象,相反,您应该使用更像...的东西......

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

    在应用您自己的自定义绘画之前,您还应该致电 super.paint(g)...

    附带说明,您应该避免覆盖顶级容器的paint,例如JApplet,而是创建一个自定义组件,从JPanel 之类的东西扩展并覆盖它的paintComponent 方法,执行您的那里的自定义绘画(不要忘记致电super.paintComponent)。更多详情请关注Performing Custom Painting

    您还应该避免使用KeyListener,而是使用Key Bindings API,因为它不会遇到KeyListener 会遇到的相同焦点问题...

    更新了可运行的示例

    所以我尝试了一些代码并制作了这个简单的示例......

    基本上,我放弃了Polygon 支持Path2D,主要是因为它提供了更强大的功能并且在扩展时易于处理;)

    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
        }
    }
    

    【讨论】:

    • 谢谢它完成了,事实上我正在使用我膝上的键盘所以这是一个愚蠢的错误,我只需要将鼠标事件.BUTTON2 改为鼠标事件.BUTTON3
    • 至少你在进步!
    • 改正后我已经使用了paint方法。通过“对象向屏幕上鼠标指向的方向移动”意味着对象应该面向鼠标指针,这反过来意味着它的 x 和 y 坐标也会改变..
    • 我正在开发一款游戏,它是一款带有角色的平面游戏。因此,如果我需要任何帮助,我将不胜感激。无论如何,现在非常感谢!
    • 当前的鼠标移动代码应该做到这一点,但它也会将对象保持在屏幕中心...
    【解决方案4】:

    这个:

      if (xpos < 0) {
    

    表示“如果光标在面板之外”。

    这个:

      xpos = getX();
    

    没有获得鼠标坐标。

    把你的活动改成这样:

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

    现在如果光标在面板左侧,它会逆时针旋转,如果光标在右侧,它会顺时针旋转。

    这个:

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

    不会对图像进行任何更改,因为您在绘制后进行变换。

    这个:

      Graphics2D g2d = (Graphics2D) g;
    

    这是一个坏主意,因为您正在对全局图形上下文应用变换,这将继续对其他组件进行后续重绘。

    把你的颜料改成这样:

    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();
    }
    

    进一步阅读:

    【讨论】:

    • 非常感谢您
    • 你已经破坏了油漆链 - 但我不会责怪你,因为 OP 也这样做了 ;)
    • @MadProgrammer 你具体是什么意思?我知道我没有调用 super.paint 但我认为在这种特定情况下这并不重要,因为唯一要绘制的是形状。不是很好的形式,但它不会爆炸,IE 存在更大的问题,正如您指出的更好的计划是不使用 Applet。
    • @Radiodef Paint 是一个复杂的方法链,每个方法都建立在每个方法之上以产生最终效果。除了JApplet 不是双缓冲这一事实之外,paint 正在做很多你刚刚决定放弃的重要工作。即使没有组件,您也应该尽可能尝试调用super.paint,因为paint 正在做其他事情而不是绘制组件;)
    • @MadProgrammer 明白了。我一直认为这发生在组件之外。我也应该继续学习。 : / 谢谢。
    猜你喜欢
    • 2017-12-17
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-02
    • 1970-01-01
    • 2011-12-18
    • 2013-06-22
    相关资源
    最近更新 更多