How to handle incoming data for JTable while editing a row?
imagine we have a client/server multiuser architecture. At any time a user is able to add a new TableRow in his JTable. The server gets informed and sends a message to all clients, so their data (meaning their tableviews) are getting updated as well. This works perfectly fine, unless a user is currently editing a row in that table, while becoming an updateEvent.
When开发者_JAVA百科 the new tableRow is above the currenty edited row from the user, the respective cell changes as well, but the tableEditor doesnt notice this and therefore the wrong row is beeing edited and changed now.
I created a small example to break this problem down to some lines of code, so it might be easier to follow me:
public class TableEventHandlingExample extends JPanel
{
static JFrame frame;
JTable table;
public TableEventHandlingExample()
{
table = new JTable( new StandardTableModel( createTestData() ) );
final Thread thread = new Thread( new Runnable()
{
@Override
public void run()
{
try
{
while ( true )
{
Thread.sleep( 5000 );
((StandardTableModel) table.getModel()).addRow( new Data( 4, "Vier" ), 0 );
}
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
} );
thread.start();
add( new JScrollPane( table ) );
}
private List<Data> createTestData()
{
Data data1 = new Data( 1, "Eins" );
Data data2 = new Data( 2, "Zwei" );
Data data3 = new Data( 3, "Drei" );
List<Data> dataList = new ArrayList<Data>();
dataList.add( data1 );
dataList.add( data2 );
dataList.add( data3 );
return dataList;
}
public static void main( String[] args )
{
frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setLayout( new BorderLayout() );
frame.setBounds( 400, 400, 500, 500 );
frame.add( new TableEventHandlingExample() );
frame.setVisible( true );
}
}
class StandardTableModel extends AbstractTableModel
{
List<Data> dataList;
public StandardTableModel( List<Data> dataList )
{
this.dataList = dataList;
}
@Override
public int getColumnCount()
{
return 2;
}
@Override
public int getRowCount()
{
return dataList.size();
}
@Override
public boolean isCellEditable( int rowIndex, int columnIndex )
{
return true;
}
@Override
public Class<?> getColumnClass( int columnIndex )
{
if ( columnIndex == 0 )
return Integer.class;
return String.class;
}
@Override
public Object getValueAt( int rowIndex, int columnIndex )
{
if ( columnIndex == 0 )
return dataList.get( rowIndex ).getId();
return dataList.get( rowIndex ).getName();
}
@Override
public void setValueAt( Object aValue, int rowIndex, int columnIndex )
{
Data data = dataList.get( rowIndex );
if ( columnIndex == 0 )
data.setId( (Integer) aValue );
else
data.setName( (String) aValue );
}
public void addRow( Data data, int index )
{
if ( index > dataList.size() )
{
return;
}
dataList.add( index, data );
fireTableRowsInserted( index, index );
}
}
class Data
{
private int id;
private String name;
public Data( int id, String name )
{
this.id = id;
this.name = name;
}
public int getId()
{
return id;
}
public void setId( int id )
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName( String name )
{
this.name = name;
}
@Override
public String toString()
{
return getName();
}
}
To fake the incoming Data-Events I used a thread, which adds a new row on position 1 every 5 seconds. Good enough to show what the problem is.
Do you have any suggestions how to handle this? Should I disallow updateEvents as long as the table gets edited and execute the updateEvents afterwards? But what will I do, when the user stays in edit-mode for like 5 minutes? Exectuting all update-Events he missed could get kinda painful. Do you maybe have any other ideas?
Thank you in advance! ymene
Have you considered just setting the cell being edited to the correct one? In your example it's fairly easy because you are always adding new cells at 0.
while ( true ) {
Thread.sleep( 5000 );
table.setEditingRow(table.getEditingRow() + 1);
((StandardTableModel) table.getModel()).addRow( new Data( 4, "Vier" ), 0 ); }
For the case where an arbitrary insert is taking place (not at row 0), you will have to add a check if the row being inserted is above or below the one that's currently being edited
I suggest you to use SwingWorker !
It enables to do some work outside the EDT, and then your JTable is updated in real time as other users adds row !
Best regards
精彩评论