2011-10-23 6 views
1

Dans mon programme JavaFX, j'utilise un TableCell dans lequel vous pouvez modifier une valeur. Comme le montre les exemples sur la JavaFX page "Example", j'utilise cette fonction pour enregistrer les modifications (fonction est activée TextField modifier cellule)JavaFX 2: Enregistrer l'édition dans TableCell

textField.setOnKeyReleased(new EventHandler<KeyEvent>() { 
    @Override public void handle(KeyEvent t) { 
    if (combo.match(t)) { 
     commitEdit(textField.getText()); 
    } else if (t.getCode() == KeyCode.ESCAPE) { 
     cancelEdit(); 
    } 
} 

Lorsque vous utilisez ENTER pour quitter la cellule, la valeur est modifiée/enregistré, mais comment puis-je modifier/enregistrer la valeur, en quittant la cellule en cliquant dans une autre cellule? En fait, la valeur est réinitialisée.

Merci Basti

Répondre

2

Écoute d'un changement d'orientation sur le TextField est une façon .. J'ai ajouté un écouteur au focusedProperty du textField. L'exemple d'Oracle ne l'inclut pas. [edit - voici un lien à une autre question qui a une approche différente UITableView - Better Editing through Binding?]

private void createTextField() { 
     textField = new TextField(getItem()); 
     textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2); 

     // Detect a change in focus on the text field.. If we lose the focus we take appropriate action 
     textField.focusedProperty().addListener(new ChangeListener<Boolean>() { 
      public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { 
       if(!newValue.booleanValue()) 
        commitEdit(textField.getText()); 
      } 
     }); 
     textField.setOnKeyReleased(new EventHandler<KeyEvent>() { 
      @Override public void handle(KeyEvent t) { 
       if (t.getCode() == KeyCode.ENTER) { 
        commitEdit(textField.getText()); 
       } else if (t.getCode() == KeyCode.ESCAPE) { 
        cancelEdit(); 
       } 
      } 
     }); 
    } 
+2

Je disli ke la sémantique d'édition pour un TableView .. Je pense qu'un meilleur moyen est de lier le contrôle au modèle de données sous-jacent et être fait avec tout le piégeage d'événement, la manipulation, et le remplacement des méthodes .. Exemples à venir plus tard. – jkaufmann

+0

Merci pour cette solution. Ce serait bien, si vous pouvez partager la meilleure façon, c'est peut-être exactement cela, ce que je cherche. – McPepper

+0

Dans l'intention de clarté - je vais poster une question "Comment utiliser la liaison pour une meilleure édition TableView" puis répondez-y. Dans le but de cette question cependant - je pense que la réponse est de piéger l'événement de changement focusedProperty(). Une fois terminé, je le lierai à cette question. – jkaufmann

0
import javafx.beans.property.ObjectProperty; 
    import javafx.beans.value.ChangeListener; 
    import javafx.beans.value.ObservableValue; 
    import javafx.collections.ObservableList; 
    import javafx.scene.Node; 
    import javafx.scene.control.Cell; 
    import javafx.scene.control.ComboBox; 
    import javafx.scene.control.TextField; 
    import javafx.scene.input.KeyCode; 
import javafx.scene.input.KeyEvent; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.layout.HBox; 
import javafx.util.StringConverter; 

class CellGenerator { 

/*************************************************************************** 
* * Private fields * * 
**************************************************************************/ 
private final static StringConverter defaultStringConverter = new StringConverter<Object>() { 
    @Override 
    public String toString(Object t) { 
     return t == null ? null : t.toString(); 
    } 

    @Override 
    public Object fromString(String string) { 
     return (Object) string; 
    } 
}; 

static <T> StringConverter<T> defaultStringConverter() { 
    return (StringConverter<T>) defaultStringConverter; 
} 

private static <T> String getItemText(Cell<T> cell, StringConverter<T> converter) { 
    return converter == null ? cell.getItem() == null ? "" : cell.getItem().toString() 
      : converter.toString(cell.getItem()); 
} 

/*************************************************************************** 
* * TextField convenience * * 
**************************************************************************/ 
static <T> void updateItem(final Cell<T> cell, final StringConverter<T> converter, final TextField textField) { 
    updateItem(cell, converter, null, null, textField); 
} 

static <T> void updateItem(final Cell<T> cell, final StringConverter<T> converter, final HBox hbox, 
     final Node graphic, final TextField textField) { 
    if (cell.isEmpty()) { 
     cell.setText(null); 
     cell.setGraphic(null); 
    } else { 
     if (cell.isEditing()) { 
      if (textField != null) { 
       textField.setText(getItemText(cell, converter)); 
      } 
      cell.setText(null); 
      if (graphic != null) { 
       hbox.getChildren().setAll(graphic, textField); 
       cell.setGraphic(hbox); 
      } else { 
       cell.setGraphic(textField); 
      } 
     } else { 
      cell.setText(getItemText(cell, converter)); 
      cell.setGraphic(graphic); 
     } 
    } 
} 

static <T> void startEdit(final Cell<T> cell, final StringConverter<T> converter, final HBox hbox, 
     final Node graphic, final TextField textField) { 
    if (textField != null) { 
     textField.setText(getItemText(cell, converter)); 
    } 
    cell.setText(null); 
    if (graphic != null) { 
     hbox.getChildren().setAll(graphic, textField); 
     cell.setGraphic(hbox); 
    } else { 
     cell.setGraphic(textField); 
    } 
    textField.selectAll(); 
    // requesting focus so that key input can immediately go into the 
    // TextField (see RT-28132) 
    textField.requestFocus(); 
} 

static <T> void cancelEdit(Cell<T> cell, final StringConverter<T> converter, Node graphic) { 
    cell.setText(getItemText(cell, converter)); 
    cell.setGraphic(graphic); 

} 

static <T> TextField createTextField(final Cell<T> cell, final StringConverter<T> converter) { 

    final TextField textField = new TextField(getItemText(cell, converter)); 
    EdittingCell cellEdit=(EdittingCell)cell; 
    textField.setOnMouseExited(event -> { 

     if (converter == null) { 
      throw new IllegalStateException("Attempting to convert text input into Object, but provided " 
        + "StringConverter is null. Be sure to set a StringConverter " 
        + "in your cell factory."); 
     } 

     cell.commitEdit(converter.fromString(textField.getText())); 

    }); 

    textField.addEventFilter(KeyEvent.KEY_PRESSED, event -> { 

     if (event.getCode() == KeyCode.ESCAPE) { 
      cell.cancelEdit(); 
      event.consume(); 
     } else if (event.getCode() == KeyCode.RIGHT) { 
      cellEdit.getTableView().getSelectionModel().selectRightCell(); 
      event.consume(); 
     } else if (event.getCode() == KeyCode.LEFT) { 
      cellEdit.getTableView().getSelectionModel().selectLeftCell(); 
      event.consume(); 
     } else if (event.getCode() == KeyCode.UP) { 
      cellEdit.getTableView().getSelectionModel().selectAboveCell(); 
      event.consume(); 
     } else if (event.getCode() == KeyCode.DOWN) { 
      cellEdit.getTableView().getSelectionModel().selectBelowCell(); 
      event.consume(); 
     } else if (event.getCode() == KeyCode.ENTER) { 
      if (converter == null) { 
       throw new IllegalStateException("Attempting to convert text input into Object, but provided " 
         + "StringConverter is null. Be sure to set a StringConverter " 
         + "in your cell factory."); 
      } 

      cell.commitEdit(converter.fromString(textField.getText())); 

      event.consume(); 
     } 
     else if (event.getCode() == KeyCode.TAB) { 

      cell.commitEdit(converter.fromString(textField.getText())); 

      cellEdit.setNextColumn(event); 

      event.consume(); 
     } 
    }); 

    return textField; 
}} 

// la table cellule

import java.util.ArrayList; 
    import java.util.List; 

    import javafx.beans.property.ObjectProperty; 
    import javafx.beans.property.SimpleObjectProperty; 
    import javafx.collections.FXCollections; 
    import javafx.collections.ObservableList; 
    import javafx.event.EventHandler; 
    import javafx.scene.control.*; 
    import javafx.scene.input.KeyCode; 
    import javafx.scene.input.KeyEvent; 
    import javafx.util.Callback; 
    import javafx.util.StringConverter; 
    import javafx.util.converter.DefaultStringConverter; 

public class EdittingCell<S, T> extends TableCell<S, T> { 

public static <S> Callback<TableColumn<S, String>, TableCell<S, String>> 
forTableColumn() { 
    return forTableColumn(new DefaultStringConverter()); 
} 

public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> 
forTableColumn(
     final StringConverter<T> converter) { 
    return new Callback<TableColumn<S, T>, TableCell<S, T>>() { 
     @Override 
     public TableCell<S, T> call(TableColumn<S, T> list) { 
      return new EdittingCell<S, T>(converter); 
     } 
    }; 
} 

public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> 
forTableColumn(final StringConverter<T> converter, 
     final boolean isFieldEditable) { 
    return new Callback<TableColumn<S, T>, TableCell<S, T>>() { 
     @Override 
     public TableCell<S, T> call(TableColumn<S, T> list) { 
      return new EdittingCell<S, T>(converter, isFieldEditable); 
     } 
    }; 
} 

/*************************************************************************** 
* * Fields * * 
**************************************************************************/ 
public TextField textField; 
private static int currentRow = -1; 
private static int control = 0; 

public EdittingCell() { 
    this(null); 
    textField = CellGenerator.createTextField(this, getConverter()); 
} 

public EdittingCell(StringConverter<T> converter) { 

    this.getStyleClass().add("text-field-table-cell"); 

    setConverter(converter); 
    textField = CellGenerator.createTextField(this, getConverter()); 
    // textField.setEditable(false); 

} 

public EdittingCell(StringConverter<T> converter, boolean isFieldEditable) { 

    this.getStyleClass().add("text-field-table-cell"); 

    setConverter(converter); 
    textField = CellGenerator.createTextField(this, getConverter()); 
    textField.setEditable(isFieldEditable); 

} 

/*************************************************************************** 
* * Properties * * 
**************************************************************************/ 
// --- converter 
private ObjectProperty<StringConverter<T>> converter = new SimpleObjectProperty<StringConverter<T>>(this, 
     "converter"); 

public final ObjectProperty<StringConverter<T>> converterProperty() { 
    return converter; 
} 

public TextField getTextFiedCell() { 
    return textField; 
} 

public final void setConverter(StringConverter<T> value) { 
    converterProperty().set(value); 
} 

public final StringConverter<T> getConverter() { 
    return converterProperty().get(); 
} 

@Override 
public void startEdit() { 
    if (!isEditable() || !getTableView().isEditable() || !getTableColumn().isEditable()) { 
     return; 
    } 
    super.startEdit(); 
    if (isEditing()) { 

     CellGenerator.startEdit(this, getConverter(), null, null, textField); 
    } 
} 

@Override 
public void cancelEdit() { 
    super.cancelEdit(); 
    CellGenerator.cancelEdit(this, getConverter(), null); 
} 

/** {@inheritDoc} */ 
@Override 
public void updateItem(T item, boolean empty) { 
    super.updateItem(item, empty); 
    CellGenerator.updateItem(this, getConverter(), null, null, textField); 
    // System.out.println("Silas"); 
} 

public TableView<S> getContextTableView() { 

    return getTableView(); 
} 

public void setNextColumn(KeyEvent event) { 
    TableColumn nextColumn = getNextColumn(!event.isShiftDown()); 

    if (nextColumn != null) { 

     // Get Selected index to reset current editable row 
     int selectedRow = getTableRow().getIndex(); 
     // Set row that serves as a control for tapping through 
     if (currentRow == -1) { 
      currentRow = getTableRow().getIndex(); 
     } 
     // Reset editing upon selection change row 
     if (currentRow != selectedRow) { 
      currentRow = selectedRow; 
     } 

     int colSize = getTableView().getColumns().size(); 
     int colindex = getTableView().getColumns().indexOf(nextColumn); 

     if (colindex == colSize - 1) { 
      control++; 
     } 
     if (control > 0 && colindex == 0) { 
      currentRow++; 
     } 

     if (getTableView().getItems().size() > currentRow) { 
      getTableView().edit(currentRow, nextColumn); 
      // getTableView().getSelectionModel().select(currentRow, 
      // nextColumn); 
     } else { 
      currentRow = 0; 
      // getTableView().getSelectionModel().select(currentRow, 
      // nextColumn); 
      getTableView().edit(currentRow, nextColumn); 
     } 
    } 
} 

private TableColumn<S, ?> getNextColumn(boolean forward) { 

    List<TableColumn<S, ?>> columns = new ArrayList<>(); 

    for (TableColumn<S, ?> column : getTableView().getColumns()) { 

     columns.addAll(getLeaves(column)); 

    } 

    // There is no other column that supports editing. 

    if (columns.size() < 2) { 
     return null; 
    } 
    int currentIndex = columns.indexOf(getTableColumn()); 
    int nextIndex = currentIndex; 
    if (forward) { 
     nextIndex++; 
     if (nextIndex > columns.size() - 1) { 
      nextIndex = 0; 

     } 
    } else { 
     nextIndex--; 
     if (nextIndex < 0) { 

      nextIndex = columns.size() - 1; 
     } 

    } 
    return columns.get(nextIndex); 
} 

private ObservableList<TableColumn<S, ?>> getLeaves(TableColumn<S, ?> column2) { 
    ObservableList<TableColumn<S, ?>> columns = FXCollections.observableArrayList(); 
    if (column2.getColumns().isEmpty()) { 
     // We only want the leaves that are editable. 
     if (column2.isEditable()) { 
      columns.addAll(column2); 
     } 
     return columns; 
    } else { 
     for (TableColumn<S, ?> column : column2.getColumns()) { 
      columns.addAll(getLeaves(column)); 
     } 
     return columns; 
    } 

} 

}

// Comment utiliser ce

TableColumn<NewInvoice, BigDecimal> quantityCol = new 
    TableColumn<NewInvoice, BigDecimal>("Quantity"); 
    quantityCol.setCellValueFactory(cellData -> 
    cellData.getValue().quantityProperty()); 
    quantityCol.setCellFactory(EdittingCell.forTableColumn(new 
    BigDecimalStringConverter())); 
    quantityCol.setStyle("-fx-alignment:CENTER-RIGHT;"); 
    quantityCol.setOnEditCommit(new EventHandler<CellEditEvent<NewInvoice, 
    BigDecimal>>() { 
     @Override 
     public void handle(CellEditEvent<NewInvoice, BigDecimal> t) { 
    t.getTableView().getItems().get(t.getTablePosition().getRow() 
    ).setQuantity(t.getNewValue()); 
     } 
    });