【问题标题】:Class extending KeyListener not responding to key presses [duplicate]扩展 KeyListener 的类不响应按键 [重复]
【发布时间】:2012-12-22 16:30:44
【问题描述】:

很抱歉它是重复的 - 我写这篇文章时很着急,没有时间检查。虽然我认为它会更快,但现在我想到了......


可能重复:
Java KeyListener for JFrame is being unresponsive?

我一直在编写一个应用程序并尝试制作热键。我决定使用KeyListener,因为这是我目前所知道的。但是,班级对按键没有反应。我将如何修复这个错误?如果有替代KeyListener 的方法可以做同样的事情,请告诉我,最好提供一个例子来说明它是如何工作的。

主类

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 类

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

【问题讨论】:

  • "如果您觉得没有必要,请随时编辑代码。" - 应该这样做。
  • 您在控制台中看到任何错误吗? hotkeyPressed 方法到底在哪里调用?您要测试哪些键?
  • 快速回答,可以肯定.. 谢谢大家。
  • @LeeMeador 介意将其作为答案,以便我接受吗? :)
  • 您可以使用KeyBinding,如图here。从 Swing 的角度来看,KeyListener 的级别太低了。

标签: java swing jframe keylistener setfocus


【解决方案1】:

我将如何修复这个错误?

与其说是不兼容,不如说是真正的错误。

如果有替代 KeyListener 的方法可以做同样的事情, 请让我知道,最好提供一个例子说明它会如何 工作。

不要将 KeyListener/KeyAdapter 用于 Swing 组件,因为存在焦点问题,这可以通过在组件可见后调用 requestFocusInWindow() 来解决,以确保它具有焦点,当然 setFoucsable(true); 必须如果组件不像JLabel 那样可聚焦,则调用该组件。

Swing 组件应该使用KeyBindings,它通过在添加了KeyBinding 的组件上自动调用setFocusable(true) 等来克服上述问题。

这是一个小例子:

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

您可以使用JComponent 的实例调用此方法,即JPanel 等您也想添加Keybinding

JPanel p=new JPanel();

addKeyBinding(p);

其他代码建议:

  • 始终通过 SwingUtilities.invokeXXX 块在 Event Dispatch Thread 上创建 Swing 组件

  • 不要在类本身上实现Listener,如ActionListener,除非该类将用作Listener,或者您想公开实现类/@ 987654343@ 其他类的方法。

【讨论】:

  • +1 用于键绑定;直到recently 我想argued 游戏可能是一个例外,但我是wrong。 :-)
  • @trashgod +1 hehe Keybindings 是唯一的猜测,我们只需要了解为什么要采用 em,在我的游戏中 KeyListeners 出现许多问题之后,我发现 KeyBindings 最初需要更多输入,但它得到了回报结束
  • 这似乎很适合我的想法。谢谢!但是有没有理由让它成为一个单独的方法而不是在构造函数中添加键绑定?
  • @NickHartley 不只是为了代码的可读性
  • @DavidKroukamp 然后我可能会添加一个数组作为参数,以便更容易定制。谢谢!
【解决方案2】:

JFrame 由许多不同的组件组成,因此,它本身不是可聚焦的。没有焦点,它不能接收关键事件。有很多解决方案。我只推荐这个:

Unresponsive KeyListener for JFrame

我会建议你谷歌“keylistener on jframe java”来查找更多信息。就像我说的,有很多方法可以解决这个问题。

【讨论】:

  • 这不是最佳实践,Swing 组件应该使用键绑定
  • +1 以获得很好的解释,但 @DavidKroukamp 建议 Key Bindings 是正确的。
  • 在链接的文章或谷歌搜索的前几个答案之一中建议使用键绑定。我认为没有理由重复那里所说的一切。很高兴@DavidKroukamp 可以建议尼克最能集中阅读的地方。
猜你喜欢
  • 2016-04-19
  • 2014-06-26
  • 2013-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-09
  • 2014-03-25
相关资源
最近更新 更多