14

I have the next class

public class ProductStockDto extends 

    private Long id;
    private Long amount;
    private ProductDto product;
    private StockDto stock;

    //getters and setters...
}

In JavaFx I have my table and I want to bind the product.name property to the column, something like this.

ObservableList<ProductStockDto> data = FXCollections.observableArrayList();
data.addAll(products);
nameColumn.setCellValueFactory(new PropertyValueFactory("product.name"));
productTable.setItems(data);

But when I do that, the rows on the TableView appears on blank.

Somebody can help me with this? I want to bind nested object properties, on Java Swing was something like that ${product.name}

Thanks.

9 Answers 9

12

I had the same problem and couldn't make it work in any suggested way, but what did the trick for me, if we instantiate columns and have nested property, for instance, in class Employee:

@FXML
private TableColumn<Employee, String> columnEmpName;
@FXML
private TableColumn<Employee, String> columnEmpLastName;
@FXML
private TableColumn<Employee, String> columnEmpJobDesc;

And class is:

public class Employee {
   private String name;
   private String lastName;
   .
   .
   private EmployeeJobDescription jobDesc; //this one is nested
}

I have made ObservableValue<String> out of string I picked up for that property

columnEmpName.setCellValueFactory(new PropertyValueFactory<Employee, String>("name"));
columnEmpLastName.setCellValueFactory(new PropertyValueFactory<Employee, String>("lastname"));
columnEmpJobDesc.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getJobDesc().getJobDescription()));

And the EmployeeJobDescription would be with all getters and setters

public class EmployeeJobDescription {

private Integer id;
private String jobDescription;

public EmployeeJobDescription(Integer id) {
    this.id = id;
}

public EmployeeJobDescription(Integer id, String jobDescription) {
    this.id = id;
    this.jobDescription = jobDescription;
}

public Integer getId() {
    return id;
}

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

public String getJobDescription() {
    return jobDescription;
}

public void setJobDescription(String jobDescription) {
    this.jobDescription = jobDescription;
}

}

Found out how to do that in this post:

Convert a String to an ObservableValue

Sign up to request clarification or add additional context in comments.

2 Comments

Can this method be done when constructnig the columns via the .fxml file?
@Stealth Rabbi sorry for a bit late answer but I haven't used Java since this post. I believe it can be used but I am not sure. I hope you'll find a solution
7

This format is not supported in Javafx, as a work around, you can try something like this :

nameColumn.setCellValueFactory(new Callback<CellDataFeatures<ProductStockDto, String>, 
                                                         ObservableValue<String>>() {  
    @Override  
    public ObservableValue<String> call(CellDataFeatures<ProductStockDto, String> data){  
         return data.getValue().getProducts().nameProperty();  
    }  
});  

where ProductDto will have

public class ProductDto{

    private StringProperty name = new SimpleStringProperty("Itachi");

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

    public void setStreet(String name) {
        this.name.set(name);
    }

    public StringProperty nameProperty(){
        return name;
    }
}

Comments

7

As variant you may work with synthetic property.

Lets name it as 'productName':

nameColumn.setCellValueFactory(new PropertyValueFactory("productName"));

In your ProductStockDto class have something like this:

public String getProductName() {
   return product.getName();
}

2 Comments

For some reason it gave me an error "Could not find a setter for property foo in class bar". I solved it by adding @Transient annotation above the getProductName() function. And also added this on the top import javax.persistence.Transient;
+1, correct workaround. Seems, you have serialization/deserialization and in this case the pair of get/set is expected. The Transient annotation exclude this from serialization/deserialization scope.
4
TableColumn<ProductStockDto , String> ProductNameCol = new ProductNameCol ("Product Name");

ProductNameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ProductStockDto , String>, ObservableValue<String>>() {

    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<ProductStockDto , String> param) {
        return new SimpleObjectProperty<>(param.getValue().ProductDto ().getName());

    }
});

2 Comments

Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others.
Simple and valuable solution.
1

You can simply use :

nameColumn.setCellValueFactory(new PropertyValueFactory("product"));

This will use the toString() method from the object product. However, if you do only this, you may end with something like "ProductDto@abcef123" with is the default return of a complex object of the toString method.

What you can do is then override the toString method :

@Override
public String toString(){
    return //Whatever you want to show
}

I've been stuck with this, and eventually find this solution. Hope this will help.

Comments

1

Please try the following code, which used Apache BeanUtils.

public class StringCellValueFactory implements 
  Callback<CellDataFeatures<Object, String>, ObservableValue<String>> {
    private String property;

    public StringCellValueFactory(String property) {
        this.property = property;
    }

    public ObservableValue<String> call(CellDataFeatures<Object, String> param) {
        Object value = param.getValue();
        String stringValue = null;
        try {
            stringValue = BeanUtils.getNestedProperty(value, property);
        } catch (Exception e) {
            logger.error("Error in StringCellValueFactory", e);
        }

        return new SimpleStringProperty(stringValue);
    }
}

1 Comment

Instead of org.apache.commons.beanutils.BeanUtils, org.apache.commons.beanutils.PropertyUtils can be use used, if the value is java.util.Date, any user-defined objects, etc.
1

If you have a object and a attribute with another type as String (example: a number "productDto_nr" with integer in class ProductDto), you can solve this with type StringProperty.

nameColumn.setCellValueFactory(new Callback<CellDataFeatures<ProductStockDto, String>, ObservableValue<String>>() {
    @Override
    public ObservableValue<String> call(CellDataFeatures<ProductStockDto, String> data) {
        StringProperty sp = new SimpleStringProperty();
        sp.setValue(String.valueOf(data.getValue().getProduct().getProductDto_nr()));
        return sp;
    }
});

Comments

0

if we have A property that is not a primitive java data type, thus we can not access it directly by steps (e.g. ProductStockDto.product.name) where ProductStockDto is an entity and product is a an other entity and product has property String name. here. we need to render name column in a TableView as I answered in previous response.

in addition, you can use : javafx.beans.property.adapter package to convert javabeans object to javafx beans object properties. if you want more complex code.

Comments

0

It is not necessary to change your regular Java class:

 nameCol.setCellValueFactory(new Callback<CellDataFeatures<ProductDto, String>, ObservableValue<String>>() {
     public ObservableValue<String> call(CellDataFeatures<ProductDto, String> p) {
         return new ReadOnlyObjectWrapper(p.getValue().getCost());
     }
  });

3 Comments

Please post in english only!
Please post in english!
A translation of the answerer's text would be "It is not necessary to change your regular Java class:"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.