Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8146323

ComboBox should propagate ENTER key press up to container

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • 14
    • 8u65, 9
    • client-libs

      FULL PRODUCT VERSION :


      ADDITIONAL OS VERSION INFORMATION :
      Non-OS specific

      A DESCRIPTION OF THE PROBLEM :
      When you press the ENTER key in a ComboBox when the popup is not visible, the key press is redirected to the default button. This is fine in most cases (as requested in RFE 4515752), but when you have a component above the ComboBox that wants to handle the ENTER key it never receives it.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile and run the attached source. When the ComboBox has the focus and the popup is not visible, press ENTER.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The panel action should be invoked (shows a dialog containing "Panel enter action performed"). This is how pressing ENTER works in the TextField following the CombBox.
      ACTUAL -
      The default button action is invoked (shows a dialog containing "Button Action Performed").

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package test;

      import java.awt.event.ActionEvent;
      import java.awt.event.KeyEvent;
      import javax.swing.AbstractAction;
      import javax.swing.Action;
      import javax.swing.JComponent;
      import javax.swing.JOptionPane;
      import javax.swing.KeyStroke;
      import javax.swing.SwingUtilities;

      public class ComboBoxEnterBinding extends javax.swing.JFrame {
          private static final String ENTER_ACTION = "enterAction";

          public ComboBoxEnterBinding() {
              initComponents();
              SwingUtilities.getRootPane(button).setDefaultButton(button);
              panel.enableInputMethods(true);
              panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
                  put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), ENTER_ACTION);
              Action enterAction = new AbstractAction() {
                  @Override
                  public void actionPerformed(ActionEvent e) {
                      JOptionPane.showMessageDialog(panel, "Panel enter action performed");
                  }
              };
              panel.getActionMap().put(ENTER_ACTION, enterAction);
          }

          @SuppressWarnings("unchecked")
          // <editor-fold defaultstate="collapsed" desc="Generated Code">
          private void initComponents() {

              button = new javax.swing.JButton();
              panel = new javax.swing.JPanel();
              comboBox = new javax.swing.JComboBox();
              jTextField1 = new javax.swing.JTextField();
              editableCheckbox = new javax.swing.JCheckBox();

              setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

              button.setText("Default");
              button.addActionListener(new java.awt.event.ActionListener() {
                  public void actionPerformed(java.awt.event.ActionEvent evt) {
                      buttonActionPerformed(evt);
                  }
              });

              panel.setBorder(javax.swing.BorderFactory.createTitledBorder("Panel Handles ENTER Key"));

              comboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "ENTER should propagate up to panel", "Even when editable", "Unless popup is open", "And then it should close without propagating" }));

              javax.swing.GroupLayout panelLayout = new javax.swing.GroupLayout(panel);
              panel.setLayout(panelLayout);
              panelLayout.setHorizontalGroup(
                  panelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                  .addGroup(panelLayout.createSequentialGroup()
                      .addContainerGap()
                      .addGroup(panelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                          .addComponent(comboBox, 0, 359, Short.MAX_VALUE)
                          .addComponent(jTextField1))
                      .addContainerGap())
              );
              panelLayout.setVerticalGroup(
                  panelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                  .addGroup(panelLayout.createSequentialGroup()
                      .addContainerGap()
                      .addComponent(comboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                      .addGap(18, 18, 18)
                      .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)
                      .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
              );

              editableCheckbox.setText("Editable ComboBox");
              editableCheckbox.addActionListener(new java.awt.event.ActionListener() {
                  public void actionPerformed(java.awt.event.ActionEvent evt) {
                      editableCheckboxActionPerformed(evt);
                  }
              });

              javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
              getContentPane().setLayout(layout);
              layout.setHorizontalGroup(
                  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                  .addGroup(layout.createSequentialGroup()
                      .addContainerGap()
                      .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                          .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                          .addGroup(layout.createSequentialGroup()
                              .addComponent(editableCheckbox)
                              .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                              .addComponent(button)))
                      .addContainerGap())
              );
              layout.setVerticalGroup(
                  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                  .addGroup(layout.createSequentialGroup()
                      .addContainerGap()
                      .addComponent(panel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                      .addGap(18, 18, 18)
                      .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                          .addComponent(editableCheckbox)
                          .addComponent(button))
                      .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
              );

              pack();
          }// </editor-fold>

          private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
              JOptionPane.showMessageDialog(this, "Button Action Performed");
          }

          private void editableCheckboxActionPerformed(java.awt.event.ActionEvent evt) {
              comboBox.setEditable(editableCheckbox.isSelected());
          }

          /**
           * @param args the command line arguments
           */
          public static void main(String args[]) {
              /* Create and display the form */
              java.awt.EventQueue.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      new ComboBoxEnterBinding().setVisible(true);
                  }
              });
          }

          // Variables declaration - do not modify
          private javax.swing.JButton button;
          private javax.swing.JComboBox comboBox;
          private javax.swing.JCheckBox editableCheckbox;
          private javax.swing.JTextField jTextField1;
          private javax.swing.JPanel panel;
          // End of variables declaration
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      A messy workaround for an editable ComboBox is to add a key listener to the editor component and redispatch the ENTER key pressed event to the parent of the combobox.

      This could be fixed by modifying BasicComboBoxUI.Actions.actionPerformed to dispatch the ENTER pressed KeyEvent to the parent of the ComboBox rather than directly invoking the root pane ENTER action. In cases where there is no ENTER key binding in containing components, this would still invoke the default button action when processing key bindings for the root pane.

            ssrivastava Swati Srivastava (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: