【问题标题】:JTextField vs JComboBox behaviour in JTableJTable 中的 JTextField 与 JComboBox 行为
【发布时间】:2012-09-26 04:32:15
【问题描述】:

好的,这很难解释,但我会尽力而为。

我在 JTable 中有一个 JTextField 和一个 JComboBox,其 getCellEditor 方法已被覆盖如下:

public TableCellEditor getCellEditor( int row, int column ) {
        if ( column == 3 ) {
              // m_table is the JTable

              if ( m_table.getSelectedRowCount() == 1 ) {             
                JComboBox choices = new JComboBox();
                choices.setEditable( true );
                choices.addItem( new String( "item 1" ) );

                return new DefaultCellEditor( choices );
         }

         return super.getCellEditor( row, column );
}

以下是行为差异(请注意,从现在开始,当我说 JTextField 或 JComboBox 时,我指的是包含任一组件的 JTable 中的 CELL):

  1. 当我在 JTextField 上单击一次时,单元格会突出显示。双击会弹出插入符号,我可以输入文本。而对于 JComboBox,单击会调出插入符号以输入文本,以及组合下拉按钮。

  2. 当我使用 Tab 键或使用箭头键导航到 JTextField 然后开始键入时,我键入的字符会自动输入到单元格中。然而,当我以相同的方式导航到 JComboBox 然后开始输入时,除了出现组合下拉按钮之外什么都没有发生。除非我先按 F2,否则我输入的任何字符都不会被输入。

所以这是我的问题:我需要做什么才能让 JComboBoxes 在上述两个实例中的行为与 JTextFields 完全一样?

请不要问我为什么要做我正在做的事情或建议替代方案(它就是这样,我需要这样做),是的,我已经阅读了所有相关组件的 API。 ...问题是,它是一个 Swing API。

【问题讨论】:

    标签: swing jtable jcombobox jtextfield


    【解决方案1】:

    进一步谷歌搜索导致我看到以下文章:

    http://www.jroller.com/santhosh/entry/keyboard_handling_in_tablecelleditor

    虽然它没有描述与我相同的问题,但它肯定具有一些共同特征。

    使用那篇文章中的一些建议,我能够(至少)解决我的问题的键盘位(我的问题第 2 点中描述的那个)。我通过覆盖JTableprocessKeyBinding 方法来做到这一点,如下所示:

    protected boolean processKeyBinding( KeyStroke key_stroke, KeyEvent e, int condition, boolean pressed ) {
            Object source = e.getSource();
    
            if ( source instanceof JTable ) {
              JTable table = (JTable) source;
              Component comp = table.getEditorComponent();
    
              if ( comp instanceof JComboBox ) {
                JComboBox combo_box = (JComboBox) comp;
    
                // this bit is quite hacky. Since I want comboboxes to behave exactly like textfields,
                // simply check to see how a textfield would handle this event.
                JTextField tmp_field = new JTextField();
                InputMap input_map = tmp_field.getInputMap( condition );
                ActionMap action_map = tmp_field.getActionMap();
    
                if( input_map != null && action_map != null && isEnabled() ) {
                    Object binding = input_map.get( key_stroke );
                    Action action = ( binding == null ) ? null : action_map.get( binding );
    
                    if( action != null ) {
                        combo_box.requestFocus();
                        ComboBoxEditor combo_editor = combo_box.getEditor();
                        JTextField text_field = (JTextField) combo_editor.getEditorComponent();
    
                        if ( e.getKeyChar() == ' ' ) {    // backspace
                          String cur_val = text_field.getText();
                          if ( ! cur_val.equals( "" ) )
                            text_field.setText( cur_val.substring( 0, cur_val.length() - 1 ) );
                        }                          
                        else
                          text_field.setText( text_field.getText() + e.getKeyChar() );
    
                        return false;
                    }
                }
              }
            }
    
            return super.processKeyBinding( key_stroke, e, condition, pressed );
    }
    

    这种方法对我来说似乎有点 hack,但它又是摇摆不定的,所以它可能是合理的。

    如果有人想尝试一下,在我的问题第 1 点(即使用鼠标时)描述的场景中,让 JComboBoxes 表现得像 JTextFields 的问题仍然存在。

    【讨论】:

    • 事实证明......什么都没有。我想我只是忘记尝试了。再次感谢克莱奥。由于我对 stackoverflow 还很陌生,所以我不确定在这种情况下该怎么做,评论结果是可以接受的答案。
    【解决方案2】:

    项目符号 2 的替代方法是将所有 keyEvents 传递移动到自定义 JComboBox 实现中:在那里,实现其 processKeyBinding 类似于 table.processKeyBinding。比如:

    public static class JTableEditorComboBox extends JComboBox {
    
        @Override
        protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
                int condition, boolean pressed) {
            boolean result = super.processKeyBinding(ks, e, condition, pressed);
            if (!result) 
                result = processKeyBindingForTextField(ks, e, condition, pressed);
            return result;
        }
    
        private boolean processKeyBindingForTextField(KeyStroke ks, KeyEvent e,
                int condition, boolean pressed) {
            // sanity check: really used as cellEditor
            if (!Boolean.TRUE.equals(getClientProperty("JComboBox.isTableCellEditor")) 
                   || !isEditable() 
                   || !(getEditor().getEditorComponent() instanceof JTextField)) return false;
            JTextField field = (JTextField) getEditor().getEditorComponent();
            // basically c&p JComponent.processKeyBinding (it's protected so
            // can't call directly from here)
            InputMap map = field.getInputMap(WHEN_FOCUSED);
            ActionMap am = field.getActionMap();
    
            if(map != null && am != null && isEnabled()) {
                Object binding = map.get(ks);
                Action action = (binding == null) ? null : am.get(binding);
                if (action != null) {
                    return SwingUtilities.notifyAction(action, ks, e, field,
                                                       e.getModifiers());
                }
            }
    
            return false;
        }
    
    }
    

    然后,在你的 cellEditor 中使用它的一个实例,例如:

    JTable table = new JTable(new AncientSwingTeam()) {
    
        @Override
        public TableCellEditor getCellEditor(int row, int column) {
            if (column == 1) {
                // m_table is the JTable
    
                JComboBox choices = new JTableEditorComboBox();
                choices.setEditable(true);
                choices.addItem(new String("item 1"));
    
                DefaultCellEditor editor = new DefaultCellEditor(choices);
                editor.setClickCountToStart(2);
                return editor;
            }
    
            return super.getCellEditor(row, column);
        }
    
    };
    

    【讨论】:

    • +1。谢谢克莱奥。这似乎是一个更好的选择,因为特定于 JComboBoxs 的键盘事件的所有处理都是在 JComboBox 扩展中完成的。
    猜你喜欢
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多