2009-10-31 18 views
22

Wysoki poziom: Posiadam JTable, którego użytkownik może użyć do edycji danych.Czy Jtable może zapisywać dane, gdy komórka traci ostrość?

Gdy użytkownik naciśnie klawisz Enter lub Tab, aby zakończyć edycję, dane są zapisywane (jestem asusming że „zapisane” naprawdę znaczy „setValueAt TableModel'S() wywoływana jest metoda”).

Jeśli liście użytkowników komórkę w jakikolwiek inny sposób po dokonaniu edycji, nowe dane nie są zapisywane, a wartość pozostaje taka, jak była. Na przykład, jeśli użytkownik zmieni wartość, a następnie kliknie jakiś inny widżet na ekranie, zmiana nie "zapcha się".

Uważam, że jest to domyślne zachowanie dla JTable pełnego ciągów znaków, tak?

Z różnych powodów pożądanym zachowaniem jest zapisanie przez komórkę wszystkich wprowadzonych zmian za każdym razem, gdy użytkownik opuści komórkę. Jaki jest najlepszy/właściwy sposób, aby to zrobić Swing?

Odpowiedz

5

Należy dodać focus listener. Biorąc pod uwagę, że JTable jest w zasadzie kontenerem składników komórki, faktycznie potrzebujesz detektora ostrości dla każdej komórki w tabeli, która musi zachowywać się w sposób wskazany przez ciebie.

Aby to zrobić, musisz utworzyć niestandardowy edytor komórek, który otoczy komponent komórki z zarejestrowanym obiektem nasłuchującym. A kiedy otrzymasz wywołanie zwrotne dla zdarzenia utraty fokusu, dokonasz zapisu danych, zgodnie z wymaganiami.

This pretty much details most of what you need to do. Szczegóły dotyczące wdrażania słuchacza nie są dostępne, ale jest to dość proste.

Powiedzmy, że używasz komponentu JTextComponent jako komponentu komórki. Następnie:

public void focusLost(FocusEvent e) { 
    JTextComponent cell = (JTextComponent) e.getSource(); 
    String data = cell.getText(); 

    // TODO: save the data for this cell 
} 

[p.s. edit]:

Wątek, który dzwoni do ciebie z tym wydarzeniem, jest wątkiem wysyłki. NIE używaj go do akcji o dużym opóźnieniu. Ale jeśli tylko rzucasz bity w stercie, powinno być dobrze.

+0

Drugi link nie działa. :( – Niroshan

+0

Lekcja, której należy się wtedy nauczyć dla ludzkości w kontekście zbiorowej wiedzy przechowywanej na efemerycznych mediach – alphazero

+0

Maszyna Wayback miała to - odpowiednio zmieniłem link. –

14

Jednym z prostych rozwiązań zaproponowano

table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); 

jest dobre tylko dla kolumn Smyczkowych. Problem polega na tym, że mam na przykład typ Float edytowanej kolumny, wprowadź pusty ciąg w odpowiedniej komórce, a następnie kliknij dowolną inną kontrolkę okna - Java wyrzuca NullPointerException w metodzie CellEditorRemover.propertyChange() z JTable.java. Używa połączenia getCellEditor(), aby zatrzymać lub anulować edycję, ale w tym przypadku zwraca null. Jeśli wprowadzona wartość nie jest pusta lub jeśli usuwam flagę terminateEditOnFocusLost wszystko jest w porządku. Prawdopodobnie opisana sytuacja to błąd.

Mam nadzieję, że przedstawię rozwiązanie oparte na jednym z poprzednich postów. Nie jest to tak banalne, jak przypuszczałem, ale wydaje mi się, że działa. Musiałem odziedziczyć mój edytor komórek z domyślnego edytora komórek i własne pole tekstowe z JTextField, które ma FocusListener. Ten słuchacz fokusowy działa dobrze podczas edycji komórki traci fokus i fokus zdobyte przez inną kontrolę okna. Ale w przypadku zmiany wyboru komórki fokus jest "głuchy". Dlatego też przed rozpoczęciem edycji muszę pamiętać zapamiętaną wartość, aby przywrócić ją, jeśli wprowadzona wartość będzie nieprawidłowa.

Zobacz poniższy kod. Przetestowane z Double, Float i Integer, ale mam nadzieję, że będzie to również działać z Byte i String.

Tekst pola z fokusem słuchacza:

public class TextFieldCell extends JTextField { 
    public TextFieldCell(JTable cellTable) { 
     super();       // calling parent constructor 
     final JTable table = cellTable;  // this one is required to get cell editor and stop editing 

     this.addFocusListener(new FocusListener() { 
      public void focusGained(FocusEvent e) { 
      } 

      // this function successfully provides cell editing stop 
      // on cell losts focus (but another cell doesn't gain focus) 
      public void focusLost(FocusEvent e) { 
       CellEditor cellEditor = table.getCellEditor(); 
       if (cellEditor != null) 
        if (cellEditor.getCellEditorValue() != null) 
         cellEditor.stopCellEditing(); 
        else 
         cellEditor.cancelCellEditing(); 
      } 
     }); 
    } 
} 

domyślna klasa redaktor komórka:

class TextFieldCellEditor extends DefaultCellEditor { 
TextFieldCell textField; // an instance of edit field 
Class<?> columnClass;  // specifies cell type class 
Object valueObject;   // for storing correct value before editing 
public TextFieldCellEditor(TextFieldCell tf, Class<?> cc) { 
    super(tf); 
    textField = tf; 
    columnClass = cc; 
    valueObject = null; 
} 

@Override 
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
    TextFieldCell tf = (TextFieldCell)super.getTableCellEditorComponent(table, value, isSelected, row, column); 
    if (value != null) { 
     tf.setText(value.toString()); 
    } 
    // we have to save current value to restore it on another cell selection 
    // if edited value couldn't be parsed to this cell's type 
    valueObject = value; 
    return tf; 
} 

@Override 
public Object getCellEditorValue() { 
    try { 
     // converting edited value to specified cell's type 
     if (columnClass.equals(Double.class)) 
      return Double.parseDouble(textField.getText()); 
     else if (columnClass.equals(Float.class)) 
      return Float.parseFloat(textField.getText()); 
     else if (columnClass.equals(Integer.class)) 
      return Integer.parseInt(textField.getText()); 
     else if (columnClass.equals(Byte.class)) 
      return Byte.parseByte(textField.getText()); 
     else if (columnClass.equals(String.class)) 
      return textField.getText(); 
    } 
    catch (NumberFormatException ex) { 

    } 

    // this handles restoring cell's value on jumping to another cell 
    if (valueObject != null) { 
     if (valueObject instanceof Double) 
      return ((Double)valueObject).doubleValue(); 
     else if (valueObject instanceof Float) 
      return ((Float)valueObject).floatValue(); 
     else if (valueObject instanceof Integer) 
      return ((Integer)valueObject).intValue(); 
     else if (valueObject instanceof Byte) 
      return ((Byte)valueObject).byteValue(); 
     else if (valueObject instanceof String) 
      return (String)valueObject; 
    } 

    return null; 
} 

To kod inicjalizacji tablicy trzeba dodać następujący:

myTable.setDefaultEditor(Float.class, new TextFieldCellEditor(new TextFieldCell(myTable), Float.class)); 
myTable.setDefaultEditor(Double.class, new TextFieldCellEditor(new TextFieldCell(myTable), Double.class)); 
myTable.setDefaultEditor(Integer.class, new TextFieldCellEditor(new TextFieldCell(myTable), Integer.class)); 

Nadzieja , to pomoże komuś, kto ma ten sam problem.

Powiązane problemy