Java:如何从任何JComponent中删除默认的KeyStrokes?
我想控制哪个击键属于哪个Jcomponent
。 我甚至想知道如何删除与Jcomponent
关联的默认击键,并将其替换为其他喜欢的击键。
我按照这个oracle 教程 ,它给出了一个JButton的例子,我尝试了它并且它工作正常,但是当我用JComboBox尝试它时它不起作用!
我试图删除SPACE键,这是为了防止JComponent响应SPACE按键
我用这段代码删除了SPACE键:
firstButton.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none");
JComboBox也是如此
sizesComboBox.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none");
但是不起作用,它(JComboBox)仍然响应SPACE键
对于我删除了SPACE印刷机效果的firstButton
; 我添加了键F ,所以现在当你按下键盘上的F键时按下了firstButton
,ant没有响应SPACE (意图)。 请注意,即使firstButton
没有焦点,也会发生F的按下( JComponent.WHEN_IN_FOCUSED_WINDOW
)
这是一个显示我的例子的SSCCE代码:
注意 :我故意没有将上面的代码行添加到第二个按钮“secondButton”,因此它默认仍然响应SPACE 。
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.*; public class KeyStrokeTest extends JPanel { JPanel widgetPanel; JPanel textAreaPanel; JButton firstButton; JButton secondButton; JTextArea textArea; JComboBox sizesComboBox; public KeyStrokeTest() { firstButton = new JButton("First"); firstButton.addActionListener(eventWatcher); firstButton.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none"); firstButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F"), "F Key"); firstButton.getActionMap().put("F Key", eventWatcher); secondButton = new JButton("Second"); secondButton.addActionListener(eventWatcher); sizesComboBox = new JComboBox(); sizesComboBox.addItemListener(new itemListenerClass()); for (int i = 1; i <= 8; i++) { sizesComboBox.addItem(i); } sizesComboBox.setSelectedIndex(0); sizesComboBox.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "none"); textArea = new JTextArea(0, 0); JScrollPane scrollTextArea = new JScrollPane(textArea); scrollTextArea.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); textArea.setEditable(false); widgetPanel = new JPanel(); textAreaPanel = new JPanel(new BorderLayout()); widgetPanel.add(firstButton); widgetPanel.add(secondButton); widgetPanel.add(sizesComboBox); textAreaPanel.add(scrollTextArea, BorderLayout.CENTER); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, textAreaPanel, widgetPanel); splitPane.setDividerLocation(280); splitPane.setResizeWeight(.5d); this.setLayout(new BorderLayout()); this.add(splitPane); } AbstractAction eventWatcher = new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { Object source = ae.getSource(); if (source == firstButton) { textArea.append("First button clicked\n"); } if (source == secondButton) { textArea.append("Second button clicked\n"); } } }; private class itemListenerClass implements ItemListener { @Override public void itemStateChanged(ItemEvent e) { if (e.getSource() == sizesComboBox) { if (textArea != null) { textArea.append("Item " + sizesComboBox.getSelectedItem() + "\n"); } } } } private static void createAndShowGUI() { JFrame frame = new JFrame("KeyStroke Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(500, 300); frame.add(new KeyStrokeTest(), BorderLayout.CENTER); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { UIManager.put("swing.boldMetal", Boolean.FALSE); createAndShowGUI(); } }); } }
我想要控制JComponent的默认击键的原因是因为我想在所有JComponent上删除SPACE的默认效果,除了一个按钮,它将响应SPACE按下,无论焦点在哪里,使用JComponent.WHEN_IN_FOCUSED_WINDOW
,因此,单击另一个组件(并将焦点从例外按钮移开)将不会阻止SPACE对该按钮的影响。
另一点 :如果您测试了上面的代码,您会注意到从JComboBox中选择一个项目会产生两行,如果您选择项目“4”,则JTextArea中的输出为
Item 4 Item 4
为什么两个?
谢谢。
但是不起作用,它(JComboBox)仍然响应SPACE键
您应该像这样使用JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
InputMap
(您可能会注意到我使用了KeyEvent
和KeyStroke.getKeyStroke(int key,int modifier,boolean onRelease)
因为它更易读,更不容易出错,即键入错误的字符串参数等。):
sizesComboBox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0,false), "none");
据我所知,这个原因很好地解释了这里 :
该组件包含(或是)具有焦点的组件。 此输入映射通常用于复合组件 – 一个实现依赖于子组件的组件。 例如,
JTable
使用WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
进行所有绑定,这样如果用户正在编辑,则向上箭头键(例如)仍会更改所选单元格。
所以我推断JCombobox
是一个复合组件,因此我们需要正确的InputMap
– WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
,以删除特定键(即SPACE)的所有内部组件KeyBindingfunction。
另一点:如果您测试了上面的代码,您会注意到从
JComboBox
中选择一个项目会产生两行,如果您选择项目“4”,则JTextArea
的输出为Item 4 Item 4
为什么两个?
正如@mKorbel(他的评论+1)所说,有2个事件可能发生:
- 取消选择一个项目
- 选择了一个项目
这些事件成对出现,就像我们选择新值时取消选择旧值一样。 因此,我们必须检查并采取适当行动:
@Override public void itemStateChanged(ItemEvent e) { if(e.getStateChange()==ItemEvent.SELECTED) { //am item was selected do something } }
其他建议:
-
不要在
JFrame
上调用setSize
。 -
使用适当的
LayoutManager
和/或覆盖getPreferredSize
以返回适合内容的Dimension
,并在设置可见之前和添加组件之后调用JFrame
上的pack()
。