Search code examples
javafxtreetableview

TreeTableView add nested value to TreeItemPropertyValueFactory


I need to add to my TreeTableView the content for two columns("Id" and "Workplace"). I don't know how to do it, because I can't get nested value from Manager -> ArrayList. What should I pass in TreeItemPropertyValueFactory if the type of the content can be only String???

The rest of code works OK. I will be grateful for any help.

enter image description here enter image description here

public void showStaffInTreeTable(){
        Employee emp_1 = new Employee("1", "secretary");
        Employee emp_2 = new Employee("2", "cleaner");
        Employee emp_3 = new Employee("3", "driver");
        Employee emp_4 = new Employee("4", "mechanic");

        ArrayList<Employee> johnStaff = new ArrayList<>(Arrays.asList(emp_1, emp_2));
        ArrayList<Employee> amandaStaff = new ArrayList<>(Arrays.asList(emp_3, emp_4));

        Manager john = new Manager("John", johnStaff);
        Manager amanda = new Manager("Amanda", amandaStaff);

        TreeTableColumn<Manager, String> columnManager = new TreeTableColumn<>("Manager");
        TreeTableColumn<Manager, String> columnStaffId = new TreeTableColumn<>("Id");
        TreeTableColumn<Manager, String> columnStaffWorkplace = new TreeTableColumn<>("Workplace");

        columnManager.setCellValueFactory(new TreeItemPropertyValueFactory<>("managersName"));
        columnStaffId.setCellValueFactory(new TreeItemPropertyValueFactory<>
                ("how to pass here: Manager-> ArrayList<Employess> -> getEmployee -> getId???"));
        columnStaffWorkplace.setCellValueFactory(new TreeItemPropertyValueFactory<>
                ("how to pass here: Manager-> ArrayList<Employess> -> getEmployee -> getWorkplace???"));

        TreeTableView<Manager> managers = new TreeTableView<>();
        managers.getColumns().addAll(columnManager, columnStaffId, columnStaffWorkplace);

        TreeItem managerItem_1 = new TreeItem(john);
        managerItem_1.getChildren().addAll(new TreeItem<>(emp_1), new TreeItem<>(emp_2));
        TreeItem managerItem_2 = new TreeItem(amanda);
        managerItem_2.getChildren().addAll(new TreeItem<>(emp_3), new TreeItem<>(emp_4));

        TreeItem root = new TreeItem(new Manager("", new ArrayList<>()));
        root.getChildren().addAll(managerItem_1, managerItem_2);
        root.setExpanded(true);

        managers.setRoot(root);
    }
public class Employee {
    private String id;
    private String workplace;

    public Employee(String id, String workplace) {
        this.id = id;
        this.workplace = workplace;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getWorkplace() {
        return workplace;
    }

    public void setWorkplace(String workplace) {
        this.workplace = workplace;
    }
}
public class Manager {
    private String managersName;
    private List<Employee> managersStaff = new ArrayList<>();

    public Manager(String managersName, List<Employee> managersStaff) {
        this.managersName = managersName;
        this.managersStaff = managersStaff;
    }

    public String getManagersName() {
        return managersName;
    }

    public void setManagersName(String managersName) {
        this.managersName = managersName;
    }

    public List<Employee> getManagersStaff() {
        return managersStaff;
    }

    public void setManagersStaff(List<Employee> managersStaff) {
        this.managersStaff = managersStaff;
    }
}

Solution

  • You can do

    columnStaffId.setCellValueFactory(cellData -> {
        TreeItem<?> item = cellData.getValue();
        Object data = item.getValue();
        if (data instanceof Employee) {
            Employee employee = (Employee)data ;
            return new SimpleStringProperty(employee.getId());
        } else {
            return new SimpleStringProperty("");
        }
    });
    

    Note in Java 14 you can simplify this to

    columnStaffId.setCellValueFactory(cellData -> {
        if (cellData.getValue().getValue() instanceof Employee employee) {
            return new SimpleStringProperty(employee.getId());
        } else {
            return new SimpleStringProperty("");
        }
    });
    

    Your setup is a little weird, as you declare a TreeTableView<Manager> but some of the items don't contain Managers, but Employees. So there's no real guarantee you don't get ClassCastExceptions thrown in places here, or other errors caused by the TreeItemPropertyValueFactory trying to call getManagersName() on an object that isn't a Manager.

    You might want to refactor so you use a TreeTableView<Object>, or maybe refactor the model so that Manager and Employee are both subclasses of some other class (which you then use as the type for your TreeTableView).