防止robot.mouseMove 生成​​MouseEvent?

Posted

技术标签:

【中文标题】防止robot.mouseMove 生成​​MouseEvent?【英文标题】:Prevent robot.mouseMove to generate a MouseEvent? 【发布时间】:2013-09-23 18:45:40 【问题描述】:

我有一个 3D 游戏,每次移动光标时,我都希望它重置到中间。问题是 robot.mouseMove() 调用 MouseEvent (它确实有意义)并重置位置,所以我不能旋转。

谢谢!

【问题讨论】:

做不到。当您调用 Robot#mouseMove 时,它​​实际上是在调用操作系统以进行移动,这会将鼠标事件放入操作系统/系统队列中。但是,您可以做的是 raise 和 ignore 标志,它告诉您的侦听器忽略下一个鼠标移动事件并在下一个鼠标事件发生时或在发出 mouseMove 请求后将其重置,您需要对其进行测试 @MadProgrammer 听起来对我来说足够了 Answer @Cruncher 目前这是一个想法,我没有对其进行测试,并且不喜欢将未经测试的想法放入答案中;) 【参考方案1】:

我更喜欢如下代码:

component.removeMouseListener(...);
Robot.doSomething();
component.addMouseListener(...);

而不是设置标志。使用这种方法,管理侦听器的代码位于代码中的一个位置。

如果你使用一个标志,你需要

    定义标志变量, 设置/重置变量 测试变量

所以你最终会在课堂上的多个地方编写代码。

编辑:

关于将机器人添加到事件队列末尾的要点。因此,我将把将 MouseListener 添加回组件的代码包装在 SwingUtilities.invokeLater() 中

【讨论】:

谢谢,我明天试试(看起来可以)! 根据我的测试,我认为这行不通。问题是Robot事件被放置在队列中,在你重新连接鼠标监听器后会执行......【参考方案2】:

因为Robot 正在生成本机事件,该事件将(最终)进入事件队列以供 EDT 处理。

这意味着如果你尝试做类似...

removeMouseListener(...);
Robot.mouseMove(...);
addMouseListener(...);

它基本上不会有任何效果,因为鼠标监听器的移除和附加发生在事件处理的同一周期,这意味着机器人引发的鼠标事件不会被处理(或将出现)稍后在队列中)...

相反,您需要提出某种可以检测到的标志,然后忽略下一个传入事件...

if (!ignoreMouseMove) 
    ignoreMouseMove = true;
    // Do your normal processing...
    robot.mouseMove(...);
 else 
    ignoreMouseMove = false;

下面的基本示例检测鼠标移动到中心的距离并更新一个简单的position 变量(它基本上充当罗盘点)。这有助于说明运动,但更重要的是,我们正在打破事件循环......

import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Robot;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestMouseMove 

    public static void main(String[] args) 
        new TestMouseMove();
    

    public TestMouseMove() 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                try 
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                 catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) 
                    ex.printStackTrace();
                

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            
        );
    

    public class TestPane extends JPanel 

        private Robot bot;
        private int position = 0;

        public TestPane() 
            try 

                bot = new Robot();
                MouseAdapter ma = new MouseAdapter() 

                    boolean ignoreMouseMove = false;

                    @Override
                    public void mouseMoved(MouseEvent e) 
                        if (!ignoreMouseMove) 
                            ignoreMouseMove = true;
                            int x = getLocationOnScreen().x + (getWidth() / 2);
                            int y = getLocationOnScreen().y + (getHeight() / 2);

                            int distanceFromCenter = e.getPoint().x - (getWidth() / 2);
                            position += distanceFromCenter;
                            if (position < 0) 
                                position = 360 - position;
                             else if (position > 360) 
                                position -= 360;
                            
                            repaint();

                            bot.mouseMove(x, y);
                         else 
                            ignoreMouseMove = false;
                        
                    

                    @Override
                    public void mouseClicked(MouseEvent e) 
                        System.exit(0);
                    

                ;
                addMouseListener(ma);
                addMouseMotionListener(ma);
             catch (AWTException ex) 
                ex.printStackTrace();;
            
        

        @Override
        public Dimension getPreferredSize() 
            return new Dimension(200, 200);
        

        @Override
        protected void paintComponent(Graphics g) 
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            FontMetrics fm = g2d.getFontMetrics();

            int x = getWidth() / 2;
            int y = getHeight() / 2;

            int amount = position;

            while (x > 0) 
                if (amount == position) 
                    g2d.drawLine(x, y, x, y - 40);
                 else 
                    g2d.drawLine(x, y, x, y - 20);
                
                String text = Integer.toString(amount);
                g2d.drawString(text, x - (fm.stringWidth(text) / 2), y + fm.getHeight());
                x -= 20;
                amount--;
                if (amount < 0) 
                    amount = 360 + amount;
                
            
            amount = position + 1;
            x = (getWidth() / 2) + 20;
            while (x < getWidth()) 
                g2d.drawLine(x, y, x, y - 20);
                if (position > 360) 
                    position = 360 - position;
                
                String text = Integer.toString(amount);
                g2d.drawString(text, x - (fm.stringWidth(text) / 2), y + fm.getHeight());
                x += 20;
                amount++;
            

            g2d.dispose();
        
    

【讨论】:

【参考方案3】:

不幸的是,MadProgrammer 的回答并非在所有情况下都有效,因为:

可以在机器人之前获得一个实际的鼠标事件。这将导致您忽略实际的鼠标事件并处理机器人事件。您不能假设下一个事件将来自机器人,而这在实践中肯定会发生(有些罕见)。 还可以获取与机器人一起添加的实际 MouseEvent 数据。因此,这将导致您丢失您想要保留的部分实际鼠标移动。

更一致的答案是不要忽略鼠标事件,而是对其进行处理,然后减去您使用机器人移动的确切数量。这是jist:

public void mouseMoved(MouseEvent me)  
    mouseDiffX += me.getX() - mouseX;
    mouseDiffY += me.getY() - mouseY;
    mouseX = me.getX();
    mouseY = me.getY();
    absoluteX = me.getLocationOnScreen().x;
    absoluteY = me.getLocationOnScreen().y;
 

public void moveRobot()  
    int newX = canvas.getWidth() / 2 + canvas.getLocationOnScreen().x;
    int newY = canvas.getHeight() / 2 + canvas.getLocationOnScreen().y;
    robotMoveX = newX - absoluteX;
    robotMoveY = newY - absoluteY;
    robotMoved = true;


public void update()  
    if (robotMoved)  
        mouseDiffX -= robotMoveX;
        mouseDiffY -= robotMoveY;
        robotMoved = false;
    

    finalX += mouseDiffX;
    finalY += mouseDiffY;

【讨论】:

以上是关于防止robot.mouseMove 生成​​MouseEvent?的主要内容,如果未能解决你的问题,请参考以下文章

滑动时防止触摸启动

如何在Java桌面应用程序中停止无限循环以移动鼠标

[转] Mou一个Markdown工具

SDE and IDE signed MoU in Tel Aviv

如何防止 FxCop 分析自动生成的代码?

生成注册激活密钥时如何防止冲突?