使用复合 JPanel 单元格编辑器进行编辑后,JTable 失去焦点
我有一个单元格编辑器,它由 JPanel 上的多个组件组成。当我的自定义单元格编辑器停止编辑时,表格会失去焦点,而不是将焦点转移到下一个单元格。
这是一个简单的例子。在表格的每个单元格和选项卡中键入内容。请注意,访问第三列后,表格将焦点移至面板上的另一个文本字段。
更新:这个问题似乎在 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 );
}
} );
}
}
我在此处发现了类似的问题,但解决方案似乎不完整,因为自定义编辑器没有焦点,其光标不显示,使用户不清楚该字段可用于文本输入。
有人有更好的解决方案吗?
I have a cell editor that is composed of several components on a JPanel. When my custom cell editor stops editing, the table loses focus instead of transfering focus to the next cell.
Here's a simple example. Type into each cell and tab through the table. Notice that after visiting the 3rd column, the table loses focus to another text field on the panel.
Update: This issue appears to be fixed in Java7. The example must be run with Java 6 to see the focus lost behavior.
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 );
}
} );
}
}
I found a similar question here, but the solution seems to be incomplete since the text field on the custom editor doesn't have focus, its cursor doesn't display making it unclear to the user that the field is available for text entry.
Anyone have a better solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
很好的挖掘:-)
对于jdk6,您可能会考虑使用 SwingX 及其 JXTable ,它已经解决了该问题(刚刚检查过,忘记我们已经解决了一些焦点问题:-)。或者,如果这不是一个选项,请查看其代码并复制重写的transferFocus(及相关)方法和改进的EditorRemover。
并且不要忘记让您的编辑遵守其合同:
nice digging :-)
For jdk6 you might consider using SwingX and its JXTable which has that problem fixed (just checked, forgot we had worked around some focus issues :-). Or, if that's not an option, look at its code and copy the overridden transferFocus (and related) methods and the improved EditorRemover.
And don't forget to make your editor comply to its contract: