4

First of all, thanks for taking the time to read my question, I appreciate it.

Here's the overview of what I've got now:

I'm writing a slider puzzle game, 3 by 3 using buttons as grid cells. I've added a key listener to the JPanel which holds those buttons, and they respond to keyboard events just fine.

However, the problem's somewhat peculiar, and I haven't really been able to pinpoint why it renders this erratic behavior. After clicking on one of those 'buttons', none of which have event listeners registered, none of the buttons move, but when you follow that with a key event, the keys become unresponsive.

My question is this: I know this is pretty vague, but does this ring a bell to anyone to be a Java problem, or does it sound like my faulty code's behind all this?

I'm really open to any suggestions, since this has been bothering me for about a week now, and I still don't know what caused the problem.

Again, thank you for taking the time to peruse this.

@trashgod: yes, of course.

public class Test2 extends JPanel{
    JButton a = new JButton("A");

    Test2(){
        setFocusable(true);
        // Set layout to grid layout
        setLayout(new GridLayout(3, 3));
        // Add button
        //a.setEnabled(false);
        add(a);

        // Register key event which shifts it to the next cell when the right arrow is pressed
        addKeyListener(new KeyAdapter(){
            public void keyPressed(KeyEvent e){
                if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                    remove(a);
                    JButton b = new JButton("B");
                    //b.setEnabled(false);
                    add(b);
                    add(a);
                    validate();

                }
            }
        });
    }
}

Function of code snippet: JPanel receives key event, the left arrow key, to be precise, removes button 'a', and adds on a new button 'b', followed by the button 'a' every time. However, if you try and run the program, after you click on a button, it just stops listening to key events.

I've just paid some thought to it, could it have something to do with the lost focus in JPanel? If so, what particular methods should I pay attention to to restore the lost focus?

Thanks!

(btw, the setEnabled comments is my attempt at solving this problem, by simply disabling the button, but it still doesn't explain how to restore the lost focus to the JPanel if that's the problem at hand.)

ROOT
  • 11,363
  • 5
  • 30
  • 45
imicrothinking
  • 95
  • 4
  • 11
  • 2
    Please provide an [sscce](http://sscce.org/) that exhibits the problem you describe. – trashgod Dec 24 '11 at 06:04
  • Note that an SSCCE should include imports. BTW *"next cell when the right arrow is pressed"* Which part of the [`KeyEvent.VK_LEFT`](http://docs.oracle.com/javase/7/docs/api/java/awt/event/KeyEvent.html#VK_LEFT) docs of *"Constant for the non-numpad **left** arrow key."* are you having trouble understanding? When including comments in code, ensure they **match** the code itself. ;) – Andrew Thompson Dec 24 '11 at 06:26
  • @AndrewThompson: Thank you for reading my question, and yes, I do understand that it's the left arrow key. An error in commenting, silly me, thanks for the reminder! :P However, what came to my concern was the inability for the JPanel to receive key events after a button was pressed, which was easily remedied by adding an ActionListener to the buttons which restored the focus to the JPanel on click. Once again, thanks! :D – imicrothinking Dec 24 '11 at 06:38

2 Answers2

3

We can keep the focus on the JPanel by just calling setFocusable(false) on each button:

button1.setFocusable(false); or button2.setFocusable(false);

etc

This will allow the JPanel, where the keyListeners are added, to keep the focus.

therealrootuser
  • 10,215
  • 7
  • 31
  • 46
2

not all Keys are accesible for KeyListener, part of them are registred as built-in short-cuts for JComponents, depends of JComponent's type and used Look and Feel, if you want to listening for Keys from keyboard, then you have to implements KeyBindings, Swing JComponents are designated to use this listener rather that KeyListener

working example for key A

import java.awt.GridLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test2 extends JPanel {

    private static final long serialVersionUID = 1L;
    private JButton a = new JButton("A");

    public Test2() {
        setFocusable(true);
        setLayout(new GridLayout(3, 3));
        a.setEnabled(false);
        add(a);
        addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_A) {
                    remove(a);
                    JButton b = new JButton("B");
                    add(b);
                    add(a);
                    revalidate();
                    repaint();
                }
            }
        });
    }

    public static void main(String... args) {
        JFrame frame = new JFrame("");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new Test2());
        frame.pack();
        frame.setVisible(true);
    }
}
ROOT
  • 11,363
  • 5
  • 30
  • 45
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Thank you for the time to edit my code. I had originally tested the code, and initially, I also thought that it was the arrow keys which couldn't be received, so I also switched to a more 'widely received' character as such - 'A'. However, my problem was really about having those buttons on the panel. Once you clicked on them JPanel becomes unable to receive keyboard events. Now I've found out why. It's because it lost focus. Simply add an action listener to the buttons to restore the lost focus to JPanel and everything's set. Again, thanks! :D – imicrothinking Dec 24 '11 at 06:35
  • @imicrothinking _Simply add an action listener to the buttons to restore the lost focus to JPanel and everything's set_ While seemingly "working" that's simply the wrong-thing-to-do ... As you discovered, KeyListener isn't the appropriate tool to service your requirement (actually it _never_ is appropriate in Swing). Instead, use Keybindings – kleopatra Dec 24 '11 at 10:39
  • @kleopatra It's interesting that you point that out, because I had sampled several alternatives to approaching this problem within our time constraints and our current knowledge of Java, and the other popular alternative was to make extensive use of the paintComponent method to redraw many, many lines to model the 'tiles', but that to me was too tedious. To be quite honest, our project specs requesting specifically for the game to be able to receive key events didn't really go well with me because writing the code wasn't intuitive. I'll look into KeyBindings later as an alternative. Merci~ – imicrothinking Dec 24 '11 at 14:11