JTable中的JTextField与JComboBox行为



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

我在一个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. 当我标记或使用箭头键导航到JTextField,然后开始键入时,我键入的字符会自动输入到单元格中。然而,当我以同样的方式导航到JComboBox,然后开始键入时,除了出现组合下拉按钮外,什么都没有发生。除非我先按F2键,否则我键入的字符都不会被输入。

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

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

进一步的谷歌搜索让我找到了以下文章:

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

这种方法在我看来有点像黑客,但话说回来,它是摇摆的,所以它可能是合理的。

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

灰分

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

最新更新