Tuesday, April 17, 2012

JavaFX 2: Editable TableView

Last article demonstrate how to implement a simple TableView. It's modified to be editable: double click the Value field of the table to edit the value.

JavaFX 2: Editable TableView

package javafx_table;

import javafx.application.Application;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

/**
*
* @web http://java-buddy.blogspot.com/
*/
public class JavaFX_TableView extends Application {

  public class Record{
      private SimpleStringProperty fieldMonth;
      private SimpleDoubleProperty fieldValue;
    
      Record(String fMonth, double fValue){
          this.fieldMonth = new SimpleStringProperty(fMonth);
          this.fieldValue = new SimpleDoubleProperty(fValue);
      }
    
      public String getFieldMonth() {
          return fieldMonth.get();
      }
    
      public double getFieldValue() {
          return fieldValue.get();
      }
    
      public void setFieldMonth(String fMonth) {
          fieldMonth.set(fMonth);
      }
    
      public void setFieldValue(Double fValue) {
          fieldValue.set(fValue);
      }
    
  }

  private TableView<Record> tableView = new TableView<>();

  private ObservableList<Record> dataList =
          FXCollections.observableArrayList(          
              new Record("January", 100),
              new Record("February", 200),
              new Record("March", 50),
              new Record("April", 75),
              new Record("May", 110),
              new Record("June", 300),
              new Record("July", 111),
              new Record("August", 30),
              new Record("September", 75),
              new Record("October", 55),
              new Record("November", 225),
              new Record("December", 99));

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
      launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
      primaryStage.setTitle("java-buddy.blogspot.com");
    
      Group root = new Group();
    
      tableView.setEditable(true);
      Callback<TableColumn, TableCell> cellFactory =
              new Callback<TableColumn, TableCell>() {
                  public TableCell call(TableColumn p) {
                      return new EditingCell();
                  }
              };

      TableColumn columnMonth = new TableColumn("Month");
      columnMonth.setCellValueFactory(
              new PropertyValueFactory<Record,String>("fieldMonth"));

      TableColumn columnValue = new TableColumn("Value");
      columnValue.setCellValueFactory(
              new PropertyValueFactory<Record,Double>("fieldValue"));
    
      //--- Add for Editable Cell of Value field, in Double
      columnValue.setCellFactory(cellFactory);
      columnValue.setOnEditCommit(
              new EventHandler<TableColumn.CellEditEvent<Record, Double>>() {
                  @Override public void handle(TableColumn.CellEditEvent<Record, Double> t) {
                      ((Record)t.getTableView().getItems().get(
                              t.getTablePosition().getRow())).setFieldValue(t.getNewValue());
                  }
              });
      //---
    
      tableView.setItems(dataList);
      tableView.getColumns().addAll(columnMonth, columnValue);
    
      VBox vBox = new VBox();
      vBox.setSpacing(10);
      vBox.getChildren().add(tableView);

      root.getChildren().add(vBox);
    
      primaryStage.setScene(new Scene(root, 300, 250));
      primaryStage.show();
  }

  class EditingCell extends TableCell<Record, Double> {

      private TextField textField;
    
      public EditingCell() {}
    
      @Override
      public void startEdit() {
          super.startEdit();
        
          if (textField == null) {
              createTextField();
          }
        
          setGraphic(textField);
          setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
          textField.selectAll();
      }
    
      @Override
      public void cancelEdit() {
          super.cancelEdit();
        
          setText(String.valueOf(getItem()));
          setContentDisplay(ContentDisplay.TEXT_ONLY);
      }

      @Override
      public void updateItem(Double item, boolean empty) {
          super.updateItem(item, empty);
        
          if (empty) {
              setText(null);
              setGraphic(null);
          } else {
              if (isEditing()) {
                  if (textField != null) {
                      textField.setText(getString());
                  }
                  setGraphic(textField);
                  setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
              } else {
                  setText(getString());
                  setContentDisplay(ContentDisplay.TEXT_ONLY);
              }
          }
      }

      private void createTextField() {
          textField = new TextField(getString());
          textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()*2);
          textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
            
              @Override
              public void handle(KeyEvent t) {
                  if (t.getCode() == KeyCode.ENTER) {
                      commitEdit(Double.parseDouble(textField.getText()));
                  } else if (t.getCode() == KeyCode.ESCAPE) {
                      cancelEdit();
                  }
              }
          });
      }
    
      private String getString() {
          return getItem() == null ? "" : getItem().toString();
      }
  }

}


Related article:
- Create and update PieChart from TableView
- Create and update LineChart from TableView
- Multi-column editable TableVIew

2 comments:

  1. 'm using javaFx-8 but this doesn't work
    @Override
    public void initialize(URL url, ResourceBundle rb) {
    facilitycol.setCellValueFactory(new javafx.scene.control.cell.PropertyValueFactory("UnitName"));
    quantitycol.setCellValueFactory(new javafx.scene.control.cell.PropertyValueFactory("Value"));
    table.setEditable(true);
    Callback cellFactory =
    new Callback() {
    public TableCell call(TableColumn p) {
    return new EditingCell();
    }
    };
    quantitycol.setOnEditCommit(
    new EventHandler>() {
    @Override public void handle(TableColumn.CellEditEvent t) {
    ((Person)t.getTableView().getItems().get(
    t.getTablePosition().getRow())).setValue(t.getNewValue());
    }
    });

    table.setItems(data);
    }
    class EditingCell extends TableCell {

    private TextField textField;

    public EditingCell() {}

    @Override
    public void startEdit() {
    super.startEdit();

    if (textField == null) {
    createTextField();
    }

    setGraphic(textField);
    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
    textField.selectAll();
    }

    @Override
    public void cancelEdit() {
    super.cancelEdit();

    setText(String.valueOf(getItem()));
    setContentDisplay(ContentDisplay.TEXT_ONLY);
    }

    @Override
    public void updateItem(String item, boolean empty) {
    super.updateItem(item, empty);

    if (empty) {
    setText(null);
    setGraphic(null);
    } else {
    if (isEditing()) {
    if (textField != null) {
    textField.setText(getString());
    }
    setGraphic(textField);
    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
    } else {
    setText(getString());
    setContentDisplay(ContentDisplay.TEXT_ONLY);
    }
    }
    }

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

    @Override
    public void handle(KeyEvent t) {
    if (t.getCode() == KeyCode.ENTER) {
    commitEdit(textField.getText());
    } else if (t.getCode() == KeyCode.ESCAPE) {
    cancelEdit();
    }
    }
    });
    }

    private String getString() {
    return getItem() == null ? "" : getItem().toString();
    }
    }
    public static class Person {

    private final SimpleStringProperty UnitName;
    private final SimpleStringProperty Value;

    private Person(String uName, String val ) {
    this.UnitName = new SimpleStringProperty(uName);
    this.Value = new SimpleStringProperty(val);

    }

    public String getUnitName() {
    return UnitName.get();
    }

    public void setUnitName(String uName) {
    UnitName.set(uName);
    }

    public String getValue() {
    return Value.get();
    }

    public void setValue(String val) {
    Value.set(val);
    }

    }
    }

    ReplyDelete