按下其他键后,JButton键侦听器不会触发
我正在用Java创建一个虚拟钢琴。 到目前为止,我有两个按键的动作监听器,它们大部分都在工作,而不是一个接一个。 例如,我在键盘上点击q
然后按下c
键并播放ac,这就是它应该做的事情。 但是我想通过按键盘上的w
来敲击钢琴上的d键,如果我已经按下q
键,它就不会这样做。
// c key JButton btnC3 = new JButton(""); btnC3.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_Q) { btnC3.doClick(); } } }); btnC3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // play c try { keys.playNote(Notes.c3.getValue()); } catch (InterruptedException e1) { e1.printStackTrace(); } catch (InvalidMidiDataException e2) { e2.printStackTrace(); } } }); // d key JButton btnD3 = new JButton(""); btnD3.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_W) { btnD3.doClick(); } } }); btnD3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // play d try { keys.playNote(Notes.d3.getValue()); } catch (InterruptedException e1) { e1.printStackTrace(); } catch (InvalidMidiDataException e2) { e2.printStackTrace(); } } }); btnD3.setBackground(Color.WHITE); btnD3.setBounds(wKeyWidth*1, 0, wKeyWidth, wKeyHeight); frame.getContentPane().add(btnD3);
问题与键盘焦点有关, KeyListener
只会在侦听器注册到IS可聚焦和HAS焦点时生成事件。
显然,当“点击”按钮时,它会获得焦点,这意味着其他任何组件都无法响应。
基本答案是,使用Use Key Bindings API 。
您可以做出许多选择,您可以使用当前容器来注册密钥绑定,例如……
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW); ActionMap am = getActionMap(); JButton btnC3 = new JButton(""); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), "c3"); am.put("c3", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { btnC3.doClick(); } }); btnC3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // play c try { keys.playNote(Notes.c3.getValue()); } catch (InterruptedException e1) { e1.printStackTrace(); } catch (InvalidMidiDataException e2) { e2.printStackTrace(); } } }); JButton btnD3 = new JButton(""); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "d3"); am.put("d3", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { btnD3.doClick(); } });
或者您可以在各个组件中注册它们。 选择主要取决于您希望解决方案的可重用性。
例如,您可以创建一个可以应用于JButton
和键绑定的Action
,这意味着您无需以编程方式单击该按钮。
例如…
public class NoteAction extends AbstractAction { private Note note; private Keys keys; public NoteAction(Note note, Keys keys) { this.note = note; this.keys = keys; } @Override public void actionPerformed(ActionEvent e) { keys.playNote(note.getValue()); } }
(我没有你的代码,所以我只是制作一些类名)
然后你可以简单地使用……
NoteAction noteAction = new NoteAction(Notes.d3, keys); JButton btnC3 = new JButton(noteAction); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), "c3"); am.put("c3", noteAction);
设置它。
有关详细信息,请参见如何使用操作
重点是问题。 按下q时它会起作用,因为该按钮具有焦点。 如果按下w,无论是否先按q,它都无法工作,因为“q”按钮始终具有焦点。 您应该使用KeyBindings。 尽管任何组件都有重点,它们仍可正
另一个解决方案是将q和w按钮按下添加到添加到JFrame上的keylistener并使用requestFocus()和grabFocus()。
但是您需要为JFrame中的keylistener添加实现,并为按钮按下和释放按钮。
这里有一个完美的链接,可以看到焦点如何影响按键在挥杆时的工作方式
http://www.javaworld.com/article/2076720/core-java/focus-on-swing.html