2014-02-07 5 views
2

그래서 JavaFx TableView에서 파고 들었습니다. 간단한 상황에 대한 멋진 해결책을 발견했습니다.지도가있는 JavaFX TableView 객체

article은 Person 개체로 Table을 만드는 방법에 대한 좋은 설명을 제공하고 Map을 사용하여 Table을 만드는 방법을 보여줍니다.

여기 내 문제입니다. 단순한 멤버 데이터와 성적에 대한 맵을 포함하는 개체 Person이 있다고 가정 해 봅니다.

예 :

private TableView<Student> table; 

간단하게 정의하기 쉬운 : 난과 같이 테이블을 정의하면 다음

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

같은 테이블을 표시 할

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

같은 열 :

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

하지만 맵의 각 키에 대해 열을 정의하는 방법은 무엇입니까?

지도를 처리하는 다른 테이블을 만들 수도 있습니까?

답변

4

기본 PropertyValueFactory를 사용할 필요는 없으며 직접 콜백을 작성할 수 있습니다.

Screen Shot

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과 같은 할당을 새 열을 추가하지 않고 추가 할 수 없습니다. 그렇지 않으면 나타나지 않습니다.

+1

굉장하고 훌륭한 솔루션! –

1

각 맵의 크기 (항목 수)는 런타임 동안 변경되지 않는다고 가정했는데, 고정 된 최대 항목 수가 있습니다. 이 경우 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-method를 정의했습니다. 이 부분은 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-방법 중 하나에 맞는 이름을 가져옵니다 가능성이 매우 중요하다. 자세한 내용은 the TableView-API을 참조하십시오.

당연히, 내 접근 방식은 런타임에서 클래스에 새 메소드를 추가하는 것이 Java에서 불가능하다는 것을 알고 있기 때문에 동적 맵에서 데이터를 가져 오는 문제를 해결하지 못합니다. 그러나이 제한을 피하기 위해 반사 API를 사용하는 트릭이있을 수 있습니다.

+0

안녕하세요, 고정 된지도를위한 훌륭한 솔루션! 불행히도이 맵은 런타임에 변경 될 수 있으므로 가능한 해결책으로 반영을 조사하기 시작합니다. 그것은 TableView 뭔가 달성 할 수있는 제한된 것으로 보인다 ... 기본 PropertyValueFactory 사용하는 방법을 주위에 얻을 수있는 테이블을 설정하는 특별한 방법 일종의 궁금 해서요. –