Java KeyListener停止工作

时间:2017-03-08 00:32:49

标签: java swing canvas keylistener

- = UPDATE = -

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

问题

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

现在我的问题:

在程序运行时,我无法让Java KeyListener合作。当我开始我的程序时,一切都像往常一样。然而,当我开始按键并移动物品(使用所述键)时,程序开始延迟并花费更多时间进行按键注册。突然间,他们KeyListener完全中断,我没有输入(即使keyPressed方法中的System.out.println语句显示没有活动)。我有三个与我的KeyListener有关的类。

如果有帮助,该程序的目标是使用BufferedImage类绘制来自不同数学函数的点,如正弦波。我已经评论了我能做到的最好,而不是超级评论者,但我可以尽我所能澄清任何代码的目的。

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

SHEETS.spreadsheets().values().update(spreadsheetId=SHEET_ID, range='A1',
        body={'values': rows}, valueInputOption='RAW').execute()

其次,我的Keyboard类(中断的KeyListener):

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

第三,我的Controller类(使用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) {
    }
}

我找到了几个有用的人说使用KeyBindings而不是KeyListener。但是,我过去成功使用过KeyListener,如果可能的话,我想让它再次运行。如果KeyBindings是绝对必要的,我想我可以进行切换,但我更愿意,如果不是这样的话。

提前谢谢大家!

2 个答案:

答案 0 :(得分:1)

Canvas会遇到与所有其他组件相同的问题,键盘焦点丢失,这就是我们通常不建议使用KeyListener的原因。

首先,您需要使Canvas具有焦点,请参阅Canvas#setFocusable

下一个更困难的问题是请求键盘焦点,您可以使用Canvas#requestFocusInWindow,但任何需要键盘焦点的组件都会窃取它。

根据您的操作,您可以简单地将调用置于更新循环中,但您需要注意,如果您想在同一窗口中询问用户的输入,则会出现问题(画布偷走焦点)

更新

由于在键盘控制器中使用了一个数组,我遇到了一些边界索引的问题,我将其转换为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];

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

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

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

答案 1 :(得分:0)

尝试

f = open('input1.csv')  # create file object
userInput = f.read()
seperated = userInput.split(',')
wordsDict = {}
for word in seperated:
    if word not in wordsDict:
        wordsDict[word] = 1
    else:
        wordsDict[word] = int(wordsDict.get(word)) + 1
for i in wordsDict:
    print i, wordsDict[i] 

尽管这是在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") 中运行的,但不应有任何问题