2010-12-14 37 views
1

Imaginons que nous ayons une architecture multi-utilisateur client/serveur. A tout moment, un utilisateur peut ajouter un nouveau TableRow dans son JTable. Le serveur est informé et envoie un message à tous les clients, de sorte que leurs données (c'est-à-dire leurs vues de table) sont également mises à jour. Cela fonctionne parfaitement, sauf si un utilisateur modifie actuellement une ligne dans cette table, tout en devenant un updateEvent. Lorsque la nouvelle tableRow est au-dessus de la ligne actuellement éditée par l'utilisateur, la cellule respective change également, mais la tableEditor ne le remarque pas et donc la mauvaise rangée est éditée et modifiée maintenant.Comment gérer les données entrantes pour JTable lors de la modification d'une ligne?

J'ai créé un petit exemple pour briser ce problème à quelques lignes de code, il pourrait être plus facile de me suivre:

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

Pour simuler les données-événements entrants j'ai utilisé un fil, ce qui ajoute une nouvelle rangée sur la position 1 toutes les 5 secondes. Assez bon pour montrer quel est le problème.

Avez-vous des suggestions pour gérer cela? Devrais-je refuser updateEvents tant que la table est éditée et exécuter les updateEvents après? Mais que vais-je faire, quand l'utilisateur reste en mode édition pendant 5 minutes? Executer toutes les mises à jour - Les événements qu'il a manqués pourraient devenir un peu douloureux. Avez-vous d'autres idées?

Merci d'avance! ymene

Répondre

2

Avez-vous envisagé de créer simplement la cellule en cours de modification à la bonne? Dans votre exemple, il est assez facile parce que vous êtes toujours ajouter de nouvelles cellules à 0.

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

Pour le cas où un insert arbitraire a lieu (non à la ligne 0), vous devrez ajouter un chèque si la ligne être inséré est au-dessus ou en dessous de celui qui est en cours d'édition

+0

Je ne peux pas croire que c'est simple comme ça. Merci beaucoup, cette solution va me sauver beaucoup de solutions de contournement! Malheureusement, je ne peux pas vous récompenser encore. Il dit que je dois attendre encore 19 heures. Mais je ne l'oublierai pas! – crusam

+0

Pas de soucis. Heureux que ça a marché pour toi :) –

0

Je vous suggère d'utiliser SwingWorker!

Il permet de faire un peu de travail en dehors de l'EDT, puis votre JTable est mis à jour en temps réel lorsque d'autres utilisateurs ajoutent une ligne!

Meilleures salutations

+0

Merci pour votre réponse. À quel moment suggérez-vous de les utiliser? Pour rafraîchir la table, quand un événement arrive? Mettre ces updateEvents dans les swingworkers a bien sûr du sens, mais je ne vois pas comment cela résoudrait le problème, puisque la ligne d'édition tout en rafraichissant la table changerait aussi, non? – crusam