【问题标题】:keyListener not applying to JPanel (yes, it is focused)keyListener 不适用于 JPanel(是的,它是专注的)
【发布时间】:2014-11-30 05:42:01
【问题描述】:

我目前正在做一个项目,当我尝试添加自己的类中的键侦听器时它不起作用,当你按下键时没有任何反应,我已经做了一段时间现在。我不能使用键绑定,所以请不要让我更改这些,因为它们不支持我正在做的事情,因为它们不支持一次多次按键(相信我,我试过了)。它使用panel.setFocusable(true);panel.requestFocusInWindow(); 聚焦,我什至使用frame.setFocusable(true);frame.requestFocusInWindow(); 对框架进行了处理,但仍然没有。这些都是我的文件:

编辑:我添加了一个SwingUtilities.invokeLater(new Runnable() {,但仍然没有,我目前正在按照 MadProgrammer 所说的关于 KeyBindings 的方式进行操作,但到目前为止,我遇到了一些我正在尝试修复的奇怪错误。

Game.Java:

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JPanel;
import com.PK.character.MainCharacter;

public class Game extends JPanel{
    private static final long serialVersionUID = -2398443377427441196L;
    public static Image gamemainmenu = Toolkit.getDefaultToolkit().createImage("src/resources/homerscared.jpg");
    public static boolean menu;
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(gamemainmenu, 10, 10, null);
        menu = true;
        if (menu = true){
            g.drawImage(MainCharacter.MainCharacterImage, 100, 100, null);
        }
    }
}

ButtonListener.Java:

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

import javax.swing.JPanel;

import com.PK.PK;
import com.PK.character.MainCharacter;

public class ButtonListener implements KeyListener{
private static JPanel gamepanel = PK.panel;
@Override
public void keyPressed(KeyEvent arg0) {
    /**N=0
     * NE=1
     * E=2
     * SE=3
     * S=4
     * SW=5
     * W=6
     * NW=7
     */
    if (arg0.getKeyChar() == KeyEvent.VK_DOWN){
        MainCharacter.move(4, MainCharacter.CharacterS);
        System.out.println("down pressed");
        gamepanel.setForeground(Color.BLUE);
    }
    if (arg0.getKeyChar() == KeyEvent.VK_UP){
        MainCharacter.move(0, MainCharacter.CharacterN);
        System.out.println("up pressed");
    }
    if (arg0.getKeyChar() == KeyEvent.VK_LEFT){
        MainCharacter.move(6, MainCharacter.CharacterW);
        System.out.println("left pressed");
    }
    if (arg0.getKeyChar() == KeyEvent.VK_RIGHT){
        MainCharacter.move(2, MainCharacter.CharacterE);
        System.out.println("right pressed");

    }
    if (arg0.getKeyChar() == KeyEvent.VK_RIGHT && arg0.getKeyChar() == KeyEvent.VK_UP){
        MainCharacter.move(1, MainCharacter.CharacterNE);
        System.out.println("right and up pressed");
    }
    if (arg0.getKeyChar() == KeyEvent.VK_RIGHT && arg0.getKeyChar() == KeyEvent.VK_DOWN){
        MainCharacter.move(3, MainCharacter.CharacterSE);
        System.out.println("up and right pressed");
    }
    if (arg0.getKeyChar() == KeyEvent.VK_LEFT && arg0.getKeyChar() == KeyEvent.VK_UP){
        MainCharacter.move(7, MainCharacter.CharacterNW);
        System.out.println("up and left pressed");
    }
    if (arg0.getKeyChar() == KeyEvent.VK_LEFT && arg0.getKeyChar() == KeyEvent.VK_DOWN){
        MainCharacter.move(5, MainCharacter.CharacterSW);
        System.out.println("left and down pressed");
    }
}

@Override
public void keyReleased(KeyEvent arg0) {

}

@Override
public void keyTyped(KeyEvent arg0) {

}

}

PK.Java (Main Class):

package com.PK;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import com.PK.movement.ButtonListener;

public class PK {
    public static short CharacterX, CharacterY;
    public static final int width = 800;
    public static final int height = 600;
    public static Date date = new Date();
    public static String dString = date.toString();
    public static String dFormat = "[" + dString + "]: ";
    public static JFrame frame = new JFrame();
    public static JPanel panel = new Game();
    public static KeyListener bt = new ButtonListener();
    public static Image logobasic = Toolkit.getDefaultToolkit().createImage("src/resources/logo-basic.png");
public static void main(String[] args){
    frame.setContentPane(panel);
    System.out.println(dFormat + "Panel added to frame");
    frame.setSize(width, height);
    frame.setTitle("PK");
    frame.setIconImage(logobasic);
    frame.setVisible(true);
    frame.setJMenuBar(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    System.out.println(dFormat + "Frame settings set");
    System.out.println(dFormat + "Launching...");   
}

public PokemonUniverse(){
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            panel.setFocusable(true);
            panel.requestFocusInWindow();
            System.out.println(dFormat + "Panel focused");
            panel.addKeyListener(bt);
            System.out.println(dFormat + "KeyListener added to panel");
            frame.setFocusable(true);
            frame.requestFocusInWindow();
            System.out.println(dFormat + "Frame focused");
            frame.addKeyListener(bt);
            System.out.println(dFormat + "KeyListener added to frame");
        }
    });
}

MainCharacter.Java

package com.PK;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.JPanel;

import com.PK.Game;
import com.PK.PK;

@SuppressWarnings("unused")
public class MainCharacter {
static Toolkit tk = Toolkit.getDefaultToolkit();
public static Image MainCharacterImage = PK.logobasic, CharacterS, CharacterN, CharacterW, CharacterE, CharacterSE, CharacterNE, CharacterSW, CharacterNW;
private static JPanel gamepanel = PK.panel;
private static short Y = PK.CharacterY;
private static short X = PK.CharacterX;

/**N=0
 * NE=1
 * E=2
 * SE=3
 * S=4
 * SW=5
 * W=6
 * NW=7
 */
public static void move(int direction, Image FacingDirection) {
    if (direction == 0){
        Y++;
        MainCharacterImage = FacingDirection;
        gamepanel.repaint();
    }
    else if (direction == 1){
        Y++;
        X++;
        MainCharacterImage = FacingDirection;
        gamepanel.repaint();
    }
    else if (direction == 2){
        X++;
        MainCharacterImage = FacingDirection;
        gamepanel.repaint();
    }
    else if (direction == 3){
        Y--;
        X++;
        MainCharacterImage = FacingDirection;
        gamepanel.repaint();
    }
    else if (direction == 4){
        Y--;
        MainCharacterImage = FacingDirection;
        gamepanel.repaint();
    }
    else if (direction == 5){
        Y--;
        X--;
        MainCharacterImage = FacingDirection;
        gamepanel.repaint();

    }
    else if (direction == 6){
        X--;
        MainCharacterImage = FacingDirection;
        gamepanel.repaint();
    }
    else if (direction == 7){
        X--;
        Y++;
        MainCharacterImage = FacingDirection;
        gamepanel.repaint();
    }
    else{
        MainCharacterImage = PK.logobasic;
        gamepanel.repaint();
    }
}
}

【问题讨论】:

  • 在窗口不可见或可显示时调用 requestFocusInWindow 将无效...
  • @MadProgrammer 我试着把它放在最后不起作用仍然什么都不做,但无论如何感谢您的帮助。
  • 坦率地说,你的代码有点乱,但是,首先要确保你的 UI 是在 EDT 的上下文中启动的,有关更多详细信息,请参阅Initial Threads。将requestFocusInWindow 包裹在SwingUtilities.invokeLater 请求中,这应该留出时间让窗口实际可见并显示在屏幕上...
  • 为了尽快获得更好的帮助,请发布MCVE(最小完整可验证示例)。

标签: java swing key listener focusable


【解决方案1】:

简短的回答是,不要使用KeyListener,使用 Key Bindings API,它可以让您克服这些缺点并配置触发它们所需的焦点级别。

详情请见How to Use Key Bindings

更新

首先,您需要停止以这样的绝对术语进行思考,而开始以更抽象的概念进行思考。你的游戏不应该关心事情是如何完成的,只有当事情发生时。

问题不在于键绑定 API,而在于您如何看待问题。

例如,您不应该关心“up”事件是如何触发的,只关心它是如何触发的。这意味着触发器可能来自操纵杆、游戏控制器、网络服务器、通过力甚至键盘的精神控制。然后游戏会对这种状态变化做出相应的反应。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class KeyBindingsTest {

    public static void main(String[] args) {
        new KeyBindingsTest();
    }

    public KeyBindingsTest() {
        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 interface InputManager {

        public void upWasPerformed(boolean active);
        public void downWasPerformed(boolean active);
        public void leftWasPerformed(boolean active);
        public void rightWasPerformed(boolean active);

    }

    public static class TestPane extends JPanel implements InputManager {

        public static final LineBorder LINE_BORDER = new LineBorder(Color.RED);
        public static final EmptyBorder EMPTY_BORDER = new EmptyBorder(1, 1, 1, 1);

        private JLabel up;
        private JLabel down;
        private JLabel left;
        private JLabel right;

        public TestPane() {
            setLayout(new GridBagLayout());
            up = new JLabel("UP");
            up.setBorder(EMPTY_BORDER);

            down = new JLabel("DOWN");
            down.setBorder(EMPTY_BORDER);

            left = new JLabel("LEFT");
            left.setBorder(EMPTY_BORDER);

            right = new JLabel("RIGHT");
            right.setBorder(EMPTY_BORDER);

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 1;
            add(left, gbc);
            gbc.gridx++;
            gbc.gridy = 0;
            add(up, gbc);
            gbc.gridy = 2;
            add(down, gbc);
            gbc.gridx++;
            gbc.gridy = 1;
            add(right, gbc);

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "up.pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "up.released");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "down.pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "down.released");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "left.pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "left.released");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "right.pressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "right.released");

            ActionMap am = getActionMap();
            am.put("up.pressed", new UpAction(this, true));
            am.put("up.released", new UpAction(this, false));
            am.put("down.pressed", new DownAction(this, true));
            am.put("down.released", new DownAction(this, false));
            am.put("left.pressed", new LeftAction(this, true));
            am.put("left.released", new LeftAction(this, false));
            am.put("right.pressed", new RightAction(this, true));
            am.put("right.released", new RightAction(this, false));
        }

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

        @Override
        public void upWasPerformed(boolean active) {
            up.setBorder(active ? LINE_BORDER : EMPTY_BORDER);
        }

        @Override
        public void downWasPerformed(boolean active) {
            down.setBorder(active ? LINE_BORDER : EMPTY_BORDER);
        }

        @Override
        public void leftWasPerformed(boolean active) {
            left.setBorder(active ? LINE_BORDER : EMPTY_BORDER);
        }

        @Override
        public void rightWasPerformed(boolean active) {
            right.setBorder(active ? LINE_BORDER : EMPTY_BORDER);
        }

    }

    public static abstract class InputManagerAction extends AbstractAction {

        private InputManager manager;
        private boolean activate;

        public InputManagerAction(InputManager manager, boolean activate) {
            this.manager = manager;
            this.activate = activate;
        }

        public InputManager getManager() {
            return manager;
        }

        public boolean shouldActivate() {
            return activate;
        }

    }

    public static class UpAction extends InputManagerAction {

        public UpAction(InputManager manager, boolean activate) {
            super(manager, activate);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            getManager().upWasPerformed(shouldActivate());
        }

    }

    public static class DownAction extends InputManagerAction {

        public DownAction(InputManager manager, boolean activate) {
            super(manager, activate);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            getManager().downWasPerformed(shouldActivate());
        }

    }

    public static class LeftAction extends InputManagerAction {

        public LeftAction(InputManager manager, boolean activate) {
            super(manager, activate);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            getManager().leftWasPerformed(shouldActivate());
        }

    }

    public static class RightAction extends InputManagerAction {

        public RightAction(InputManager manager, boolean activate) {
            super(manager, activate);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            getManager().rightWasPerformed(shouldActivate());
        }

    }
}

现在,您有两个选择,您可以改变您的思维方式并利用 API 来解决您的问题并使您的程序更加灵活和可配置(因为用户可能希望更改触发事件),或者您可以继续尝试使用无法满足您的需求并且整个社区会鼓励您不要继续使用的 API...

【讨论】:

  • 我已经解释过我不能使用键绑定,因为它们不支持同时按下多个按钮,请完整阅读我所说的,它会告诉你我不能使用键绑定,但是谢谢无论如何都需要帮助(顺便说一下,我知道如何使用键绑定)
  • 他们当然会这样做,这取决于你。基本方法是使用标志来指示何时按下特定键并根据这些标志采取适当的行动
  • 作为example
  • 我不知道它是否有效,因为我不知道将 MainCharacter.move(0, CharacterN) 等方法放在哪里。
  • 我尝试了你所说的,但没有对我有用,对不起,我坚持使用关键听众
猜你喜欢
  • 2018-07-07
  • 2013-12-16
  • 2012-05-14
  • 1970-01-01
相关资源
最近更新 更多