Problem with JTable inside JInternalFrame
I'm having a problem with a JTable inside a JInternalFrame. The cell editor sometimes does not pop up when it should.
I have a dialog that includes a JTable. The JTable has custom renderers and editors for each column. The JTable is inside a JScrollPane, and the JScrollPane and several other components are contained in a JInternalFrame.
If I click on a cell, the editor should appear, but it doesn't. I can trace through the code and determine that getTableCellEditorComponent is being called, and add(editorComp) is being called within JTable.editCellAt. Yet the component doesn't ever appear. It's as if it were invisible.
The problem appears to be related to focus. If I click on one of the other components in the JInternalFrame, and tab until one of the cells in the JTable is highlighted, everything works fine. Then if I click on one of the other components again, the JTable stops working again. It seems JInternalFrame isn't handling focus properly, and that somehow affects display of the editor component.
If I base my editor on a DefaultCellEditor instead of an AbstractCellEditor, everything works in the default configuration, but it fails if I set getClickCountToStart(1);
If I place the identical code inside a JDialog, everything works fine. The problem only appears within a JInternalFrame.
Does anyone have insight into what may be happening, or a workaround?
Here's some code, if it helps...
Code:
public class EnsembleMatrixDialog extends JInternalFrame
{
public EnsembleMatrixDialog( JFrame ownerFrame )
{
super( "Ensemble matrix", false, true, false, true );
setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE );
setLayout( null );
ownerFrame.addWindow( this );
// ... Add some components
JTable theTable = new EnsembleTable();
JScrollPane scrollPane = new JScrollPane( theTable );
add( scrollPane );
scrollPane.setBounds( 25, y, 300, 300 );
setBounds( windowX, windowY, width, height );
setVisible( true );
try
{
setIcon( false );
setSelected( true );
}
catch ( Exception e ) {}
}
private class EnsembleTable extends JTable
{
public EnsembleTable()
{
super( ensembleTableModel );
putClientProperty( "terminateEditOnFocusLost", Boolean.TRUE );
setDefaultRenderer( String.class, new TextRenderer() );
setDefaultEditor( String.class, new StringCellEditor() );
}
}
private TableModel ensembleTableModel = new AbstractTableModel()
{
public int getRowCount()
{
return selectedEnsembles.size();
}
public int getColumnCount()
{
return 1;
}
public Class<?> getColumnClass( int column )
{
if ( column == 0 )
return String.class;
}
public Object getValueAt( int row, int column )
{
if ( column == 0 )
return selectedEnsembles.get( row ).getID();
}
public boolean isCellEditable( int row, int column )
{
return true;
}
public void setValueAt( Object value, int row, int column )
{
if ( column == 0 )
{
if ( selectedEnsembles.get( row ).setID( (String)value ) )
ownerWeek.getFrame().update();
else
Utils.beep();
}
}
};
private static Border focusedBorder = UIManager.getBorder("Table.focusCellHighlightBorder");
public class TextRenderer extends DefaultTableCellRenderer
{
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column)
{
setText( selectedEnsembles.get( row ).getID() );
return this;
}
}
private class StringCellEditor extends AbstractCellEditor implements TableCellEditor
{
JTextField field = null;
public StringCellEditor()
{
field = new JTextField();
field.setBorder( focusedBorder );
}
public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected,
int argRow, int argColumn )
{
field.setText( (String)value );
return field;
}
public String getCellEditorValue()
{
return field.getText();
}
}