Your question is mixing up two concepts here: javafx.scene.control.TableView
on one hand, and SQL/ORM on the other hand. Let's forget about SQL queries and such as I think your concern is mostly on TableView
.
TableView
must be populated with a List
. The inner type of this list must match the TableView's generic type. So for instance TableView<Person>
will be populated with a List<Person>
.
Other than that, the actual type of the objects representing rows can be anything. It doesn't even have to contain the data itself, or it can very-well be, for instance, a Map<String, Object>
. In this case, you will map the keys of the row to each column by defining a CellValueFactory
for each column, that will return the entry value for your chosen key.
Then you can convert this value to a String
and/or a Node
by defining a CellFactory
for the column.
Objects with JavaFX properties can be mapped more easily, as there exists pre-made PropertyValueFactory
that will require only the property name. But they're not the only way to go.
Example using a Map<String, Object>
for each row:
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class App extends Application {
private TableView<Map<String, Object>> tableView;
private TableColumn<Map<String, Object>, String> nameCol;
private TableColumn<Map<String, Object>, Integer> ageCol;
private Stage stage;
@Override
public void start(Stage stage) {
this.stage = stage;
//Insert a TableView into scene
this.tableView = new TableView<>();
this.nameCol = new TableColumn<>("Name");
this.nameCol.setPrefWidth(250);
ageCol = new TableColumn<>("Age");
tableView.getColumns().add(nameCol);
tableView.getColumns().add(ageCol);
nameCol.setCellValueFactory(param -> {
Map<String, Object> v = param.getValue();
return new SimpleStringProperty(v == null ? null : (String) v.get("name"));
});
ageCol.setCellValueFactory(param -> {
Map<String, Object> v = param.getValue();
return new SimpleObjectProperty<Integer>(v == null ? null : (Integer) v.get("age"));
});
ageCol.setCellFactory(param -> {
return new TableCell<>() {
@Override
public void updateItem(Integer item, boolean empty) {
if (empty || item == null)
super.setText("");
else
super.setText(NumberFormat.getIntegerInstance().format(item));
//Could also call setGraphic(Node)
}
};
});
final Scene scene = new Scene(new BorderPane(tableView), 640, 480);
stage.setScene(scene);
stage.setOnShown(event -> stageReady()); //Continue when stage is rendered
stage.show();
}
private void stageReady() {
//Generate data
List<Map<String, Object>> data = new ArrayList<>();
Map<String, Object> obj1 = new HashMap<>();
obj1.put("name", "Name of Object 1");
obj1.put("age", 42);
data.add(obj1);
Map<String, Object> obj2 = new HashMap<>();
obj2.put("name", "OBJECT 2");
obj2.put("age", 53);
data.add(obj2);
//Show data
tableView.getItems().setAll(data);
}
public static void main(String[] args) {
launch();
}
}
ageCol.setCellFactory
is only here for demonstration. If I had not set it, then the Integer
cells would have been rendered calling Integer.toString()
for the cells text
property.