8

我想控制哪个击键属于哪个Jcomponent. 我什至想知道如何删除与 a 关联的默认击键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

因为firstButton我删除了SPACE印刷机的效果;我添加了 key F,所以现在firstButton当你按下F键盘上的键时,ant 没有响应SPACE(有意)。请注意,F即使firstButton没有焦点,也会发生按下 ( 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<Integer> 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 的默认击键的原因是因为我想删除SPACE所有 JComponent 上的默认效果,除了一个按钮会响应SPACE按下,无论焦点在哪里,使用JComponent.WHEN_IN_FOCUSED_WINDOW, 以便单击另一个组件(并将焦点从例外按钮上移开)不会阻止该SPACE按钮上的效果。


另一点:如果您测试了上面的代码,您会注意到从 JComboBox 中选择一个项目需要两行,如果您选择项目“4”,则 JTextArea 中的输出为

Item 4
Item 4

为什么是两个??

谢谢。

4

1 回答 1

5

但是不起作用,它是(JComboBox)仍然响应SPACE键

你应该JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT InputMap这样使用(你可能注意到我使用KeyEventandKeyStroke.getKeyStroke(int key,int modifier,boolean onRelease)因为它更易读,更不容易出错,即输入错误的字符串参数等):

sizesComboBox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
        .put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0,false), "none");

据我所知,原因在这里得到了很好的解释:

组件包含(或是)具有焦点的组件。此输入映射通常用于复合组件——其实现依赖于子组件的组件。例如,JTables 进行所有绑定,WHEN_ANCESTOR_OF_FOCUSED_COMPONENT这样如果用户正在编辑,向上箭头键(例如)仍然会更改选定的单元格。

所以我推断JCombobox是一个复合组件,因此我们需要正确的InputMap-WHEN_ANCESTOR_OF_FOCUSED_COMPONENT来删除其所有内部组件的 KeyBinding 特定键的功能,即SPACE

还有一点:如果您测试了上面的代码,您会注意到从JComboBoxpoduces 中选择一个项目需要两行,如果您选择项目“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
   }
}

其他建议:

  • 不要打电话setSizeJFrame

  • 使用适当的LayoutManager和/或覆盖getPreferredSize来返回Dimension适合内容的 s,并pack()JFrame设置可见之前和添加组件之后调用。

于 2013-01-27T12:53:04.170 回答