【问题标题】:How to accept a value in a Swing JComboBox with the Tab key如何使用 Tab 键接受 Swing JComboBox 中的值
【发布时间】:2014-06-20 22:51:30
【问题描述】:

当您键入 Tab 键时,如何让 Java 组合框接受突出显示的值,就像您键入 Enter 时一样? 我认为这是一种 UI 规范,并且在网站和桌面程序上看到过,所以我不明白为什么 Java 默认不这样做。 (退出键是用来取消的。)

我发现了几个与此相关的问题,包括如何让 Enter 表现得像 Tab 一样,但结果证明反过来更难,所以我将发布我是如何做到的。也许我错过了一个简单的方法!

特别是,the closest posting I could find 不起作用,因为焦点系统已经使用了 tab 键。 其他相关问题有herehere,也许还有一些提示here

【问题讨论】:

    标签: java swing focus jcombobox keylistener


    【解决方案1】:

    这很棘手,因为 Enter 键处理是多么难以访问。它发生在BasicComboBoxUI.actionPerformed() 的一棵大 if-else 树中。这是它从也无法访问的弹出菜单中将值拉入组合框的地方。这也很棘手,因为焦点遍历关键事件在您对它们进行任何操作之前就被消耗掉了。

    要让它工作,我必须从焦点遍历键集中删除 Tab,覆盖 JComboBox 上的 processKeyEvent(),然后抱歉! 将假的 Enter-key 事件传递给超类,以便让 UI 执行通常对 Enter 执行的操作。然后我不得不手动处理焦点转换。

    这里有一些代码。 (我以同样的方式处理了 shift-tab/backwards 焦点遍历,这可能是矫枉过正。)

    protected final JComboBox combobox = new JComboBox() {
        @Override
        public void processKeyEvent(KeyEvent e) {           
            if ( e.getID() != KeyEvent.KEY_PRESSED
                    || e.getKeyCode() != KeyEvent.VK_TAB) {
                super.processKeyEvent(e);
                return;
            }
    
            if (isPopupVisible()) {
                assert e.getSource() instanceof Component;
                KeyEvent fakeEnterKeyEvent = new KeyEvent((Component) e.getSource(),
                        e.getID(),
                        e.getWhen(),
                        0,                   // No modifiers.
                        KeyEvent.VK_ENTER,   // Enter key.
                        KeyEvent.CHAR_UNDEFINED);
                super.processKeyEvent(fakeEnterKeyEvent);
            }
            if ( e.getModifiers() == 0) {
                transferFocus();
            } else if ( e.getModifiers() == KeyEvent.SHIFT_MASK) {
                transferFocusBackward();
            }
        }
    };
    
    // Remove tabs from focus traversal keylists.
    // Forward.
    Set<AWTKeyStroke> focuskeys = Sets.newHashSet(combobox.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
    KeyStroke lTabKeystroke = KeyStroke.getKeyStroke("pressed TAB");
    focuskeys.remove(lTabKeystroke);
    combobox.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, focuskeys);
    // Backward.
    focuskeys = Sets.newHashSet(combobox.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
    KeyStroke lShiftTabKeystroke = KeyStroke.getKeyStroke("shift pressed TAB");
    focuskeys.remove(lShiftTabKeystroke);
    combobox.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, focuskeys);
    

    【讨论】:

      【解决方案2】:

      Swing 使用键绑定来为不同的 KeyStroke 调用动作。 JComboBox 有一个用于 ENTER 键的操作。请参阅Key Bindings 上的所有绑定列表。

      所以我认为这将是一个将 ENTER 操作绑定到另一个 KeyStroke 的简单案例。

      果然,当我将 ENTER 操作绑定到 RIGHT 箭头键时,功能按预期工作。

      但是,当我将 Enter 操作绑定到 TAB 键时,它不起作用。但是,弹出菜单仍然关闭。所以现在我想知道 TAB 键是否由另一个组件处理以关闭阻止新 TAB 键绑定工作的菜单。也许其他人对此有所了解?

      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import javax.swing.plaf.basic.*;
      
      public class ComboBoxTest2 extends JFrame
      {
          JComboBox comboBox;
          JTextField textField;
          String[] tabs;
          public ComboBoxTest2()
          {
              String[] tabs = { "a", "b", "c", "d", "e", "f", "g" };
      
              DefaultComboBoxModel model = new DefaultComboBoxModel(tabs);
              comboBox = new JComboBox( model );
              add(comboBox, BorderLayout.NORTH);
              add( new JButton("A Component To Tab To"), BorderLayout.SOUTH);
      
              //  This works
      
              InputMap im = comboBox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
              KeyStroke existingKeyStroke = KeyStroke.getKeyStroke("ENTER");
              KeyStroke rightKS = KeyStroke.getKeyStroke("RIGHT");
              im.put(rightKS, im.get(existingKeyStroke));
      
              //  This doesn't work
      
              comboBox.setFocusTraversalKeysEnabled(false);
              KeyStroke tabKS = KeyStroke.getKeyStroke("TAB");
              im.put(tabKS, im.get(existingKeyStroke));
          }
          public static void main(String[] args)
          {
              JFrame frame = new ComboBoxTest2();
              frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
              frame.pack();
              frame.setLocationRelativeTo( null );
              frame.setVisible( true );
           }
      }
      

      【讨论】:

      • 您好,感谢您的跟进!我没有提到的一件事:当我尝试你的解决方案时,我实际上得到了 im.get(ENTER) 的 null。不过,我看到了不同之处:我使用 WHEN_FOCUSED 来获取输入映射,而不是 WHEN_ANCESTOR_OF。我现在尝试了 WHEN_ANCESTOR 并且确实看到了非空绑定。但是,就像您在此处报告的那样,为 TAB 设置相同的绑定不起作用。 (还有一点需要注意:我认为 Tab 和 Enter 在不显示弹出窗口的情况下应该表现不同。我认为在这种情况下只有 tab 应该将焦点推进到下一个组件。)
      猜你喜欢
      • 2014-03-13
      • 2012-09-15
      • 1970-01-01
      • 2020-11-11
      • 1970-01-01
      • 2016-08-15
      • 1970-01-01
      • 1970-01-01
      • 2013-09-20
      相关资源
      最近更新 更多