I was trying to add TableColumn
s to my TableView
when an error popped up because my PropertyValueFactory
could not read the property inside it. This was because the property that I was passing to it was from the parent class. Is there anyway for PropertyValueFactory
to accept the parent class data through the child class because of the super function? Code is posted below. I looked at other SO posts but they don't address what to do when you use an inherited class property.
Parent Class
public abstract class User {
private String username;
private String password;
public User(String username, String password){
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Child Class
public class Customer extends User {
private int points;
public Customer(String username, String password, int points){
super(username,password);
this.points = points;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
}
TableColumn Code
TableColumn<Customer,String> customerUsernameCol = new TableColumn<>("Customer Username");
customerUsernameCol.setMinWidth(100);
customerUsernameCol.setCellValueFactory(new PropertyValueFactory<>("username")); //Does not work as intended
TableColumn<Customer,String> customerPasswordCol = new TableColumn<>("Customer Password");
customerPasswordCol.setMinWidth(100);
customerPasswordCol.setCellValueFactory(new PropertyValueFactory<>("password")); //Does not work as intended
TableColumn<Customer,Integer> customerPointsCol = new TableColumn<>("Customer Points");
customerUsernameCol.setMinWidth(100);
customerUsernameCol.setCellValueFactory(new PropertyValueFactory<>("points"));
Don't use PropertyValueFactory. Define your own CellValueFactory
. You just need to implement the appropriate Callback.
(Notes after the code.)
import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TblVwTst extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Customer customer1 = new Customer("George", "Best", 8);
TableView<Customer> tblVw = new TableView<>();
ObservableList<Customer> items = tblVw.getItems();
items.add(customer1);
TableColumn<Customer, String> usernameColumn = new TableColumn<>("User");
Callback<TableColumn.CellDataFeatures<Customer, String>, ObservableValue<String>> usernameColumnCellValue;
usernameColumnCellValue = cellDataFeatures -> {
Customer customer = cellDataFeatures.getValue();
String username = customer.getUsername();
ObservableValue<String> usernameObservableValue = new SimpleStringProperty(username);
return usernameObservableValue;
};
usernameColumn.setCellValueFactory(usernameColumnCellValue);
TableColumn<Customer, String> passwordColumn = new TableColumn<>("Password");
Callback<TableColumn.CellDataFeatures<Customer, String>, ObservableValue<String>> passwordColumnCellValue;
passwordColumnCellValue = cellDataFeatures -> {
Customer customer = cellDataFeatures.getValue();
String password = customer.getPassword();
ObservableValue<String> passwordObservableValue = new SimpleStringProperty(password);
return passwordObservableValue;
};
passwordColumn.setCellValueFactory(passwordColumnCellValue);
TableColumn<Customer, Number> pointsColumn = new TableColumn<>("Points");
Callback<TableColumn.CellDataFeatures<Customer, Number>, ObservableValue<Number>> pointsColumnCellValue;
pointsColumnCellValue = cellDataFeatures -> {
Customer customer = cellDataFeatures.getValue();
int points = customer.getPoints();
ObservableValue<Number> pointsCellValue = new SimpleIntegerProperty(points);
return pointsCellValue;
};
pointsColumn.setCellValueFactory(pointsColumnCellValue);
ObservableList<TableColumn<Customer, ?>> tblVwColumns = tblVw.getColumns();
tblVwColumns.add(usernameColumn);
tblVwColumns.add(passwordColumn);
tblVwColumns.add(pointsColumn);
BorderPane root = new BorderPane(tblVw);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
abstract class User {
private String username;
private String password;
public User(String username, String password){
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
class Customer extends User {
private int points;
public Customer(String username, String password, int points){
super(username,password);
this.points = points;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
}
The Callback
in the above code is implemented by a lambda expression since interface Callback
contains a single, abstract method named call
which takes a single parameter and returns a value. Callback
is a generic interface. In the above code, the actual type of the parameter to method call
is TableColumn.CellDataFeatures<Customer, String>
and the type of the returned value is ObservableValue<String>. The JavaFX infrastructure will call your method and pass it the appropriate argument. You need to extract the relevant value from the supplied method argument and return that value as an ObservableValue
. Since the members of your Customer
class are not ObservableValue
s, you need to create one. Hence, in the above code, I return SimpleStringProperty, which is a concrete (i.e. not abstract) class that implements interface ObservableValue
, as the cellValueFactory property for the usernameColumn
and passwordColumn
. Similarly, I return SimpleIntegerProperty
for pointsColumn
.
In the above code, I also create a sample Customer
and add it to the TableView
.
This is how the GUI looks when I run the above code.