我有一个单元格编辑器,它由JPanel上的几个组件组成。当我的自定义单元格编辑器停止编辑时,表将失去焦点,而不是将焦点转移到下一个单元格。
这是一个简单的例子。键入每个单元格并在表格中选项卡。请注意,在访问第3列后,该表将失去焦点到面板上的另一个文本字段。
更新:此问题似乎在Java7中已得到修复。必须使用Java 6运行该示例才能查看焦点丢失行为。
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.AbstractCellEditor;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;
import javax.swing.text.JTextComponent;
public class TableEditorFocusExample extends JFrame
{
private JTable m_table;
private TableModel tableModel;
public TableEditorFocusExample()
{
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
{
@Override
public void eventDispatched( AWTEvent event )
{
System.out.println( "FOCUS " +
event +
"\n source=" +
event.getSource() );
}
}, AWTEvent.FOCUS_EVENT_MASK | AWTEvent.WINDOW_FOCUS_EVENT_MASK );
tableModel = new DefaultTableModel( 4, 4 );
m_table = new JTable( tableModel )
{
@Override
public void changeSelection(
int row,
int column,
boolean toggle,
boolean extend )
{
super.changeSelection( row, column, toggle, extend );
if ( editCellAt( row, column ) )
{
Component editor = getEditorComponent();
editor.requestFocusInWindow();
if ( editor instanceof JTextComponent )
{
( (JTextComponent)editor ).selectAll();
}
}
}
};
m_table.setModel( tableModel );
m_table.setSurrendersFocusOnKeystroke( true );
m_table.putClientProperty( "terminateEditOnFocusLost", Boolean.TRUE ); //$NON-NLS-1$
DefaultCellEditor textFieldCellEditor = new DefaultCellEditor( new JTextField() );
textFieldCellEditor.setClickCountToStart( 1 );
TableCellEditor panelBasedCellEditor = new PanelCellEditor();
m_table.getColumnModel().getColumn( 0 ).setCellEditor( textFieldCellEditor );
m_table.getColumnModel().getColumn( 1 ).setCellEditor( textFieldCellEditor );
m_table.getColumnModel().getColumn( 2 ).setCellEditor( panelBasedCellEditor );
m_table.getColumnModel().getColumn( 3 ).setCellEditor( textFieldCellEditor );
m_table.setColumnSelectionAllowed( true );
final JButton ok = new JButton( "reset" );
JPanel panel = new JPanel();
panel.add( m_table );
// add a component to grab focus when the table editor loses focus
final JTextField textField = new JTextField( 8 );
final Color origTextColor = textField.getBackground();
textField.addFocusListener( new FocusAdapter()
{
@Override
public void focusGained( FocusEvent e )
{
System.err.println( "focus gained from: " + e.getSource() );
textField.setBackground( Color.red );
}
} );
// reset the text field background color to the pre-focus color
ok.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
textField.setBackground( origTextColor );
}
} );
panel.add( textField );
panel.add( ok );
getContentPane().add( panel );
}
public class PanelCellEditor extends AbstractCellEditor implements
TableCellEditor
{
public PanelCellEditor()
{
m_textfield.setBackground( Color.green );
m_panel = new JPanel( new GridLayout() )
{
@Override
public boolean requestFocusInWindow()
{
// when the table transfers focus to the editor,
// forward focus onto the text field.
return m_textfield.requestFocusInWindow();
}
};
m_panel.add( m_textfield );
}
@Override
public Object getCellEditorValue()
{
return m_textfield.getText();
}
@Override
public Component getTableCellEditorComponent(
JTable table,
Object value,
boolean isSelected,
int row,
int column )
{
m_textfield.setText( value == null ? "" : value.toString() );
return m_panel;
}
private JPanel m_panel;
private JTextField m_textfield = new JTextField( 5 );
}
public static void main( String[] args )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
TableEditorFocusExample test = new TableEditorFocusExample();
test.setSize( 600, 300 );
test.setVisible( true );
}
} );
}
}
我发现了一个类似的问题here,但解决方案似乎不完整,因为自定义编辑器上的文本字段没有焦点,其光标不显示使用户不清楚该字段可用于输入文字。
任何人都有更好的解决方案吗?
答案 0 :(得分:1)
很好的挖掘: - )
对于jdk6,您可以考虑使用SwingX and its JXTable修复该问题(刚检查过,忘记了我们已经解决了一些焦点问题:-)。或者,如果这不是一个选项,请查看其代码并复制重写的transferFocus(及相关)方法和改进的EditorRemover。
不要忘记让你的编辑遵守合同:
Action action = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
};
m_textfield.setAction(action);