2013-08-02 3 views
4

Suite de la situation: J'ai une table J (X) avec RowHeader (Comme guideline j'ai utilisé un de Rob Camicks grand Examples). Tout a fonctionné comme prévu.Comment gérer RowSorter-Synchronization dans JTables avec RowHeader?

enter image description here

Par condition que les données que je reçois de serveur contient déjà un tablerownumber, que je dois montrer dans le RowHeader et les données doivent être filtrables. J'ai donc étendu l'exemple, et j'ai ajouté un filtre. Lorsque j'ai filtré la vue, j'ai vu des trous dans les numéros de ma rangée (par exemple: 1, 3, 6, ..), ce qui est l'effet désiré.

Pour être en mesure de filtrer et trier la table par mon propre tablerow, j'ai ajouté un TableRowSorter. Et ici j'ai commencé à être confus. L'exemple utilise le même TableModel et SelectionModel pour maintable et rowHeaderTable:

setModel(main.getModel()); 
setSelectionModel(main.getSelectionModel()); 

Cela tombe bien, puisque je n'ai pas de les synchroniser. Mais concernant TableRowSorter je ne étais pas tout à coup sûr, si je peux aussi ou même avoir à utiliser le même TableRowSorter -Instance ou si je dois créer un TableRowSorter pour chaque table. D'abord, j'ai ajouté la même chose aux deux tables, puisque cela semblait pratiquement, mais ensuite j'ai eu IndexOutOfBound-Exceptions dans de nombreux cas. Après quelques recherches j'ai découvert que c'est parce que le TableRowSorter est mis à jour deux fois à chaque TableModelEvent, parce que chaque table (RowHeader et MainTable) notifie le TableRowSorter au sujet des changements de tablier par lui-même. Maintenant, je ne suis pas sûr que la bonne façon d'y aller est. Les solutions suivantes me sont venues à l'esprit: Dois-je ajouter un second TableRowSorter (un pour chaque table) et les synchroniser, ou devrais-je envelopper le TableModel dans le RowHeaderTable et ne pas laisser d'événements? Ou peut-être devrais-je créer mon propre type de RowHeaderTable qui n'informe pas Sorters de tout changement?

+0

Avez-vous essayé d'utiliser un trieur de ligne distincte pour chaque table? Je sais, vous devez le synchroniser, mais cela peut vous aider à surmonter l'obstacle initial. – MadProgrammer

+0

@ymene [voir ma vue de RowHeader (deux JTables, deux XxxModels, un écouteur pour deux notificateurs)] (http: // stackoverflow .com/a/8187799/714968), il n'y a que RowFilter, [vous pouvez essayer votre propre vue de RowSorter] (http://stackoverflow.com/a/16664124/714968), [si sans succès] (http://stackoverflow.com/a/11280226/714968) puis poster, je pense que cela doit être basé sur votre [SSCCE] (http://sscce.org/), ou attendre (@camickr), btw de toute façon (celui-ci) pourrait être très agréable question +1 – mKorbel

+0

pouvez-vous montrer un SSCCE où il souffle?Je me souviens d'avoir eu une discussion similaire (mais pas son résultat et ne peut pas le trouver) - et un exemple très simple - avec RowSorter partagé - semble se conduire bien. – kleopatra

Répondre

3

Voici un rapide (attention: pas formellement testé! L'exemple d'utilisation fonctionne bien, cependant) l'implémentation d'un RowSorter d'emballage.

  • ne fait rien sur réception de la notification du modèle change
  • délégués tout état requêtes
  • écoutes à enveloppées rowSorter et propage ses événements

Il est de la responsabilité du client pour le maintenir en phase avec le rowSorter utilisé dans la table principale

Exemple d'utilisation (en termes d'infrastructure de test SwingX et avec SwingX sortController/table):

public void interactiveRowSorterWrapperSharedXTable() { 
    final DefaultTableModel tableModel = new DefaultTableModel(list.getElementCount(), 2) { 

     @Override 
     public Class<?> getColumnClass(int columnIndex) { 
      return Integer.class; 
     } 

    }; 
    for (int i = 0; i < tableModel.getRowCount(); i++) { 
     tableModel.setValueAt(i, i, 0); 
     tableModel.setValueAt(tableModel.getRowCount() - i, i, 1); 
    } 
    final JXTable master = new JXTable(tableModel); 
    final TableSortController<TableModel> rowSorter = (TableSortController<TableModel>) master.getRowSorter(); 
    master.removeColumn(master.getColumn(0)); 
    final JXTable rowHeader = new JXTable(master.getModel()); 
    rowHeader.setAutoCreateRowSorter(false); 
    rowHeader.removeColumn(rowHeader.getColumn(1)); 
    rowHeader.setRowSorter(new RowSorterWrapper<TableModel>(rowSorter)); 
    rowHeader.setSelectionModel(master.getSelectionModel()); 
    // need to disable selection update on one of the table's 
    // otherwise the selection is not kept in model coordinates 
    rowHeader.setUpdateSelectionOnSort(false); 
    JScrollPane scrollPane = new JScrollPane(master); 
    scrollPane.setRowHeaderView(rowHeader); 
    JXFrame frame = showInFrame(scrollPane, "xtables (wrapped sortController): shared model/selection"); 
    Action fireAllChanged = new AbstractAction("fireDataChanged") { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      tableModel.fireTableDataChanged(); 
     } 

    }; 
    addAction(frame, fireAllChanged); 
    Action removeFirst = new AbstractAction("remove firstM") { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      tableModel.removeRow(0); 

     } 
    }; 
    addAction(frame, removeFirst); 
    Action removeLast = new AbstractAction("remove lastM") { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      tableModel.removeRow(tableModel.getRowCount() - 1); 

     } 
    }; 
    addAction(frame, removeLast); 
    Action filter = new AbstractAction("toggle filter") { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      RowFilter filter = rowSorter.getRowFilter(); 
      if (filter == null) { 
       rowSorter.setRowFilter(RowFilter.regexFilter("^1", 1)); 
      } else { 
       rowSorter.setRowFilter(null); 
      } 

     } 
    }; 
    addAction(frame, filter); 
    addStatusMessage(frame, "row header example with RowSorterWrapper"); 
    show(frame); 
} 

Le RowSorterWrapper:

/** 
* Wrapping RowSorter for usage (f.i.) in a rowHeader. 
* 
* Delegates all state queries, 
* does nothing on receiving notification of model changes, 
* propagates rowSorterEvents from delegates. 
* 
* Beware: untested! 
* 
* @author Jeanette Winzenburg, Berlin 
*/ 
public class RowSorterWrapper<M> extends RowSorter<M> { 

    private RowSorter<M> delegate; 
    private RowSorterListener rowSorterListener; 

    public RowSorterWrapper(RowSorter<M> delegate) { 
     this.delegate = delegate; 
     delegate.addRowSorterListener(getRowSorterListener()); 
    } 

    /** 
    * Creates and returns a RowSorterListener which re-fires received 
    * events. 
    * 
    * @return 
    */ 
    protected RowSorterListener getRowSorterListener() { 
     if (rowSorterListener == null) { 
      RowSorterListener listener = new RowSorterListener() { 

       @Override 
       public void sorterChanged(RowSorterEvent e) { 
        if (RowSorterEvent.Type.SORT_ORDER_CHANGED == e.getType()) { 
         fireSortOrderChanged(); 
        } else if (RowSorterEvent.Type.SORTED == e.getType()) { 
         fireRowSorterChanged(null);    } 
       } 
      }; 
      rowSorterListener = listener; 
     } 
     return rowSorterListener; 
    } 


    @Override 
    public M getModel() { 
     return delegate.getModel(); 
    } 

    @Override 
    public void toggleSortOrder(int column) { 
     delegate.toggleSortOrder(column); 
    } 

    @Override 
    public int convertRowIndexToModel(int index) { 
     return delegate.convertRowIndexToModel(index); 
    } 

    @Override 
    public int convertRowIndexToView(int index) { 
     return delegate.convertRowIndexToModel(index); 
    } 

    @Override 
    public void setSortKeys(List keys) { 
     // TODO Auto-generated method stub 
     delegate.setSortKeys(keys); 
    } 

    @Override 
    public List getSortKeys() { 
     return delegate.getSortKeys(); 
    } 

    @Override 
    public int getViewRowCount() { 
     return delegate.getViewRowCount(); 
    } 

    @Override 
    public int getModelRowCount() { 
     return delegate.getModelRowCount(); 
    } 

    @Override 
    public void modelStructureChanged() { 
     // do nothing, all work done by delegate 
    } 

    @Override 
    public void allRowsChanged() { 
     // do nothing, all work done by delegate 
    } 

    @Override 
    public void rowsInserted(int firstRow, int endRow) { 
     // do nothing, all work done by delegate 
    } 

    @Override 
    public void rowsDeleted(int firstRow, int endRow) { 
     // do nothing, all work done by delegate 
    } 

    @Override 
    public void rowsUpdated(int firstRow, int endRow) { 
     // do nothing, all work done by delegate 
    } 

    @Override 
    public void rowsUpdated(int firstRow, int endRow, int column) { 
     // do nothing, all work done by delegate 
    } 

}