2016-09-20 1 views
0


TreeTableView: Affichage des différents types de données

J'ai une classe Factory qui contient une liste des employés. Je veux utiliser un TreeTableView pour afficher les données Factory. Il est assez en avant pour afficher le nom et la taille d'un Factory, mais je ne sais pas comment afficher les noms des employés!

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 

    } 

Je veux avoir la sortie suivante:

enter image description here

Avec la possibilité de plier l'usine.

+0

par « fold » voulez-vous dire dans un menu déroulant? –

+0

Je ne sais pas si c'est possible de cette façon, vous pouvez faire quelque chose de similaire en voyant le nom de l'usine et la taille répétée pour chaque enregistrement – MaglioniLorenzo

Répondre

3

Dans un TreeView ou TreeTableView tous les nœuds dans l'arborescence doivent être du même type. Cela rend le type de design que vous voulez (ce qui est très naturel) quelque chose d'une douleur. Fondamentalement, vous devez faire le type de TreeView ou TreeTableView la superclasse la plus spécifique de tous les types de lignes que vous voulez dans l'arbre: dans ce cas, le type de TreeTableView doit être une superclasse à la fois Employee et Factory. Ensuite, les fabriques de valeurs de cellule sur les colonnes devront taper les objets de ligne pour déterminer quelle valeur renvoyer.

Il serait inhabituel d'avoir un modèle d'objet dans lequel ceux-ci étaient liés par héritage autre que les deux étant des sous-classes de Object, donc vous avez probablement besoin d'un TreeTableView<Object> ici.

Donc, grosso modo (si vous utilisez le style ancien JavaBean plaine, au lieu du recommandé JavaFX properties), vous définiriez quelque chose comme

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); 

et bien sûr vous le remplissiez avec

// 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); 

Voici un simple SSCCE utilisant ceci:

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


Une autre approche, que je pense est un peu artificielle, est de créer une classe représentant la ligne de la vue de la table, puis de faire des sous-classes Factory et Employee de celui-ci:

public abstract class EmploymentEntity { 

    public String getName() { 
     return null ; 
    } 

    public Double getSize() { 
     return null ; 
    } 

    public String getEmployeeName { 
     return null ; 
    } 
} 

puis

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 ; 
    } 
} 

et

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 ; 
    } 
} 

Ce modèle d'objet est vraiment contre nature (pour moi, de toute façon), mais il ne fait la table un peu plus facile:

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

Une modification de ceci en utilisant un objet pour représenter la ligne du tableau qui contient l'employé et l'usine réaliser la même simplification de la table. Cela ne nécessiterait pas de modifier le modèle de données pour étendre un ancêtre commun et supprime le besoin de la conversion, etc. requis par la version Object. – Geoff

+0

@Geoff Cela ressemble à une bonne idée. Je ne vois pas de moyen propre de mettre en œuvre les usines de valeur de cellule cependant; cela évite les tests de type mais la logique serait encore assez compliquée (à moins que je ne néglige quelque chose, ce qui est certainement possible). –

+0

Ce serait essentiellement la même chose que votre deuxième solution, mais au lieu d'avoir des objets de domaine descendant de la classe commune, une classe wrapper le ferait, avec une implémentation pour chaque objet de domaine. Les usines de valeur cellulaire seraient identiques aux vôtres. Cela signifierait plus de classes qui seraient un inconvénient, donc je suppose que cela dépend de quel inconvénient est préféré? – Geoff