Как обрабатывать входящие данные для JTable при редактировании строки? - PullRequest
1 голос
/ 14 декабря 2010

представьте, что у нас многопользовательская архитектура клиент / сервер. В любое время пользователь может добавить новый TableRow в свой JTable. Сервер получает информацию и отправляет сообщение всем клиентам, поэтому их данные (то есть их табличные представления) также обновляются. Это прекрасно работает, если только пользователь не редактирует строку в этой таблице, в то время как становится updateEvent.

Когда новый tableRow находится выше текущей отредактированной строки от пользователя, соответствующая ячейка также изменяется, но tableEditor не замечает этого, и поэтому неправильная строка редактируется и изменяется сейчас.

Я создал небольшой пример, чтобы разбить эту проблему на несколько строк кода, чтобы мне было легче следовать:

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

Для подделки входящих Data-Events я использовал поток, который добавляет новую строку в позицию 1 каждые 5 секунд. Достаточно хорош, чтобы показать, в чем проблема.

У вас есть предложения, как с этим справиться? Должен ли я запретить updateEvents до тех пор, пока таблица редактируется, а потом выполнять updateEvents? Но что я буду делать, когда пользователь будет находиться в режиме редактирования около 5 минут? Извлечение всех обновлений, которые он пропустил, может быть довольно болезненным. Может быть, у вас есть другие идеи?

Заранее спасибо! ymene

Ответы [ 2 ]

2 голосов
/ 04 января 2011

Рассматривали ли вы просто установку редактируемой ячейки на правильную? В вашем примере это довольно просто, потому что вы всегда добавляете новые ячейки в 0.

while ( true ) {
        Thread.sleep( 5000 );
        table.setEditingRow(table.getEditingRow() + 1);
        ((StandardTableModel) table.getModel()).addRow( new Data( 4, "Vier" ), 0 ); }

Для случая, когда происходит произвольная вставка (не в строке 0), вам нужно будет добавить проверку, находится ли вставляемая строка выше или ниже той, которая в данный момент редактируется

0 голосов
/ 22 декабря 2010

Я предлагаю вам использовать SwingWorker!

Это позволяет выполнять некоторую работу вне EDT, а затем ваш JTable обновляется в режиме реального времени, когда другие пользователи добавляют строки!

С уважением

...