JavaFX/TableViewCell

TableViewセルの扱い方

面倒で不安定なフィールド指定

TableViewに指定されるColumnのフィールドは文字列で指定される例が多い。その文字列から適切なフィールドとして使用できる「メソッド」が勝手に探し出される。 以下の例では、

探し出される。通常は「フィールド名 + Property」というObservableValueが返されるメソッドが探し出されるが、なければ「get + 頭大文字フィールド名」というゲッターメソッドが採用されるようだ。 しかしこれには問題がある。

import javafx.application.*;
import javafx.beans.property.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.stage.*;

public class CumbersomeFields extends Application {

  public static class Row {
    
    Row(String email, String name, String address) {
      this.emailWrapper.set(email);
      this.name = name;
      this.addressProperty.set(address);
    }
    
    private ReadOnlyStringWrapper emailWrapper = new ReadOnlyStringWrapper();
    public ReadOnlyStringProperty emailProperty() { return emailWrapper.getReadOnlyProperty(); }

    private String name;
    public String getName() { return name; }
    
    public SimpleStringProperty addressProperty = new SimpleStringProperty();
    public SimpleStringProperty addressProperty() { return addressProperty; }
  }
  
  @SuppressWarnings("unchecked")
  @Override
  public void start(Stage stage) throws Exception {    
    TableView<Row>tableView= new TableView<>();
    tableView.getColumns().addAll(
       new Column<Row, String>("EMAIL", "email").col,
       new Column<Row, String>("NAME", "name").col,
       new Column<Row, String>("ADDRESS", "address").col
    );
    tableView.getItems().addAll(
      new Row("email1", "name1", "address1"), 
      new Row("email2", "name2", "address")
    );
    stage.setScene(new Scene(tableView));
    stage.show();
  }
  
  static class Column<E, T> {
    TableColumn<E, T>col;
    Column(String title, String field) {
      col = new TableColumn<E, T>(title);
      col.setCellValueFactory(new PropertyValueFactory<E, T>(field));
    }
  }
  
  public static void main(String[] args) throws Exception {
    launch(args);
  }
}

改良版は以下。ここでは、

import javafx.application.*;
import javafx.beans.*;
import javafx.beans.property.*;
import javafx.beans.value.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.stage.*;

public class ImprovedFields extends Application {

  public static class Row {
    
    Row(String email, String name, String address) {
      this.emailWrapper.set(email);
      this.name = name;
      this.address.set(address);
    }
    
    private ReadOnlyStringWrapper emailWrapper = new ReadOnlyStringWrapper();
    public ReadOnlyStringProperty email() { return emailWrapper.getReadOnlyProperty(); }

    private String name;
    public String getName() { return name; }
    
    public SimpleStringProperty address = new SimpleStringProperty();
  }
  
  @SuppressWarnings("unchecked")
  @Override
  public void start(Stage stage) throws Exception {    
    TableView<Row>tableView= new TableView<>();
    tableView.getColumns().addAll(
       new Column<Row, String>("EMAIL", r->r.email()).col,
       new Column<Row, String>("NAME", r->fv(r.getName())).col,
       new Column<Row, String>("ADDRESS", r->r.address).col
    );
    tableView.getItems().addAll(
      new Row("email1", "name1", "address1"), 
      new Row("email2", "name2", "address")
    );
    stage.setScene(new Scene(tableView));
    stage.show();
  }

  private <T> FixedValueWrapper<T> fv(T value) {
    return new FixedValueWrapper<T>(value);
  }

  /** 固定値なのでリスナー登録等は一切無視 */
  public static class FixedValueWrapper<T> implements ObservableValue<T>{
    T value;
    public FixedValueWrapper(T value) {
      this.value = value;
    }
    public T getValue() {
      return value;
    }
    public void addListener(InvalidationListener listener) {}
    public void removeListener(InvalidationListener listener) {}
    public void addListener(ChangeListener<? super T> listener) {}
    public void removeListener(ChangeListener<? super T> listener) {}
  }

  public interface PropertyGetter<E, T> {
    public ObservableValue<T> get(E e);
  }
  
  static class Column<E, T> {
    TableColumn<E, T>col;
    Column(String title, PropertyGetter<E, T>getProperty) {
      col = new TableColumn<E, T>(title);
      col.setCellValueFactory(t->getProperty.get(t.getValue()));
    }
  }
  
  public static void main(String[] args) throws Exception {
    launch(args);
  }
}
last edited 2016-12-12 07:00:59 by ysugimura