2015-01-30 11 views
8

Quando utilizzo un JXTable per il rendering e la modifica dei miei dati, alcuni input nei CellEditor vengono persi. Se clicco su Ridimensionamento-Divisore di JXTable-ColumnHeader o cambio la larghezza di JFrame, CellEditor si interrompe senza il commit del valore. I valori vengono salvati se utilizzo JTable.Perché JXTable perde input in cui JTable non lo è?

Desidero utilizzare JXTable a causa delle sue altre funzionalità, quindi esiste un modo per correggere JXTable?

Screenrecording

Esempio:

package table.columnresize; 

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableModel; 

import org.jdesktop.swingx.JXTable; 

/** 
* Demo of differing behaviour of JXTable and JTable. JXTable loses input in a TableCell where JTable persists 
* it. 
* <p> 
* <table border=1> 
* <tr> 
* <th></th> 
* <th>JXTable</th> 
* <th>JTable</th> 
* </tr> 
* <tr> 
* <td>Click on TableColumnHeader</td> 
* <td>saved</td> 
* <td>saved</td> 
* </tr> 
* <tr> 
* <td>Resizing with Divider of TableColumnHeader</td> 
* <td>lost</td> 
* <td>saved</td> 
* </tr> 
* <tr> 
* <td>Changing the width of JFrame</td> 
* <td>lost</td> 
* <td>saved</td> 
* </tr> 
* 
* </table> 
* </p> 
* 
* @author bobndrew 2015-01-29 
*/ 
public class JXTableAndJTableEditLossDemo 
{ 
    private static class DataModel extends DefaultTableModel 
    { 
    public DataModel(Object[][] data, Object[] columnNames) 
    { 
     super(data, columnNames); 
    } 
    } 

    private static void createAndShowUI() 
    { 
    Object[][] DATA = { { "One", 1 }, { "Two", 2 }, { "Three", 3 }, { "Four", 4 }, { "Five", 5 } }; 
    String[] COLUMNS = { "A", "B" }; 
    DataModel dataModel = new DataModel(DATA, COLUMNS); 

    JFrame frame1 = new JFrame("JXTable"); 
    JXTable jXTable = new JXTable(dataModel); 
    //does not change anything: jXTable.setTerminateEditOnFocusLost(true); 
    System.out.println(jXTable.isTerminateEditOnFocusLost()); 
    frame1.add(new JScrollPane(jXTable)); 
    frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame1.pack(); 
    frame1.setVisible(true); 

    JFrame frame2 = new JFrame("JTable"); 
    JTable jTable = new JTable(dataModel); 
    //does not change anything: jTable.putClientProperty("terminateEditOnFocusLost", Boolean.FALSE); 
    System.out.println(jTable.getClientProperty("terminateEditOnFocusLost")); 
    frame2.add(new JScrollPane(jTable)); 
    frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame2.pack(); 
    frame2.setLocation((int) frame1.getLocation().getX() + frame1.getWidth() + 100, (int) frame1 
     .getLocation().getY()); 
    frame2.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
    java.awt.EventQueue.invokeLater(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
     createAndShowUI(); 
     } 
    }); 
    } 

} 
+0

Hai provato ad aggiungere un listener di messa a fuoco personalizzato a JXTable? Vedi la seconda e la terza risposta su questo post. http://stackoverflow.com/questions/1652942/can-a-jtable-save-data-whenever-a-cell-lose-focus –

+0

Buona idea, ma FocusListener è troppo inaffidabile in diversi sistemi operativi. – bobndrew

risposta

3

Durante il debug di JXTable e JTable ho trovato il motivo della perdita di CellEdits. La differenza è nel metodo columnMarginChanged():

JXTable:

if (isEditing()) { 
    removeEditor(); 
} 

JTable:

if (isEditing() && !getCellEditor().stopCellEditing()) { 
    getCellEditor().cancelCellEditing(); 
} 

In un primo momento ho pensato che il metodo removeEditor() è un miglioramento della JTable ... Ma poi ho trovato questo OpenJDK changeset from September 2010 che corregge il bug "4330950: dati inseriti di nuovo nella cella quando si ridimensiona la larghezza della colonna". Sembra che le modifiche dal JDK non siano state applicate al codice sorgente SwingX.

Accetterò la mia risposta perché il motivo per un comportamento diverso è ora chiaro. Per risolvere questo problema per me e gli altri utenti SwingX, andrò alla mailing list SwingX e al bug tracker.

1

Quando si dà un'occhiata al metodo frameInit() di JTable, si può vedere che si lega a tutti gli AWTEvent.WINDOW * gli eventi. In JXTable il metodo initActionsAndBindings() esegue il binding a azioni specifiche (come il valore modificato) e solo per la tabella.

Sarà necessario aggiungere la tua ascoltatore

jXTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() { 
     @Override 
     public void columnMarginChanged(ChangeEvent e) { 

     } 
    }); 

e quindi avrebbe dovuto esporre alcune funzionalità del tavolo per permettere l'evento per attivare l'aggiornamento della tabella. O forse puoi attivare un TableModelEvent da lì.

+0

'frameInit()' è un metodo in 'JFrame.java' e non' JTable.java'. Ma la tua idea con un 'TableColumnModelListener' e' columnMarginChanged() 'è simile ai miei risultati; guarda la mia risposta – bobndrew

Problemi correlati