1

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

我在 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。

4

2 回答 2

2

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

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

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

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

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 );
}

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

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

于 2012-10-05T17:12:48.220 回答
2

项目符号 2 的替代方法是将 keyEvents 的所有传递移动到自定义 JComboBox 实现中:在那里,实现类似于 table.processKeyBinding 的 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);
    }

};
于 2012-10-06T15:56:12.120 回答