2016-09-20 67 views
0


TreeTableView:显示不同的数据类型

我有一个Factory类,其中包含员工的列表。我想用TreeTableView来显示Factory数据。显示Factory的名称和大小是相当不错的,但我不知道如何显示员工姓名!

public class Factory { 
     private String name; 
     private double size; 
     private List<Employee> employees; 

     public Factory(name, size){this.name=name; this.size=size} 

     // Getters & setters 

    } 

我想有以下输出:

enter image description here

随着possibilty工厂倍。

+0

通过“折叠”你在下拉的意思吗? –

+0

我不知道是否有可能以这种确切的方式,你可以做类似的事情,看到每个记录的工厂名称和大小重复 – MaglioniLorenzo

回答

3

TreeViewTreeTableView树中的所有节点必须是相同类型的。这使得你想要的设计(这是非常自然的)是一种痛苦。基本上,您必须将TreeViewTreeTableView的类型设置为树中所需的所有行类型的最具体的超类:即在此情况下,TreeTableView的类型必须是EmployeeFactory的超类。然后,列上的单元格值工厂必须对行对象进行类型测试以确定要返回的值。

拥有一个对象模型并不常见,其中这些对象模型通过继承而不是两者都是Object的子类,因此您可能在这里需要TreeTableView<Object>

因此粗略地说(如果你使用普通的旧JavaBean风格的,而不是推荐JavaFX properties),你会用填充它定义像

TreeTableView<Object> treeTable = new TreeTableView<>(); 
treeTable.setShowRoot(false); 

TreeTableColumn<Object, String> nameColumn = new TreeTableColumn<>("Name"); 
nameColumn.setCellValueFactory(cellData -> { 
    TreeItem<Object> rowItem = cellData.getValue(); 
    if (rowItem != null && (rowItem.getValue() instanceof Factory)) { 
     Factory f = (Factory) rowItem.getValue() ; 
     return new SimpleStringProperty(f.getName()); 
    } else { 
     return new SimpleStringProperty(""); 
    } 
}); 

TreeTableColumn<Object, Number> sizeColumn = new TreeTableColumn<>("Size"); 
sizeColumn.setCellValueFactory(cellData -> { 
    TreeItem<Object> rowItem = cellData.getValue(); 
    if (rowItem != null && (rowItem.getValue() instanceof Factory)) { 
     Factory f = (Factory) rowItem.getValue() ; 
     return new SimpleObjectProperty<Number>(Double.valueOf(f.getSize())); 
    } else { 
     return new SimpleObjectProperty<Number>(null); 
    } 
}); 

TreeTableColumn<Object, String> employeeColumn = new TreeTableColumn<>("Employee"); 
employeeColumn.setCellValueFactory(cellData -> { 
    TreeItem<Object> rowItem = cellData.getValue(); 
    if (rowItem != null && (rowItem.getValue() instanceof Employee)) { 
     Employee emp = (Employee) rowItem.getValue() ; 
     return new SimpleStringProperty(emp.getName()); 
    } else { 
     return new SimpleStringProperty(""); 
    } 
}); 

treeTable.getColumns().addAll(nameColumn, sizeColumn, employeeColumn); 

当然

// fully initialized list of factories, with employee lists initialized: 
List<Factory> factories = ... ; 

TreeItem<Object> root = new TreeItem<>(null); 
for (Factory factory : factories) { 
    TreeItem<Object> factoryItem = new TreeItem<>(factory); 
    root.getChildren().add(factoryItem); 
    for (Employee emp : factory.getEmployees()) { 
     TreeItem<Object> employeeItem = new TreeItem<>(emp); 
     factoryItem.getChildren().add(employeeItem); 
    } 
} 
treeTable.setRoot(root); 

这是一个简单的SSCCE使用这个:

import java.util.ArrayList; 
import java.util.List; 

import javafx.application.Application; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.scene.Scene; 
import javafx.scene.control.TreeItem; 
import javafx.scene.control.TreeTableColumn; 
import javafx.scene.control.TreeTableView; 
import javafx.stage.Stage; 

public class TreeTableExample extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TreeTableView<Object> treeTable = new TreeTableView<>(); 
     treeTable.setShowRoot(false); 

     TreeTableColumn<Object, String> nameColumn = new TreeTableColumn<>("Name"); 
     nameColumn.setCellValueFactory(cellData -> { 
      TreeItem<Object> rowItem = cellData.getValue(); 
      if (rowItem != null && (rowItem.getValue() instanceof Factory)) { 
       Factory f = (Factory) rowItem.getValue() ; 
       return new SimpleStringProperty(f.getName()); 
      } else { 
       return new SimpleStringProperty(""); 
      } 
     }); 

     TreeTableColumn<Object, Number> sizeColumn = new TreeTableColumn<>("Size"); 
     sizeColumn.setCellValueFactory(cellData -> { 
      TreeItem<Object> rowItem = cellData.getValue(); 
      if (rowItem != null && (rowItem.getValue() instanceof Factory)) { 
       Factory f = (Factory) rowItem.getValue() ; 
       return new SimpleObjectProperty<Number>(Double.valueOf(f.getSize())); 
      } else { 
       return new SimpleObjectProperty<Number>(null); 
      } 
     }); 

     TreeTableColumn<Object, String> employeeColumn = new TreeTableColumn<>("Employee"); 
     employeeColumn.setCellValueFactory(cellData -> { 
      TreeItem<Object> rowItem = cellData.getValue(); 
      if (rowItem != null && (rowItem.getValue() instanceof Employee)) { 
       Employee emp = (Employee) rowItem.getValue() ; 
       return new SimpleStringProperty(emp.getName()); 
      } else { 
       return new SimpleStringProperty(""); 
      } 
     }); 

     treeTable.getColumns().addAll(nameColumn, sizeColumn, employeeColumn); 

     List<Factory> factories = createData(); 
     TreeItem<Object> root = new TreeItem<>(null); 
     for (Factory factory : factories) { 
      TreeItem<Object> factoryItem = new TreeItem<>(factory); 
      root.getChildren().add(factoryItem); 
      for (Employee emp : factory.getEmployees()) { 
       TreeItem<Object> employeeItem = new TreeItem<>(emp); 
       factoryItem.getChildren().add(employeeItem); 
      } 
     } 
     treeTable.setRoot(root); 

     Scene scene = new Scene(treeTable, 800, 800); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private List<Factory> createData() { 
     String[][] empNames = { 
       {"John", "Jane", "Mary"}, 
       {"Susan", "Mike"}, 
       {"Alex", "Francois", "Joanne"} 
     }; 
     List<Factory> factories = new ArrayList<>(); 
     for (String[] emps : empNames) { 
      int count = factories.size()+1 ; 
      Factory f = new Factory("Factory "+ count, count*10); 
      for (String empName : emps) { 
       f.getEmployees().add(new Employee(empName)); 
      } 
      factories.add(f); 
     } 
     return factories ; 
    } 

    public static class Employee { 
     private String name ; 

     public Employee(String name) { 
      this.name = name ; 
     } 

     public String getName() { 
      return name; 
     } 

     public void setName(String name) { 
      this.name = name; 
     } 


    } 

    public class Factory { 
     private String name ; 
     private double size ; 
     private List<Employee> employees ; 

     public Factory(String name, double size) { 
      this.name = name ; 
      this.size = size ; 
      this.employees = new ArrayList<>(); 
     } 

     public String getName() { 
      return name; 
     } 

     public void setName(String name) { 
      this.name = name; 
     } 

     public double getSize() { 
      return size; 
     } 

     public void setSize(double size) { 
      this.size = size; 
     } 

     public List<Employee> getEmployees() { 
      return employees; 
     } 


    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

enter image description here


另一种方法,我认为这是一个有点做作,是创建表示在表视图行类,然后利用它FactoryEmployee子类:

public abstract class EmploymentEntity { 

    public String getName() { 
     return null ; 
    } 

    public Double getSize() { 
     return null ; 
    } 

    public String getEmployeeName { 
     return null ; 
    } 
} 

然后

public class Employee extends EmploymentEntity { 
    private String name ; 

    public Employee(String name) { 
     this.name = name ; 
    } 

    @Override 
    public String getEmployeeName() { 
     return name ; 
    } 

    public void setEmployeeName(String name) { 
     this.name = name ; 
    } 
} 

public class Factory extends EmploymentEntity { 

    private String name ; 
    private double size ; 
    private List<Employee> employees ; 

    public Factory(String name, double size) { 
     this.name = name ; 
     this.size = size ; 
     this.employees = new ArrayList<>(); 
    } 

    @Override 
    public String getName() { 
     return name ; 
    } 

    public void setName(String name) { 
     this.name = name ; 
    } 

    @Override 
    public Double getSize() { 
     return size ; 
    } 

    public void setSize(double size) { 
     this.size = size ; 
    } 

    public List<Employee> getEmployees() { 
     return employees ; 
    } 
} 

此对象模型确实是不自然的(对我来说,反正),但它确实使该表更容易一些:

TreeTableView<EmploymentEntity> treeTable = new TreeTableView<>(); 
TreeTableColumn<EmploymentEntity, String> nameColumn = new TreeTableColumn<>("Name"); 
nameColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getValue().getName())); 
TreeTableColumn<EmploymentEntity, Number> sizeColumn = new TreeTableColumn<>("Size"); 
sizeColumn.setCellValueFactory(cellData -> new SimpleObjectProperty<Number>(cellData.getValue().getValue().getSize())); 
TreeTableColumn<EmploymentEntity, String> employeeColumn = new TreeTableColumn<>("Employee"); 
employeeColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getValue().getEmployeeName())); 
// etc... 
+0

使用对象来表示包含Employee和Factory的表行的修改实现表格的相同简化。这不需要改变数据模型来扩展一个共同的祖先,也不需要对象版本所需的强制转换等。 – Geoff

+0

@Geoff这看起来不错。虽然我没有看到一个干净的方式来实施细胞价值工厂,它避免了类型测试,但逻辑仍然非常混乱(除非我忽略了某些东西,这当然是可能的)。 –

+0

它与我认为的第二种解决方案基本相同,但不是让域对象从普通类降序,而是使用包装类来实现,而每个域对象只需一个实现。细胞价值工厂与您的细胞价值工厂完全相同。这将意味着更多的类将是一个不利的方面,所以我想这取决于哪个下降是首选? – Geoff