2012-01-06 18 views
9

Ho una JTable che sta utilizzando un TableColumnModelListener() per rilevare quando la colonna è stata ridimensionata e ho del codice che voglio eseguire nel metodo columnMarginChanged().Java JTable detect Colonna ridimensionata dall'utente

Come determinare se la colonna è stata ridimensionata dall'utente o come risultato di un altro codice?

Sto pensando che devo iniziare con ChangeEvent.getSource() ma non so da dove andare.

Grazie.

+0

A meno che non lo si cambi, la sorgente sarà sempre la 'DefaultTableColumnModel' della tabella tramite' fireColumnMarginChanged() '. Che problema stai cercando di risolvere? – trashgod

+0

in nessun modo. Ripetendo la domanda @ trashgod: perché? – kleopatra

+0

Se il proprio codice che modifica la dimensione della colonna, è sempre possibile disattivare o rimuovere il listener prima della modifica, apportare la modifica e quindi reattivi o aggiungere nuovamente il listener. – Robin

risposta

7

Posso darvi un possibile approccio. Stavo cercando di risolvere lo stesso problema, perché volevo serializzare le informazioni sulla larghezza delle colonne su disco, in modo che la prossima volta che la tabella si aprisse nella mia applicazione, potrei ripristinare le larghezze della colonna in modo appropriato. Qui va:

Fase 1 - ignorare la JTable e aggiungere una proprietà booleana ad esso

class MyTable extends JTable { 

    private boolean isColumnWidthChanged; 
    public boolean getColumnWidthChanged() { 
     return isColumnWidthChanged; 
    } 

    public void setColumnWidthChanged(boolean widthChanged) { 
     isColumnWidthChanged = widthChanged; 
    } 

} 

Fase 2 - Aggiungi un TableColumnModelListener() alla tabella

private class TableColumnWidthListener implements TableColumnModelListener 
{ 
    @Override 
    public void columnMarginChanged(ChangeEvent e) 
    { 
     /* columnMarginChanged is called continuously as the column width is changed 
      by dragging. Therefore, execute code below ONLY if we are not already 
      aware of the column width having changed */ 
     if(!tableObj.hasColumnWidthChanged()) 
     { 
      /* the condition below will NOT be true if 
       the column width is being changed by code. */ 
      if(tableObj.getTableHeader.getResizingColumn() != null) 
      { 
       // User must have dragged column and changed width 
       tableObj.setColumnWidthChanged(true); 
      } 
     } 
    } 

    @Override 
    public void columnMoved(TableColumnModelEvent e) { } 

    @Override 
    public void columnAdded(TableColumnModelEvent e) { } 

    @Override 
    public void columnRemoved(TableColumnModelEvent e) { } 

    @Override 
    public void columnSelectionChanged(ListSelectionEvent e) { } 
} 

Passaggio 3: aggiungi un listener del mouse all'intestazione della tabella

private class TableHeaderMouseListener extends MouseAdapter 
{ 
    @Override 
    public void mouseReleased(MouseEvent e) 
    { 
     /* On mouse release, check if column width has changed */ 
     if(tableObj.getColumnWidthChanged()) 
     { 
      // Do whatever you need to do here 

      // Reset the flag on the table. 
      tableObj.setColumnWidthChanged(false); 
     } 
    } 
} 

NOTA: Nella mia applicazione, le classi TableHeaderMouseListener e TableColumnWidthListener erano classi interne private della mia classe di applicazione principale. La mia classe di applicazione principale si è mantenuta su un riferimento del tavolo osservato. Pertanto, queste classi interne hanno avuto accesso all'istanza della tabella. Ovviamente, a seconda della configurazione, è necessario fare la cosa appropriata per rendere l'istanza della tabella disponibile per queste altre classi. Spero che questo ti aiuti!

+0

(non prendi il tuo requisito - perché non salvi sempre le larghezze?) - ma per quanto riguarda il marker: invece di usare il cursore, che è estremamente fragile, come hai già notato :-) usa l'intestazione resizingColumn: è!= null solo mentre è in corso un ridimensionamento da parte dell'utente. Ecco come JXTableHeader supporta l'impacchettamento e corregge il fastidioso bug di attivazione di un ordinamento anche durante il ridimensionamento ... – kleopatra

+1

Come si è accennato, un approccio è semplicemente serializzare tutte le larghezze delle colonne quando l'applicazione viene chiusa (magari tramite il metodo windowClosing di un WindowListener). Questo potrebbe essere l'approccio corretto per la persona che ha postato questa domanda. Il motivo per cui devo serializzare le larghezze delle colonne in modo incrementale è perché il mio JTable viene distrutto e ricreato da zero ogni volta che una riga/colonna viene creata/distrutta. (Può sembrare strano, ma c'è un motivo per cui non posso rivelarlo in un forum pubblico.) Quindi l'unico modo per recuperare le larghezze originali è serializzarle in modo incrementale. – eternaln00b

+0

Forse potrei dare qualche dettaglio in più. :) Vedi, il mio JTable è un modulo di iscrizione per un backend più sofisticato. quando l'utente apporta modifiche a JTable nella mia applicazione, alcune cose vengono automaticamente costruite per l'utente in background. Quindi il mio JTable è essenzialmente un mago. Per garantire che la tabella rifletta esattamente ciò che è stato auto-costruito in background, devo analizzare gli oggetti costruiti automaticamente e ricreare la tabella. Se non lo faccio, c'è un pericolo (a causa di un errore di programmazione) che la tabella e gli oggetti costruiti automaticamente iniziano a divergere e non c'è più una verità. – eternaln00b

4

In genere si desidera ricevere una notifica di un trascinamento della colonna completato o di una ridimensionamento di una colonna completata. Per esempio.

interface SGridModel { 
    public void columnMoved(int oldLocation, int newLocation); 
    public void columnResized(int column, int newWidth); 
}   

Questo non è abbastanza ma lo farà ciò che si vuole:

class SColumnListener extends MouseAdapter implements TableColumnModelListener { 

    private final Logger log = Logger.getLogger(getClass()); 
    private final SGridModel model; 

    private int oldIndex = -1; 
    private int newIndex = -1; 
    private boolean dragging = false; 

    private boolean resizing = false; 
    private int resizingColumn = -1; 
    private int oldWidth = -1; 

    SColumnListener(SGridModel model){ 
     this.model = model; 
    } 

    @Override 
    public void mousePressed(MouseEvent e) { 
     // capture start of resize 
     if(e.getSource() instanceof JTableHeader) { 
      TableColumn tc = ((JTableHeader)e.getSource()).getResizingColumn(); 
      if(tc != null) { 
       resizing = true; 
       resizingColumn = tc.getModelIndex(); 
       oldWidth = tc.getPreferredWidth(); 
      } else { 
       resizingColumn = -1; 
       oldWidth = -1; 
      } 
     } 
    } 

    @Override 
    public void mouseReleased(MouseEvent e) { 
     // column moved 
     if(dragging && oldIndex != newIndex) { 
      model.columnMoved(oldIndex, newIndex); 
      log.info("column moved: " +oldIndex+" -> "+newIndex); 
     } 
     dragging = false; 
     oldIndex = -1; 
     newIndex = -1; 


     // column resized 
     if(resizing) { 
      if(e.getSource() instanceof JTableHeader) { 
       TableColumn tc = ((JTableHeader)e.getSource()).getColumnModel().getColumn(resizingColumn); 
       if(tc != null) { 
        int newWidth = tc.getPreferredWidth(); 
        if(newWidth != oldWidth) { 
         model.columnResized(resizingColumn, newWidth); 
         log.info("column resized: " +resizingColumn+" -> "+newWidth); 
        } 
       } 
      } 
     } 
     resizing = false; 
     resizingColumn = -1; 
     oldWidth = -1; 
    } 

    @Override 
    public void columnAdded(TableColumnModelEvent e) {  
    } 

    @Override 
    public void columnRemoved(TableColumnModelEvent e) {   
    } 

    @Override 
    public void columnMoved(TableColumnModelEvent e) { 
     // capture dragging 
     dragging = true; 
     if(oldIndex == -1){ 
      oldIndex = e.getFromIndex(); 
     } 

     newIndex = e.getToIndex(); 
    } 

    @Override 
    public void columnMarginChanged(ChangeEvent e) { 
    } 

    @Override 
    public void columnSelectionChanged(ListSelectionEvent e) { 
    } 
} 

aggiungerlo alla tabella come segue:

table.getColumnModel().addColumnModelListener(cl); 
table.getTableHeader().addMouseListener(cl); 
0

Una soluzione più semplice potrebbe essere solo di ascoltare sull'evento di rilascio del mouse (che si verifica solo una volta in questa interazione dell'utente) e controllare se le dimensioni delle colonne sono cambiate nel frattempo? Sto usando il codice qui sotto per ascoltare il riordino delle colonne e le modifiche alle dimensioni.

getTableHeader().addMouseListener(new MouseAdapter() { 
    public void mouseReleased(MouseEvent arg0) 
    { 
     String colNamesAndSizes = ""; 
     for(int i=0;i<getColumnModel().getColumnCount();i++) { 

     if(i>0) colNamesAndSizes += ","; 
     TableColumn column = getColumnModel().getColumn(i); 
     colNamesAndSizes += column.getHeaderValue(); 
     colNamesAndSizes += ":"; 
     colNamesAndSizes += column.getWidth(); 
     } 
     // check if changed, if yes, persist... 
    }});