2014-02-07 120 views
2

所以我在JavaFx TableView上做了一些探索,我發現了一些很好的解決方案,以簡單的情況。JavaFX帶有地圖的TableView對象

這個article提供了一個很好的解釋,說明如何用Person對象創建一個表格,並且演示瞭如何使用Map創建一個表格。

這是我的問題,比方說,我有一個對象人員,其中包含一些簡單的成員數據,也是一個地圖的作業分級地圖。

實施例:

public class Person { 
    String firstName; 
    String lastName; 
    String age; 
    Map<Assignment, Grade> map; 
} 

我想顯示像下面

firstName | lastName | age | Assignment1 | Assignment 2 | Assignment 3 | ... 

表如果我定義像這樣一個表:

private TableView<Student> table; 

這是很容易定義簡單列如:

private TableColumn<Student, String> firstNameColumn = 
    firstNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName")); 

但我應該如何去爲地圖中的每個鍵定義列?

這是可能的,或者我應該只是創建另一個表處理地圖?

回答

4

您不必使用默認的PropertyValueFactory,您可以編寫自己的回調函數。

import java.util.HashMap; 
import java.util.LinkedHashMap; 
import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Scene; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class AssTable extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     ObservableList<Student> students = FXCollections.observableArrayList(
      new Student("jack"),new Student("john"),new Student("jill"),new Student("jane")); 
     TableView<Student> studentTable = new TableView(students); 
     TableColumn<Student, String> firstNameColumn = new TableColumn("name"); 
      firstNameColumn.setCellValueFactory(new PropertyValueFactory("firstName")); 
     studentTable.getColumns().add(firstNameColumn); 

     int maxAss = 0; 
     for (Student student : students) 
      maxAss = Math.max(maxAss, student.map.size()); 

     Callback<TableColumn.CellDataFeatures<Student, String>, ObservableValue<String>> callBack = 
       new Callback<TableColumn.CellDataFeatures<Student, String>, ObservableValue<String>>() { 
      @Override 
      public ObservableValue<String> call(TableColumn.CellDataFeatures<Student, String> param) { 
       return param.getValue().map.containsKey(
         "ass"+Integer.toString((int)param.getTableColumn().getUserData())) 
         ? new SimpleStringProperty(String.format("%.1f",100d*param.getValue().map.get(
          "ass"+Integer.toString((int)param.getTableColumn().getUserData())))) 
         :new SimpleStringProperty(""); 
      } 
     }; 

     ObservableList<TableColumn<Student, String>> assCols = FXCollections.observableArrayList(); 
     for (int i = 1; i<=maxAss; i++){ 
      TableColumn<Student, String> tmpCol = new TableColumn("ass"+Integer.toString(i)); 
      tmpCol.setUserData(i); 
      tmpCol.setCellValueFactory(callBack); 
      assCols.add(tmpCol); 
     } 
     studentTable.getColumns().addAll(assCols); 

     VBox root = new VBox(studentTable); 
     Scene scene = new Scene(root, 500, 250); 

     primaryStage.setTitle("Table with map"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public class Student { 

     private final StringProperty firstName = new SimpleStringProperty(); 
     public StringProperty firstNameProperty(){return firstName;} 
     public final HashMap<String, Double> map; 

     public Student(String fn) { 
      firstName.set(fn); 
      map = new LinkedHashMap<>(); 
      for (int i = 1; i <= 10; i++) { 
       double grade = Math.random(); 
       if (grade > .5) { 
        map.put("ass" + Integer.toString(i), grade); 
       } 
      } 
     } 
    } 
} 

Screen Shot

你可以看到它取決於有多少任務有添加列。在這個隨機樣本中也沒有人做過ass4。通過這段代碼和示例,您不能添加像#8那樣的任務,也不會添加新列,否則它不會顯示。

+1

真棒,偉大的解決方案! –

1

我認爲每個Map的大小(條目數)在運行時不會改變,或者更好:存在固定的最大值條目。如果是這種情況,TableView可以按照與標準屬性(或Property)相同的方式訪問每個Entry。 這裏是一個修改後的類Person

public class PersonSimple { 
String firstName; 
String lastName; 
String age; 
Map<Integer, Double> map; 

public PersonSimple(String fn, String ln, String age, Double gr0, Double gr1, Double gr2) 
{ 
    this.firstName = fn; 
    this.lastName = ln; 
    this.age = age; 
    map = new LinkedHashMap<>(); 
    map.put(0, gr0); 
    map.put(1, gr1); 
    map.put(2, gr2); 
} 

public String getFirstName() 
{ 
    return firstName; 
} 

public String getLastName() 
{ 
    return firstName; 
} 
public String getAge() 
{ 
    return age; 
} 

private Double getFromMap(Integer key) 
{ 
    Set<Entry<Integer, Double>> s = map.entrySet(); 
    Iterator<Entry<Integer, Double>> iter = s.iterator(); 
    int index = 0; 
    while(iter.hasNext()) 
    { 
     Entry<Integer, Double> e = iter.next(); 
     if(index == key.intValue()) 
     { 
      return e.getValue(); 
     } 
     index++; 
    } 
    return null; 
} 

public Double getFM0() 
{ 
    return getFromMap(0); 
} 

public Double getFM1() 
{ 
    return getFromMap(1); 
} 

public Double getFM2() 
{ 
    return getFromMap(2); 
} 

}

正如你可以看到,每一個PersonSimpleMap必須持有三個條目。現在來訣竅。對於每個條目,您都定義了一個get方法。小心如何命名它們,因爲這部分對與TableView的交互至關重要。

以下代碼顯示如何將這些新方法連接到TableView

TableColumn firstNameCol = new TableColumn("First Name"); 
    TableColumn lastNameCol = new TableColumn("Last Name"); 
    TableColumn ageCol = new TableColumn("Age"); 
    TableColumn aCol = new TableColumn("Assignment1"); 
    TableColumn bCol = new TableColumn("Assignment2"); 
    TableColumn cCol = new TableColumn("Assignment3"); 

    table.getColumns().addAll(firstNameCol, lastNameCol, ageCol,aCol,bCol,cCol); 

    firstNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName")); 
    lastNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("lastName")); 
    ageCol.setCellValueFactory(new PropertyValueFactory<Person,String>("age")); 

    aCol.setCellValueFactory(new PropertyValueFactory<Person,Double>("FM0")); 
    bCol.setCellValueFactory(new PropertyValueFactory<Person,Double>("FM1")); 
    cCol.setCellValueFactory(new PropertyValueFactory<Person,Double>("FM2")); 

這是非常重要的,每個PropertyValueFactor獲得適合於在課堂PersonSimple一開始的方法之一的名稱。有關詳細信息,請參見the TableView-API

當然,我的方法並沒有解決從動態映射中獲取數據的問題,因爲據我所知,在運行時在Java中添加新方法是不可能的。但是使用reflection-api來繞過這個限制可能會有一些技巧。

+0

嘿人,一個固定的地圖很好的解決方案!不幸的是,這張地圖可能在運行時發生變化,這導致我開始將反射看作一種可能的解決方案。看起來TableView在它的實現方面有一定的侷限性......我想知道是否有某種特殊的方式來設置表格來繞過這種使用Default PropertyValueFactory的方式。 –