0

I have a jframe of which I have made in Netbeans, this jframe is being "launched" by another java class, but for the current question that doesn't matter. What matters is the fact that I can't seem to figure out how to add my key listener to this jframe of mine. I have implemented the key listener, added the required functions (key typed, key pressed and key released). But I can't figure out how to actually add/initiate the actual key listener, to make it work.

As of right now I have tried two different things, first I have tried to add the line addKeylistener(new JFrameList()); in the start of the code, where the actual jframe is being initiated, but doing so the actual frame won't even show. Apart from this I have tried to add the same line within another function callJframFForm(), which is called from another class at the same time as the jframe is called. But this just returns the error non-static method addKeyListener(KeyListener) cannot be referenced from a static context. I am not sure what other ways I could add the key listener and thus am looking for a little help.

Currently my code looks like the one below.

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

public class JFrameList extends javax.swing.JFrame implements KeyListener{

    public static String keyPresCod = "";

    public JFrameList() {
        initComponents();
        addKeyListener(new JFrameList()); //This is where I am currently trying to call from, but frame won't show
    }    

    public static void main(String args[]) {
        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new JFrameList().setVisible(true);
            }
        });  
    }                                                

    // Variables declaration - do not modify                    
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    // End of variables declaration                  

    static void callJframFForm(){
        try {
            //This is where I have also tried to add the initialization line
        } catch(Exception e) {
            e.printStackTrace();
    }
    }

    @Override
    public void keyTyped(KeyEvent e) {
        int codeFKey = e.getKeyCode();

        if (codeFKey == KeyEvent.VK_A) {
            System.out.println("Button A clicked");
                        keyPresCod = "A";
        } else if (codeFKey == KeyEvent.VK_B) {
            System.out.println("Button B clicked");
                        keyPresCod = "B";
        } else {
            System.out.println("Different key pressed");
                        keyPresCod = "Another key";
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

}
  • I think your current approach is overkill, I'd have a look at [How to Use Buttons, Check Boxes, and Radio Buttons](http://docs.oracle.com/javase/tutorial/uiswing/components/button.html) as buttons have a predefined way of working which users are use to – MadProgrammer Feb 13 '17 at 19:58
  • 1
    @MadProgrammer - `I'd have a look at...` - glad you agree. – camickr Feb 13 '17 at 20:23
  • @camickr But given the lack of context to the problem the OP is trying to solve, I don't know if it's the answer ;) – MadProgrammer Feb 13 '17 at 20:47
  • Your inputs are very much appreciated, the whole purpose of my code is to be able to display what button on the computer keyboard has been clicked and not a JButton. As of right now there is a load of inspiration of how I would change my code, so I will have to check it all through first. –  Feb 13 '17 at 21:44

2 Answers2

1

Problem

addKeyListener(new JFrameList())

This creates a new JFrameList object and uses it's listener. This means any keystrokes are being stored in the new object's member. To see the results, you would have to do

JFrameList list = new JFrameList(); addKeyListener(list); //use list variable to access keyPressed code

Of course this isn't the behavior you want. You want the keys strokes to be stored in the current instance, not a new object. This means you should be doing

addKeyListener(this)

Although you may notice the listener only works "sometimes", or maybe not at all depending on how you're testing it.

Swing uses a focus system to manage which listeners should be receiving events, and since you are adding the listener to a JFrame, the listener will receive events only when the frame is in focus.

Solution

You should use key bindings rather than a key listener.

If you choose to continue using the listener, you should add it to your buttons, not your frame:

jButton1.addKeyListener(this);
jButton2.addKeyListener(this);

Instead of checking the key code of the event, you could grab the source of the event (your button) by calling event.getSource().

Key bindings allows you to set flexible focus settings for your components. All you need to do is access the input map of the component:

String actionCommand = "Press Button A";
jButton1.setActionCommand(actionCommand);
jButton1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), actionCommand);
jButton1.getActionMap(actionCommand, this);

Your JFrameList should now implement ActionListener rather than KeyListener, as it will be receiving your events as actions:

class JFrameList extends JFrame implements ActionListener {
    private JButton jButton1;

    public JFrameList() {
        jButton1 = new JButton("A");
        //set action command, add to input map, add to action map
    }

    public void actionPerformed(ActionEvent event) {
        JButton button = (JButton) event.getSource();
        System.out.println(button.getActionCommand() + " was performed.");
    }
}

Alternative

JButton has built-in mnemonic handling. You can specify a mnemonic via JButton#setMnemonic(int), where the argument is a key code:

jButton1.setMnemonic(KeyEvent.VK_A);

This is the standard way of handling hotkeys in graphical interfaces. Simply hold down the Alt key (windows) then press the key you set the mnemonic to.

Community
  • 1
  • 1
Vince
  • 14,470
  • 7
  • 39
  • 84
  • I really appreciate the input, I have now changed the code to have the line `addKeyListener(this)` within the initialization function at the start. Now the Jframe is showing again, but the actual key listener doesn't seem to work. As you can see it is set to print specific things depending on what button has been clicked. But it doesn't. –  Feb 13 '17 at 19:13
  • @rootsquaredtimes89 That's because the frame needs to be in focus for the events to be dispatched, since the listener is added to the frame. You could have the frame `requestFocus` after being displayed, but it'll lose focus as soon as you click off the frame (like when you click a button). I've updated my answer – Vince Feb 13 '17 at 19:42
  • Adding `KeyListener` to the buttons will have no additional effect, as the buttons won't respond until they have focus, key bindings is the correct solution to overcome the issue with `KeyListener`, but buttons have a functionality built in which could do a similar job – MadProgrammer Feb 13 '17 at 19:59
  • @MadProgrammer Updated my answer. Don't think he'll prefer mnemonics, although I'll include it in my answer – Vince Feb 13 '17 at 20:03
  • @VinceEmigh It would require more context to the problem the OP is trying to solve to be sure, but if it saves them a lot of unnecessary time and effort, it's worth mentioning, besides, it's what the user would "expect" in most case – MadProgrammer Feb 13 '17 at 20:45
  • @VinceEmigh Your edit is much appreciated, however for me it seems as if the edit is for Jbuttons only. The purpose of my code is to get the key pressed, on the actual computer keyboard. So if the user would click the key "alt" I would get the keycode of the "alt" button. –  Feb 13 '17 at 22:32
  • @VinceEmigh I have now managed to get it to work, using your great advice. I have ended up moving the actual KeyEvent code into the `KeyPressed` section and then I have just added the key listener to any focusable element. It might not be completely right, but as of right now it seems to work perfectly. –  Feb 13 '17 at 22:59
  • @rootsquaredtimes89 You can add key bindings to any component – Vince Feb 13 '17 at 23:35
0

Key Events are only dispatched to the component with focus. You didn't post the entire code but I'm guessing that focus is on the button that you add to the frame, so the button gets the KeyEvent.

Not sure what you are trying to do with the KeyListener. You can't tell which button was clicked by looking at the character typed in the KeyEvent.

If you want to know what button is clicked then you need to add an ActionListener to each button. Read the section from the Swing tutorial on How to Use Buttons for more information and examples.

camickr
  • 321,443
  • 19
  • 166
  • 288