Chaz
Chaz

Reputation: 11

Java KeyListener not responding

Forgive me if I'm asking too big of a question, I trying to learn to code and I think I'm missing a big detail about KeyListiner. I am trying to make a simple program that "rolls a dice" and displays a picture of a number 1 to 6 when the users presses a key. My program doesn't seem to respond to any user input.

What am I doing wrong?

Thank you for any help, I'm just trying to learn so any advice is appreciated.

public class Dice   {

 public static void  main (String arg[]) {
     new DD(); 
 }
}   

class DD extends JPanel {   
DD(){

    JFrame frame = new JFrame();
    ImageIcon icon = new ImageIcon("dice.jpg");
    JLabel label = new JLabel(icon);
    frame.add(label);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
    addKeyListener(new Roll());
    }   
}

class Roll extends JFrame implements KeyListener {

public void keyPressed(KeyEvent event){}
public void keyReleased(KeyEvent event){}
public void keyTyped(KeyEvent event){   
    int d = event.getKeyCode();
    if(d == KeyEvent.VK_UP){
        int roll = (int) (Math.random()*6) + 1;
        System.out.println(roll);
  }
 }  
}   

Upvotes: 1

Views: 117

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

Let's take a closer look at your DD class...

class DD extends JPanel {

    DD() {

        JFrame frame = new JFrame();
        ImageIcon icon = new ImageIcon("dice.jpg");
        JLabel label = new JLabel(icon);
        frame.add(label);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        addKeyListener(new Roll());
    }
}
  • You create an instance of JFrame, from within the constructor of the JPanel, which is a questionable act...
  • You create a JLabel and add it to the JFrame
  • You show the JFrame
  • You add a KeyListener to the DD JPanel

But wait a minute, DD is never attached to any visible component, how could it ever possible be capable of receiving key events?!

KeyListener will only work when the component that it's registered to is focusable AND has focus, but if it's never displayed on the screen, it could never have focus!

To start with, I'd avoid using KeyListener, it has focus related issues, and instead use the Key Bindings API

For example...

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
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;

public class Dice {

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

    public Dice() {
        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 DD());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    class DD extends JPanel {

        DD() {
            setLayout(new GridBagLayout());
            JLabel label = new JLabel(" - ");
            add(label);

            addKeyBindingFor(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Action.roll", new DiceRollAction(label));
        }

        protected void addKeyBindingFor(KeyStroke keyStroke, String name, Action action) {
            InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap actionMap = getActionMap(); 

            inputMap.put(keyStroke, name);
            actionMap.put(name, action);
        }

        public class DiceRollAction extends AbstractAction {

            private JLabel label;

            public DiceRollAction(JLabel label) {
                this.label = label;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                int roll = (int) (Math.random() * 6) + 1;
                label.setText(Integer.toString(roll));
            }
        }

    }

}

Upvotes: 1

Related Questions