1

I am experimenting with JavaFX and I am trying to add a progress bar in tree table. Is there a way to link the values of salary to progress bar.

My Code is modified version of Oracle's TreeTableView Example:

public class TreeTableViewSample extends Application implements Runnable {

List<Employee> employees = Arrays.<Employee>asList(
        new Employee("Ethan Williams", 30.0),
        new Employee("Emma Jones", 10.0),
        new Employee("Michael Brown", 70.0),
        new Employee("Anna Black", 50.0),
        new Employee("Rodger York", 20.0),
        new Employee("Susan Collins", 70.0));

/*  private final ImageView depIcon = new ImageView (
 new Image(getClass().getResourceAsStream("department.png"))
 );
 */
final CheckBoxTreeItem<Employee> root
        = new CheckBoxTreeItem<>(new Employee("Sales Department", 0.0));
final CheckBoxTreeItem<Employee> root2
        = new CheckBoxTreeItem<>(new Employee("Departments", 0.0));

public static void main(String[] args) {
    Application.launch(TreeTableViewSample.class, args);
}

@Override
public void start(Stage stage) {
    root.setExpanded(true);
    employees.stream().forEach((employee) -> {
        CheckBoxTreeItem<Employee> cbt=new CheckBoxTreeItem<>(employee);
        cbt.selectedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
                if (newValue) {
                    System.out.println("Slected employ name is "+cbt.getValue().getName()); 
                }
            });

        root.getChildren().add(cbt);
    });
    stage.setTitle("Tree Table View Sample");
    final Scene scene = new Scene(new Group(), 400, 400);
    scene.setFill(Color.LIGHTGRAY);
    Group sceneRoot = (Group) scene.getRoot();

    TreeTableColumn<Employee, String> empColumn
            = new TreeTableColumn<>("Employee");
    empColumn.setPrefWidth(150);
    empColumn.setCellValueFactory(
            (TreeTableColumn.CellDataFeatures<Employee, String> param)
            -> new ReadOnlyStringWrapper(param.getValue().getValue().getName())
    );

    TreeTableColumn<Employee, Double> salaryColumn
            = new TreeTableColumn<>("Salary");
    salaryColumn.setPrefWidth(190);
    salaryColumn.setCellValueFactory(new Callback<CellDataFeatures<Employee, Double>, ObservableValue<Double>>() {
  @Override
  public ObservableValue<Double> call(CellDataFeatures<Employee, Double> p)          {
// p.getValue() returns the Employee instance for a particular TableView row
      return p.getValue().getValue().getSalary();
 }
 });
    salaryColumn.setCellFactory(ProgressBarTreeTableCell.<Employee>forTreeTableColumn());
    root2.getChildren().add(root);

    TreeTableView<Employee> treeTableView = new TreeTableView<>(root2);
    treeTableView.getColumns().setAll(empColumn, salaryColumn);
    treeTableView.setRowFactory(f -> new CheckBoxTreeTableRowHack<>());
    sceneRoot.getChildren().add(treeTableView);
    stage.setScene(scene);
    stage.show();
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    executorService.scheduleAtFixedRate(this, 3, 10, TimeUnit.SECONDS);

}

@Override
public void run() {
    root2.getValue().setSalary(calcSalary(root));
}

public double calcSalary(TreeItem<Employee> t) {
    Double salary = 0.0;
    if (!t.isLeaf()) {

        ObservableList<TreeItem<Employee>> al = t.getChildren();
        for (int i = 0; i < al.size(); i++) {
            TreeItem<Employee> get = al.get(i);
            salary += calcSalary(get);
        }
        t.getValue().setSalary(salary);
    }
    return salary += t.getValue().getSalary();
}

public class Employee {

    private SimpleStringProperty name;
    private SimpleDoubleProperty salary;

    public SimpleStringProperty nameProperty() {
        if (name == null) {
            name = new SimpleStringProperty(this, "name");
        }
        return name;
    }

    public SimpleDoubleProperty salaryProperty() {
        if (salary == null) {
            salary = new SimpleDoubleProperty(this, "salary");
        }
        return salary;
    }

    private Employee(String name, Double salary) {
        this.name = new SimpleStringProperty(name);
        this.salary = new SimpleDoubleProperty(salary);
    }

    public String getName() {
        return name.get();
    }

    public void setName(String fName) {
        name.set(fName);
    }

    public Double getSalary() {
        return salary.get();
    }

    public void setSalary(Double fName) {
        salary.set(fName);
    }
}
}

I am recieving error at return p.getValue().getValue().getSalary(); it says Incompatible Types: Double cannot be converted to ObservableValue<Double>. As i know you have to return ObservableValue in the return of the call method. But as newbie i am unable to find a way to cast the value. Setting string is easy.

So far i have tried return new ReadOnlyDoubleWrapper(p.getValue().getValue().getSalary()); but that also didn't worked out for me.

I am using JavaFx 8.

I am trying to create Salary Bars, which can also be used as progress bar for a task and its sub tasks. (Just playing with UI). But don't know how to connect them with the real values of employe, as i guess normal table view is different from tree table view. Thanks ! :)

DeepSidhu1313
  • 805
  • 15
  • 31
  • possible duplicate of [JavaFX: Add UI control to TreeTableView](http://stackoverflow.com/questions/26233554/javafx-add-ui-control-to-treetableview) – ItachiUchiha Mar 31 '15 at 10:05
  • @ItachiUchiha How can i set salary to progress bar according to your code. My apologies i am working continuously, so may be it is becoming hard for me to understand the code :P. It is not simple as `setCellValueFactory( new PropertyValueFactory("salary") );` – DeepSidhu1313 Mar 31 '15 at 14:09

1 Answers1

2

This is essentially the same as JavaFX Properties in TableView : salaryProperty is not an ObservableValue<Double> but is an ObservableValue<Number>.

You need to make the column a TreeTableColumn<Employee, Number>. Then you can just return the salaryProperty for the employee:

TreeTableColumn<Employee, Number> salaryColumn
        = new TreeTableColumn<>("Salary");
salaryColumn.setCellValueFactory(p -> p.getValue().getValue().salaryProperty());

The other option is to use salaryProperty().asObject() which returns an ObjectProperty<Double> bidirectionally bound to salaryProperty():

TreeTableColumn<Employee, Double> salaryColumn
        = new TreeTableColumn<>("Salary");
salaryColumn.setCellValueFactory(p -> 
    p.getValue().getValue().salaryProperty().asObject());
Community
  • 1
  • 1
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thanks :) , Second one worked, but progressbar is not showing as i expected. All progressbars are full , i wanted to set Parent Progress Bar's value as maximum and others according to that (intermediate value). For example if Parent ProgressBar is 100 and lets say children ProgressBars sum should be 100.(like 10,20,30,40 can be values of children progressBar). Is this achievable ? – DeepSidhu1313 Mar 31 '15 at 16:41
  • 1
    `ProgressBar` takes values for `progress` between `0` and `1`. To get the correct display for other ranges, you need to subclass `TreeTableCell` and set the value directly. – James_D Mar 31 '15 at 16:48
  • :) Sir, Do i have to ask that question separately :) ?? – DeepSidhu1313 Mar 31 '15 at 17:48
  • 1
    Yes, now you have the correct value (which I think is what this question is about), try to implement your own cell with a progress bar, and if you have trouble, post a new question. But you should try it yourself first. – James_D Mar 31 '15 at 18:41
  • :) Thanks, i solved the problem by finding total salary and then setting value between 0 and 1. But i am still curious about `TreeTableCell` with custom `ProgressBar`. Is there any example available? – DeepSidhu1313 Mar 31 '15 at 19:03
  • 1
    The tutorial has an example of creating a custom cell with a graphic for a `ListView`: the idea is similar. See [example 12.4](http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/list-view.htm#CEGGEDBF). – James_D Mar 31 '15 at 19:25