0

I am currently working on a project and when I try to add my own key listener that is in its own class it doesn't work and when you press the keys nothing happens, and I've been at it for a while now. I can't use Keybindings so please don't offer for me to change to those because they don't work with what I am doing since they don't support multiple key presses at 1 time (trust me ive tried). It is focused using panel.setFocusable(true); and panel.requestFocusInWindow();, and I even did it to the frame with frame.setFocusable(true); and frame.requestFocusInWindow(); but still nothing. these are all my files:

EDIT: I added a SwingUtilities.invokeLater(new Runnable() {, but still nothing, I am currently doing what MadProgrammer said about KeyBindings but as of now I'm getting some weird errors I'm trying to fix.

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();
    }
}
}
Abob
  • 751
  • 5
  • 27
  • Calling `requestFocusInWindow` while the window is not visible or displayable will have no effect... – MadProgrammer Oct 05 '14 at 23:14
  • @MadProgrammer I tried putting it last doesn't work still does nothing, but thanks for help anyway. – Abob Oct 05 '14 at 23:41
  • Frankly, your codes a bit of mess, however, start by making sure you UI is started within the context of the EDT, see [Initial Threads](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html) for more details. Wrap the `requestFocusInWindow` inside a `SwingUtilities.invokeLater` request, this should allow time for the window to actually become visible and displayed on the screen... – MadProgrammer Oct 05 '14 at 23:44
  • For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example). – Andrew Thompson Oct 06 '14 at 00:13

1 Answers1

2

The short answer is, don't use KeyListener, use the Key Bindings API which will allow you to overcome these shortcomings and configure the level of focus required in order for them to be triggered.

See How to Use Key Bindings for more details

Updated

First, you need to stop think in such absolute terms and start thinking in more abstract concepts. Your game shouldn't care HOW something is done, only when something IS down.

The problem is not with the key bindings API but how you see the problem.

For example, you shouldn't care HOW an "up" event is triggered, only that it was. This means that trigger could have come from a joystick, game controller, network server, mind control through the force and even the keyboard. The game would then react to this change in state accordingly.

Key bindings

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

    }
}

Now, you have two choices to make, you can change the way you are thinking and take advantage of an API which will solve your problem and make your program more flexible and configurable (as the user might like to change the keys that trigger the events) or your can continue trying to use to an API which is failing to meet your needs and which the community at large will encourage you not to continue to use...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I already explained I can't use keybindings because they don't support multiple button presses at a time, please fully read what I said and it will tell you I can't use keybindings, but thanks for the help anyway (I know how to use keybindings by the way) – Abob Oct 05 '14 at 23:38
  • Of course they do, it's up to you to make that work. The basic approach is to use a flag to indicate when particular keys are pressed and take appropriate actions based on those flags – MadProgrammer Oct 05 '14 at 23:40
  • As an [example](http://stackoverflow.com/questions/13528953/detecting-multiple-keypresses-in-java/13537419#13537419) – MadProgrammer Oct 05 '14 at 23:41
  • I can't tell if it works or not because I don't know where to put my method of MainCharacter.move(0, CharacterN) etc. – Abob Oct 06 '14 at 00:04
  • I tried what you said and non of that worked for me sorry, im stuck to using key listeners – Abob Oct 06 '14 at 00:11
  • thanks for the update! that's actually helped! (except the attitude) :\ – Abob Oct 06 '14 at 01:01
  • @Abob78 Sorry, it's nothing personal, but it's a little tiring to hear people say stuff like "it doesn't work" or "I don't want to use that" ... please don't take it personally ;) – MadProgrammer Oct 06 '14 at 01:03
  • could you possibly clarify how I adjust your code to match my `MainCharacter.move(direction, facingDirection)` method? Thanks a bunch! – Abob Oct 06 '14 at 03:06
  • Honestly, you wouldn't. What you would do is check the state `InputManager` and make decisions about which direction the character should move in and which direction they should be facing. This would suggest you need to change your rendering/update code. – MadProgrammer Oct 07 '14 at 00:30
  • Okay thanks for your time, but is it possible to use Mouselistener at the same time because I also need mouseclicks at the same time as the key inputs...is that possible? also would you mind upvoting on my question so it won't be -1 :), thanks – Abob Oct 08 '14 at 23:42
  • Yes, you can use what ever input you want...not sure if it's the same thing or not, but that's kind of the point of the `InputManager` ;) – MadProgrammer Oct 08 '14 at 23:43