keyListener не применяется к JPanel (да, он сфокусирован)
В настоящее время я работаю над проектом, и когда я пытаюсь добавить свой собственный слушатель клавиш, который находится в его собственном классе, он не работает, и когда вы нажимаете клавиши, ничего не происходит, и я уже некоторое время занимаюсь этим. Я не могу использовать сочетания клавиш, поэтому, пожалуйста, не предлагайте мне поменять их, потому что они не работают с тем, что я делаю, поскольку они не поддерживают одновременное нажатие нескольких клавиш (поверьте мне, я пытался). Ориентирован на использование 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();
}
}
}
1 ответ
Короткий ответ: не используйте KeyListener
используйте API привязок клавиш, который позволит вам преодолеть эти недостатки и настроить уровень фокусировки, необходимый для их запуска.
См. Как использовать привязки клавиш для более подробной информации.
обновленный
Во-первых, вам нужно перестать думать в таких абсолютных терминах и начать думать в более абстрактных понятиях. Ваша игра не должна заботиться о том, КАК что-то делается, только когда что-то не работает.
Проблема не в API привязок клавиш, а в том, как вы видите проблему.
Например, вас не должно волновать, КАК запускается событие "вверх", только то, что это было. Это означает, что триггер мог исходить от джойстика, игрового контроллера, сетевого сервера, контроля над разумом посредством силы и даже клавиатуры. Затем игра соответствующим образом отреагирует на это изменение состояния.
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-интерфейс, который не отвечает вашим потребностям и который сообщество в целом побудит вас не продолжать использовать...