【问题标题】:How can I resolve conflict between java mouse and keyboard events?如何解决java鼠标和键盘事件之间的冲突?
【发布时间】:2015-04-15 04:54:09
【问题描述】:

在运行 Java 1.7 的 Windows 8 系统上,我发现键事件干扰了鼠标事件。这是一个例子。这是一件愚蠢的事情,但它说明了在更复杂的环境中出现的问题。我发现一旦我按下一个键,我就不能 移动鼠标直到我松开按键。我不知道为什么这不起作用。

事实上,更多的实验表明这似乎根本不是 Java 问题 - 所以我不确定我应该在论坛中对这个问题做什么。

正如下面的 MadProgrammer 所说,这是一个键盘自动重复问题。实际上, 如果您按下一个键然后快速移动鼠标(在自动重复开始之前),您可以画一条短线。因此,来自自动重复的关键事件似乎阻止了鼠标在屏幕上的移动。这出现 在整个 Windows 界面中发生。例如,我使用辅助功能设置来关闭自动重复 - 所以在记事本中,例如,按住时键不再重复。但是,如果您按住某个键,鼠标仍然会锁定。即使不在记事本窗口中也会锁定。

显然这不是 Java 问题 - 我只是碰巧在这里注意到它。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

// Demo key/mouse event interference
// Pressing and holding any key, moving the mouse
// and releasing the key should draw a line.
// written by mcslattery - april 2015
public class KeyMouse extends JPanel {
    public static final int WID = 500;
    public static final int HT = 400;

    int x1,y1,x2,y2;
    boolean drawn = false;
    int mx,my;

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new KeyMouse()); f.pack();
        f.setVisible(true);
    }

    public KeyMouse() {
        super();
        setPreferredSize(new Dimension(WID, HT));
        addMouseMotionListener(new MseL());
        addKeyListener(new KeyL());
        setFocusable(true); requestFocus();
    }

    public void paintComponent(Graphics g) {
        g.setColor(Color.white);
        g.fillRect(0,0,WID,HT);
        if (drawn) {
            g.setColor(Color.black);
            g.drawLine(x1, y1, x2, y2);
        }   
    }

    class MseL extends MouseMotionAdapter {
        public void mouseMoved(MouseEvent e) {
            mx = e.getX(); my = e.getY();   
        }
    }

    class KeyL extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            x1 = mx; y1 = my;
            drawn = false;
            repaint();
        }

        public void keyReleased(KeyEvent e) {
            x2 = mx; y2 = my;
            drawn = true;
            repaint();
        }
    }
}

【问题讨论】:

    标签: java events


    【解决方案1】:

    问题不在于操作系统或 Java,而在于您对 keyPressed 工作原理的假设。

    当按键被按下时,会触发keyPressed事件,在特定操作系统延迟之后,它会触发重复事件,直到按键被释放,此时调用keyReleased

    这意味着……

    public void keyPressed(KeyEvent e) {
        x1 = mx;
        y1 = my;
        drawn = false;
        repaint();
    }
    

    不断更新x1y1 值以与当前鼠标位置相同...

    相反,添加一个标志,该标志可用于确定该键是否已被按下,如果它尚未设置起始值。释放时,重置标志,例如...

    private boolean pressed = false;
    
    public void keyPressed(KeyEvent e) {
        if (!pressed) {
            pressed = true;
            x1 = mx;
            y1 = my;
            drawn = false;
            repaint();
        }
    }
    
    public void keyReleased(KeyEvent e) {
        pressed = false;
    

    旁注:

    我不太适合你的paintComponent 方法...

    public void paintComponent(Graphics g) {
        g.setColor(Color.white);
        g.fillRect(0,0,WID,HT);
    

    三个主要原因...

    1. 组件可能不是WID 宽或HT
    2. 您可以在构造函数中使用setBackground(Color.WHITE)super.paintComponent(g) 来获得相同的结果,如果paintComponent 因某种原因发生更改,这通常会更安全
    3. 方法不需要是public,你永远不想让任何人调用它

    【讨论】:

    • 是的,keyPressed 不仅仅在按键被按下时被调用,这很愚蠢,但是 AWT 的创建者现在修复它为时已晚。
    • @immibis 我不认为 AWT 有这么大的问题,因为这就是操作系统消息传递的工作方式,并且可能应该,如果您在多行编辑器上按下向下箭头键会发生什么?你想必须不断地按住它吗?看起来很奇怪,但这就是它的工作方式:P
    • Win32 也会有同样的问题。有一个 WM_KEYDOWN 事件、一个 WM_KEYUP 事件和一个 WM_CHAR 事件。显然它应该在按键被按下时发送一个 WM_KEYDOWN 事件,在按键被释放时发送一个 WM_KEYUP 事件,并在中间发送任意数量的 WM_CHAR 事件。但相反,他们选择重复 WM_KEYDOWN... 现在他们无法修复它,因为太多依赖它。
    • 当然!我知道。这不是 Java 设计问题(正如 immibis 所述)
    • [我是新来的,不知何故只是切断了我之前的评论] 这是操作系统在按住键时提供了一个键盘频闪。您也可以通过关闭操作系统功能来克服这个问题 - 当然,键不会在编辑器中自动重复,......谢谢!我也很欣赏paintComponent() 上的cmets。这个问题出现在一个几乎所有东西都是手绘的游戏中,但我一定会考虑你的建议!
    猜你喜欢
    • 2016-05-05
    • 1970-01-01
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多