Revision 1 as of 2016-12-12 02:00:44

Clear message
Locked History Actions

JavaFX/TableViewCell

TableViewセルの扱い方

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

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

  • "email"はemailProperty()メソッドが
  • "name"はgetName()メソッドが
  • "address"はaddressProperty()メソッドが

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

  • 列に指定するフィールド名が間違っていた場合に何もエラーが出ない、セルが空白になるだけ。
  • メソッド側の名称が間違っていた場合も同じ。
  • TableViewに表示した後でセル内容を変更したい場合には、必ずObservableValueにする必要がある。つまり、setName()メソッドでnameデータを変更しても(特殊な方法以外では)それをテーブルに反映する方法はない。

  • ともあれ、文字列による結合なので、Obfuscatorにかけた場合には全く動作しなくなる。
  • 行のフィールドが不必要なものでいっぱいになる。

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 void setName(String name) { this.name = 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);
  }
}