Java KeyListener停止工作 [英] Java KeyListener Stops Working

查看:62
本文介绍了Java KeyListener停止工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

-=更新=-

事实证明,问题不在于Java,而在于我的Apple键盘.按住字母键会弹出一个菜单,该菜单会破坏我的Java程序.通过禁用该菜单弹出窗口,我的KeyListener和我的键绑定都可以正常工作.谢谢大家的回答.

It turns out the issue was not with Java but with my Apple keyboard. Holding down a letter key brings up a menu that breaks my Java programs. By disabling that menu popup, my KeyListener and my Key Bindings both work as they should. Thank you all for your answers.

问题

我已经在Google和StackOverflow上搜索了对我的问题的答案,但无济于事.我发现的所有问题都有扩展JComponent,JFrame,JPanel等的主类,而不是Canvas.

I have searched on Google and on StackOverflow for an answer to my question, but to no avail. All of the questions that I've found have the main class extending JComponent, JFrame, JPanel, etc., and not Canvas.

现在我的问题是

我无法在程序运行时让我的Java KeyListener合作.当我启动程序时,一切正常.但是,当我开始按下按键并移动周围的东西(带有所述按键)时,该程序开始延迟并且需要更多时间来注册按键.突然之间,它们的KeyListener完全中断了,我也没有得到任何输入(即使keyPressed方法中的System.out.println语句也没有显示任何活动).我有三个与我的KeyListener无关的类.

I am having trouble getting my Java KeyListener to cooperate while my program runs. When I start my program, everything works as usual. However, as I start pressing keys and moving things around (with said keys), the program begins to delay and take more time for the key presses to register. All of a sudden, they KeyListener breaks altogether and I get no input (even a System.out.println statement in the keyPressed method shows no activity). I have three classes that have to do with my KeyListener in any way.

如果有帮助,此程序的目标是使用BufferedImage类绘制来自不同数学函数(如正弦波)的点.我已经发表过评论,没有成为Super-Comment-Man,但我会尽我所能.

If it helps, the goal of this program is to use BufferedImage class to plot points from different mathematical functions, like a sine wave. I have commented the best I can without being Super-Comment-Man, but I can clarify on the purpose of any code to the best of my ability.

首先,我的Screen类(使用BufferStrategy在JFrame上绘制内容):

First, my Screen class (draws stuff on the JFrame with a BufferStrategy):

package com.elek.waves.graphics;

import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;

import com.elek.waves.graphics.math.Controller;
import com.elek.waves.graphics.math.Graph;
import com.elek.waves.input.Keyboard;

/**
 * The engine of the entire Waves project. Processes the BufferedImage and puts the JFrame
 * on the screen. Uses other classes to calculate where to put pixels (what color each pixel
 * in the array should be) and get keyboard input.
 * 
 * @author my name
 * @version 1.0
 */
public class Screen extends Canvas {
    /**
     * Holds some *important* number that makes Java happy.
     */
    private static final long serialVersionUID = 1L;

    /**
     * Constant (and static) dimensions of the window.
     */
    public static final int WIDTH = 800, HEIGHT = 800;

    /**
     * Frame that will contain the BufferedImage and all its glory.
     */
    private JFrame frame;

    /**
     * BufferedImage processes the pixel array and translates it into fancy screen magic.
     */
    private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);

    /**
     * Holds color data for each pixel on the screen. Each pixel has an integer value equivalent
     * to the hexadecimal RGB value for whatever color this pixel is supposed to be.
     */
    private int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();

    /**
     * Graph object to draw the lines on.
     */
    private Graph graph;

    /**
     * Controller object to control the graph.
     */
    private Controller controller;

    /**
     * Keybaord object to use as a key-listener.
     */
    private Keyboard key;

    /* -- Constructor -- */

    /**
     * Creates a new Screen object. Initializes the JFrame object.
     */
    public Screen() {
        frame = new JFrame("Magic!");

        graph = new Graph(pixels);
        key = new Keyboard();

        controller = new Controller(key, graph);

        addKeyListener(key);
    }

    /* -- Methods -- */

    /**
     * Called once and only once by the main method. Repeatedly calls the update and render methods
     * until the program stops running.
     */
    private void start() {
        this.requestFocus();
        this.requestFocusInWindow();

        while (true) {
            update();
            render();
        }
    }

    /**
     * Called by the start method repeatedly. First, clears the screen of the previous image in
     * order to prevent ghost-imaging or blurring. Then, updates the pixel array to whatever it
     * needs to be for the next iteration of the render method.
     */
    private void update() {
        // Update the keyboard input
        key.update();

        // Update the controller
        controller.update();

        // Clean up the screen and then graph the line
        clearScreen();
        graph.drawWave();
    }

    /**
     * Called by the start method repeatedly. Draws the pixel array onto the JFrame using the
     * BufferedImage magic.
     */
    private void render() {
        // Initialize buffer strategies
        BufferStrategy bs = getBufferStrategy();

        if (bs == null) {
            createBufferStrategy(2);
            return;
        }

        // Physically update the actual pixels on the image
        Graphics g = (Graphics2D) bs.getDrawGraphics();
        g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
        g.dispose();
        bs.show();
    }

    /**
     * Clears the screen by setting every pixel in the pixel array to black. Used to prevent
     * ghost-images or blurring.
     */
    public void clearScreen() {
        for (int i = 0; i < pixels.length; i++)
            pixels[i] = 0;
    }

    /**
     * Main method to run the program. Creates a Screen object with a BufferedImage to display
     * pixels however the other classes decide to. All this does is set up the JFrame with the
     * proper parameters and properties to get it up and running.
     * 
     * @param   args    A String array of random arguments that Java requires or it gets fussy
     */
    public static void main(String[] args) {
        // Create Screen object
        Screen screen = new Screen();

        screen.frame.add(screen);
        screen.frame.pack();
        screen.frame.setSize(WIDTH, HEIGHT);
        screen.frame.setLocationRelativeTo(null);
        screen.frame.setResizable(false);
        screen.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        screen.frame.setVisible(true);

        screen.start();
    }
}

第二,我的Keyboard类(会断开的KeyListener):

Second, my Keyboard class (KeyListener that breaks):

package com.elek.waves.input;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

/**
 * Gets the user's key strokes and determines which keys are down at a given time.
 * 
 * @author my name
 * @version 1.0
 */
public class Keyboard implements KeyListener {
    /**
     * Holds the state of 120 keys (true if they're down, false if they're not).
     */
    private boolean[] keys = new boolean[120];

    /**
     * Holds the state of the "useful" keys (true if down, false if not).
     */
    public boolean w, a, s, d, up, down, left, right;

    /**
     * Determines if the "useful" keys are down or not. Sets the variables to true if they're down and
     * false if they're up.
     */
    public void update() {
        w = keys[KeyEvent.VK_W];
        a = keys[KeyEvent.VK_A];
        s = keys[KeyEvent.VK_S];
        d = keys[KeyEvent.VK_D];

        up = keys[KeyEvent.VK_UP];
        down = keys[KeyEvent.VK_DOWN];
        left = keys[KeyEvent.VK_LEFT];
        right = keys[KeyEvent.VK_RIGHT];
    }

    /**
     * Changes the state of the pressed key's corresponding boolean in the array to true.
     */
    public void keyPressed(KeyEvent e) {
        keys[e.getKeyCode()] = true;
    }

    /**
     * Changes the state of the pressed key's corresponding boolean in the array to false.
     */
    public void keyReleased(KeyEvent e) {
        keys[e.getKeyCode()] = false;
    }

    public void keyTyped(KeyEvent e) {
    }
}

第三,我的Controller类(使用KeyListener来控制程序):

Third, my Controller class (uses the KeyListener to control the program):

package com.elek.waves.graphics.math;

import com.elek.waves.input.Keyboard;

/**
 * Controls the graph's transformation properties (stretching and shifting). Directly changes the
 * transformation variables in the Graph class to achieve this.
 * 
 * @author my name
 * @version 1.0
 */
public class Controller {
    /**
     * Keyboard object to get the user's key-inputs.
     */
    private Keyboard input;

    /**
     * Graph object that this Controller will control.
     */
    private Graph graph;

    /* -- Constructor -- */

    /**
     * Create a new Controller object with the specific keyboard input parameter. 
     * <pre>Sets the starting parameters as the following:
     * Vertical Scale: 1
     * Horizontal Scale: 1
     * Vertical Shift = 0
     * Horizontal Shift = 0</pre>
     * 
     * @param   input   The Keybaord object from which the controller will get input
     */
    public Controller(Keyboard input, Graph parent) {
        // Initialize keybaord input and graph parent
        this.input = input;
        graph = parent;

        // Initialize transformation variables
        graph.vScale = 50;
        graph.hScale = 0.05;
        graph.vShift = 0;
        graph.hShift = 0;
    }

    /* -- Methods -- */

    /**
     * Updates the shifting of the graph (moving around) and the scaling of the graph (stretching)
     * from the keyboard input. <strong>WASD</strong> keys control shifting, and <strong>up, down, 
     * left, and right</strong> keys control stretching.
     */
    public void update() {
        // Update shifting
        if (input.w)        graph.vShift += 0.5;
        if (input.s)        graph.vShift -= 0.5;
        if (input.a)        graph.hShift -= 0.04;
        if (input.d)        graph.hShift += 0.04;

        // Update scaling
        if (input.up)       graph.vScale += 0.5;
        if (input.down)     graph.vScale -= 0.5;
        if (input.left)     graph.hScale += 0.0001;
        if (input.right)    graph.hScale -= 0.0001;
    }
}

我发现有几个有用的人说使用KeyBindings而不是KeyListener.但是,我过去曾经成功使用过KeyListener,并且希望在可能的情况下再次使其正常工作.如果绝对需要KeyBindings,我以为我可以进行切换,但是如果不是必需的话,我希望这样做.

I have found several helpful people saying to use KeyBindings as opposed to a KeyListener. However, I have used a KeyListener successfully in the past, and I'd like to get it to work again if possible. If KeyBindings are absolutely necessary, I supposed I can make the switch, but I'd prefer if that didn't have to be the case.

谢谢大家!

推荐答案

Canvas 将遭受与所有其他组件相同的问题,失去键盘焦点,这就是我们通常不这样做的原因t推荐 KeyListener .

Canvas will suffer the same issues that all the other components suffer from, loss of keyboard focus, this is why we generally don't recommend KeyListener.

首先,您需要使 Canvas 成为焦点,请参见

First you need to make the Canvas focusable, see Canvas#setFocusable

下一个更困难的问题是请求键盘焦点,您可以使用

The next, more difficult issue, is requesting keyboard focus, you can use Canvas#requestFocusInWindow but any component which requires keyboard focus will steal it.

根据您正在执行的操作,您可以将呼叫简单地放在更新循环中,但是您需要知道,如果要在同一窗口中询问用户的输入,将会遇到问题(画布抢了焦点)

Depending on what you are doing, you might be able to simply place the call in the update loop, but you need to be aware that if you want to ask input from the user, within the same window, you will have issues (with the canvas stealing the focus)

由于在键盘控制器中使用了数组,我的边界索引出现了一些问题,我改用了 Set ...

I had some issues with index of bounds due to the use of an array in the keyboard controller, which I switched over to Set instead...

public class Keyboard implements KeyListener {

    /**
     * Holds the state of 120 keys (true if they're down, false if they're
     * not).
     */

//private boolean [] keys = new boolean [120];

// private boolean[] keys = new boolean[120];

    /**
     * Holds the state of the "useful" keys (true if down, false if not).
     */
    private Set<Integer> keys;

    /**
     * Determines if the "useful" keys are down or not. Sets the variables
     * to true if they're down and false if they're up.
     */
    public void update() {
        
        keys = new HashSet<>(8);
    }
    
    public boolean isKeyPressed(int key) {
        return keys.contains(key);
    }
    
    public boolean isWPressed() {
        return isKeyPressed(KeyEvent.VK_W);
    }
    
    public boolean isAPressed() {
        return isKeyPressed(KeyEvent.VK_A);
    }
    
    public boolean isSPressed() {
        return isKeyPressed(KeyEvent.VK_S);
    }
    
    public boolean isDPressed() {
        return isKeyPressed(KeyEvent.VK_D);
    }

    public boolean isUpPressed() {
        return isKeyPressed(KeyEvent.VK_UP);
    }
    
    public boolean isDownPressed() {
        return isKeyPressed(KeyEvent.VK_DOWN);
    }
    
    public boolean isLeftPressed() {
        return isKeyPressed(KeyEvent.VK_LEFT);
    }
    
    public boolean isRightPressed() {
        return isKeyPressed(KeyEvent.VK_RIGHT);
    }
    /**
     * Changes the state of the pressed key's corresponding boolean in the
     * array to true.
     */
    public void keyPressed(KeyEvent e) {
        System.out.println("Pressed = " + e.getKeyCode());
        keys.add(e.getKeyCode());
    }

    /**
     * Changes the state of the pressed key's corresponding boolean in the
     * array to false.
     */
    public void keyReleased(KeyEvent e) {
        System.out.println("Released = " + e.getKeyCode());
        keys.remove(e.getKeyCode());
    }

    public void keyTyped(KeyEvent e) {
    }
}

我还在渲染循环中添加了一个小的延迟,这样您就不会阻塞系统

I also added a small delay into the render loop so you're not chocking the system

private void start() {
    setFocusable(true);
    while (true) {
        this.requestFocusInWindow();
        update();
        render();
        try {
            Thread.sleep(16);
        } catch (InterruptedException ex) {
        }
    }
}

这篇关于Java KeyListener停止工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆