Sorry about its being a duplicate - I was in a hurry when I wrote this, and didn't have time to check. Though I suppose it would have been faster, now that I think about it...


Possible Duplicate:
Java KeyListener for JFrame is being unresponsive?

I have been writing an app and am trying to make hotkeys. I decided to use KeyListener, as it is all I know as of yet. However, the class is not responding to key presses. How would I fix this bug? If there is an alternative to KeyListener that will do the same thing, please let me know and preferably provide an example of how it would work.

Main class

import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
import panels.TabBar;

public class __mn implements KeyListener {
    static JFrame disp = new JFrame("dat app");

    static TabBar tabs = new TabBar();

    public static void main(String[] args) {
        disp.setLayout(new BorderLayout());
        disp.add(tabs, BorderLayout.PAGE_START);
        disp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        disp.setSize(TabBar.PREF_WIDTH, 500);
        disp.setResizable(false);
        disp.setLocationRelativeTo(null);
        disp.addKeyListener(new __mn());
        disp.setVisible(true);
    }

    @Override
    public void keyPressed(KeyEvent e) {
        System.out.println(e.paramString());
    }

    //Unused
    @Override public void keyReleased(KeyEvent e) {
        System.out.println(e.paramString());
    } 
    @Override public void keyTyped(KeyEvent e) {
        System.out.println(e.paramString());
    }
}

TabBar class

package panels;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;

//http://www.dreamincode.net/forums/topic/245148-java-key-binding-tutorial-and-demo-program/

public class TabBar extends JPanel implements ActionListener {
    private static final long serialVersionUID = 1L;

    public static final int NONE = -1;
    public static final int INBOX = 0;
    public static final int SEND_MSG = 1;
    public static final int PRIVATE_CHAT = 2;
    public static final int FEEDBACK = 3;

    public static final int PREF_WIDTH = 425;

    private static final String[] tabNames = {"Inbox", "Send a message", "Private chat", "Feedback"};

    private static final JButton btnInbox = new JButton(tabNames[INBOX]);
    private static final JButton btnSendMSG = new JButton(tabNames[SEND_MSG]);
    private static final JButton btnPrivChat = new JButton(tabNames[PRIVATE_CHAT]);
    private static final JButton btnFeedback = new JButton(tabNames[FEEDBACK]);

    public int currentTab = -1;

    public TabBar() {
        this(new FlowLayout());
    }

    public TabBar(LayoutManager layout) {
        super(layout);

        add(btnInbox);
        add(btnSendMSG);
        add(btnPrivChat);
        add(btnFeedback);

        btnInbox.addActionListener(this);
        btnSendMSG.addActionListener(this);
        btnPrivChat.addActionListener(this);
        btnFeedback.addActionListener(this);

        setBackground(Color.BLACK);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.paramString());
        if (e.getSource() == btnInbox)
            currentTab = INBOX;
        else if (e.getSource() == btnSendMSG)
            currentTab = SEND_MSG;
        else if (e.getSource() == btnPrivChat)
            currentTab = PRIVATE_CHAT;
        else if (e.getSource() == btnFeedback)
            currentTab = FEEDBACK;
        else currentTab = NONE;
    }

    public void hotkeyPressed(char pressed) {
        pressed = Character.toLowerCase(pressed);
        System.out.println("Hotkey pressed: " + pressed);
        switch (pressed) {
        case 'i':
            setTab(INBOX);
            break;
        case 's':
            setTab(SEND_MSG);
            break;
        case 'p':
            setTab(PRIVATE_CHAT);
            break;
        case 'f':
            setTab(FEEDBACK);
            break;
        default:
            break;
        }
    }

    private void setTab(int tab) {
        System.out.println("Somthing pressed! tab=" + tab);
        currentTab = tab;
        switch (tab) {
        case INBOX:
            btnInbox.requestFocusInWindow();
        }
    }
}
有帮助吗?

解决方案

How would I fix this bug?

Not really a bug as much as incompatiblity.

If there is an alternative to KeyListener that will do the same thing, please let me know and preferably provide an example of how it would work.

Dont use KeyListener/KeyAdapter for Swing components as there is focus issues, which can be gotten around by calling requestFocusInWindow() on the component after its visible to make sure it has focus and of course setFoucsable(true); must be called if component is not focusable like a JLabel.

Swing components should use KeyBindings, which overcomes the above mentioned problems by automatically calling setFocusable(true) on the component to which KeyBinding is added etc.

Here is a small example:

void addKeyBinding(JComponent jc) {
        jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "A pressed");
        jc.getActionMap().put("esc pressed", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                System.out.println("A pressed");
            }
        });

        jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "A released");
        jc.getActionMap().put("A released", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                System.out.println("A released");
            }
        });
}

you would call this method with the instance of the JComponent i.e JPanel etc that you want to add the Keybinding too:

JPanel p=new JPanel();

addKeyBinding(p);

Other suggestions on code:

  • Always create Swing components on Event Dispatch Thread via SwingUtilities.invokeXXX block

  • Dont implement an Listener like ActionListener on the class itself unless this class will be used as a Listener only, or you want to expose the implementing classes/Listeners methods to other classes.

其他提示

The JFrame consists of many different components and, as such, is not inheirently focusable. Without focus, it can not receive key events. There are a lot of solutions to this. I'm only going to suggest this one:

Unresponsive KeyListener for JFrame

And I'll suggest you google "keylistener on jframe java" to find some more info. Like I said, there are a lot of ways to tackle this problem.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top