[英]JavaFX TableView Objects with Maps
所以我在JavaFx TableView上做了一些挖掘,我找到了一些很好的解決方案來處理簡單的情況。
本文提供了如何使用Person對象創建表的一個很好的解釋,並且還展示了如何使用Map創建表。
這是我的問題,假設我有一個Object Person,它包含一些簡單的成員數據,還有一個Level to Assignments to Grades。
例:
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"));
但是,我應該如何為地圖中的每個鍵定義列?
這甚至是可能的還是我應該創建另一個處理地圖的表?
您不必使用默認的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);
}
}
}
}
}
您可以看到它根據分配的數量添加列。 此隨機樣本中也沒有人做過ass4。 使用此代碼和示例,您無法添加#8之類的分配而不添加新列,或者它不會顯示。
我假設每個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);
}
}
如您所見,每個PersonSimple
都有一個必須包含三個條目的Map
。 現在來了訣竅。 對於每個條目,您都定義了一個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
類中其中一個get方法的PersonSimple
。 有關詳細信息,請參閱TableView-API 。
當然,我的方法並沒有解決從動態映射中獲取數據的問題,因為據我所知,Java在運行時期間無法向類中添加新方法。 但是可能有一個技巧使用reflection-api來規避這種限制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.