简体   繁体   English

Java KeyListener 停止工作

[英]Java KeyListener Stops Working

- = UPDATE = - - = 更新 = -

It turns out the issue was not with Java but with my Apple keyboard.事实证明,问题不在于 Java,而在于我的 Apple 键盘。 Holding down a letter key brings up a menu that breaks my Java programs.按住字母键会弹出一个菜单,它会破坏我的 Java 程序。 By disabling that menu popup, my KeyListener and my Key Bindings both work as they should.通过禁用该菜单弹出窗口,我的 KeyListener 和我的 Key Bindings 都可以正常工作。 Thank you all for your answers.谢谢大家的答案。

Question

I have searched on Google and on StackOverflow for an answer to my question, but to no avail.我在 Google 和 StackOverflow 上搜索过我的问题的答案,但无济于事。 All of the questions that I've found have the main class extending JComponent, JFrame, JPanel, etc., and not Canvas.我发现的所有问题都有扩展 JComponent、JFrame、JPanel 等的主类,而不是 Canvas。

Now for my question:现在我的问题:

I am having trouble getting my Java KeyListener to cooperate while my program runs.当我的程序运行时,我无法让我的 Java KeyListener 合作。 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).突然之间,它们 KeyListener 完全中断,我没有得到任何输入(即使 keyPressed 方法中的 System.out.println 语句也没有显示任何活动)。 I have three classes that have to do with my KeyListener in any way.我有三个类与我的 KeyListener 有任何关系。

If it helps, the goal of this program is to use BufferedImage class to plot points from different mathematical functions, like a sine wave.如果有帮助,该程序的目标是使用 BufferedImage 类绘制来自不同数学函数的点,如正弦波。 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.我在没有成为超级评论员的情况下尽可能地评论了,但我可以尽我所能澄清任何代码的目的。

First, my Screen class (draws stuff on the JFrame with a BufferStrategy):首先,我的 Screen 类(使用 BufferStrategy 在 JFrame 上绘制内容):

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

Second, my Keyboard class (KeyListener that breaks):其次,我的键盘类(中断的 KeyListener):

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

Third, my Controller class (uses the KeyListener to control the program):三、我的Controller类(使用KeyListener来控制程序):

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

I have found several helpful people saying to use KeyBindings as opposed to a KeyListener.我发现有几个有用的人说要使用 KeyBindings 而不是 KeyListener。 However, I have used a KeyListener successfully in the past, and I'd like to get it to work again if possible.但是,我过去曾成功使用过 KeyListener,如果可能的话,我想让它再次工作。 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.如果 KeyBindings 是绝对必要的,我想我可以进行切换,但如果不必如此,我更愿意。

Thank you all in advance!谢谢大家!

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会遇到与所有其他组件相同的问题,即失去键盘焦点,这就是我们通常不推荐KeyListener

First you need to make the Canvas focusable, see Canvas#setFocusable首先你需要让Canvas成为焦点,参见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.下一个更困难的问题是请求键盘焦点,您可以使用Canvas#requestFocusInWindow但任何需要键盘焦点的组件都会窃取它。

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)根据您的操作,您也许可以简单地将调用置于更新循环中,但您需要注意,如果您想在同一窗口内询问用户的输入,您将遇到问题(使用画布偷了焦点)

Update更新

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...由于在键盘控制器中使用了数组,我在边界索引方面遇到了一些问题,我改为使用Set代替...

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

try this尝试这个

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

public class Main {


    public static void main(String[] argv) throws Exception {

        JTextField textField = new JTextField();

        textField.addKeyListener(new MKeyListener());

        JFrame jframe = new JFrame();
        jframe.add(textField);

        jframe.setSize(700, 700);

        jframe.setVisible(true);

    }
}
class MKeyListener extends KeyAdapter {

    @Override
    public void keyPressed(KeyEvent event) {
        System.out.println(event.getKeyCode)
        if(event.getKeyCode() = \\key code here\\){
            System.out.println("True")
            }else{System.out.println("False")

Allthough this was ran in package java but there shouldnt be anything wrong with it虽然这是在package java中运行的,但它不应该有任何问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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