I'm new. Let's say I want to create a TableView dinamycally based on someString with query like this
TableView<???> table = new TableView<>();
ResultSet rs = statement.executeQuery("SELECT * FROM %s".formatted(someString));
So I will have various tables with various object types and therefore properties and columns
ResultSetMetaData meta = rs.getMetaData();
for (int i = 0; i < meta.getColumnCount(); i++) {
TableColumn<???, String> column = new TableColumn<>(meta.getColumnLabel(i + 1));
table.getColumns().add(column);
column.setCellValueFactory(data -> data.getValue().???dynamicPropertyBasedOn[i]);
}
while (rs.next()) {........}
How do I setCellValueFactory() not knowing Object type and exact number of columns beforehand?
I have models for my database tables, for basic example
Student.java
public class Student {
private final StringProperty lastName;
private final StringProperty firstName;
private final IntegerProperty age;
...........
}
Schedule.java
public class Schedule {
private final ObjectProperty<LocalDate> date;
private final BooleanProperty completed;
...........
}
So I need to create TableViews of various Objects with one function.. Is it possible anyhow?
If you're creating a GUI with the purpose of displaying specific, known data types then I recommend you create the tables in the usual way. That means create a model class for the data that exposes JavaFX properties and write the code that configures the table view to work with that model class. At most, you could create a framework that generates a table view based on the model class. How complex the framework is depends on your exact needs. In general though, such a framework would likely rely on reflection and custom annotations (for configuration).
However, if you're creating a GUI that is supposed to work with an arbitrary database that isn't known at build time, then relying on ResultSetMetaData
is a good approach. But in this case you won't have specialized model classes. Instead, you'd use a single general model class, if not simply just an array or list of objects. At the most basic level, it could look something like this:
public TableView<?> toTableView(ResultSet queryResult) throws SQLException {
var table = new TableView<Object[]>();
var metadata = queryResult.getMetaData();
int columnCount = metadata.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
final int idx = i;
var column = new TableColumn<Object[], Object>(metadata.getColumnLabel(idx));
column.setCellValueFactory(data -> new SimpleObjectProperty<>(data.getValue()[idx - 1]));
table.getColumns().add(column);
}
var items = table.getItems();
while (queryResult.next()) {
var row = new Object[columnCount];
for (int i = 1; i <= columnCount; i++) {
row[i - 1] = queryResult.getObject(i);
}
items.add(row);
}
return table;
}
That will display every column value using its Object::toString
method. If you want to get more detailed, then you need to make use of methods like getColumnType
, getScale
, getPrecision
, and isCurrency
from ResultSetMetaData
. You would set the cell factories (to customize the display) based on the results of those methods.