4

I'm new. Let's say I want to create a TableView dynamically based on someString with a 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 the 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;
    // ...........
}

I need to create TableViews of various objects with one function. Is it possible somehow?

6
  • 1
    Your model classes expose JavaFX properties, so they seem designed to be used with something like a TableView. Given that, why do you need to create the table columns dynamically based on the query? Or are you trying to generate a TableView from any arbitrary SQL query? In which case, why have the specialized model classes? Commented Apr 13 at 5:45
  • I agree with Slaw. Why do you want a single TableView to handle multiple data types? Why not create a TableView<Student>, a TableView<Schedule>, and so on? Commented Apr 13 at 14:59
  • That's what Im trying to do. To create multiple TableViews with given Classes from SQL query. Specified tables were there just for a basic example. What if I have a million tables in database, do I really have to create TableView<Something> for every Object in db with all of their properties manually? Commented Apr 13 at 18:02
  • For now I think what I'm trying to do is impossible. Either I get any tables as TableView<String> and then create new Objects based on data I've got, or simply create models for every table and related TableView<Model> for every single one of them manually. Commented Apr 13 at 18:24
  • 1
    Yes, you probably would need to have code for creating a million different TableViews in that case. If one did try to automate the construction of TableViews based on database columns, one might be able to do it, but they would look pretty bad, and they certainly would not approach the quality expected of a professional application for end users. It is always worth the effort to make the separate TableViews. Commented Apr 13 at 19:42

1 Answer 1

4

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.

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

Comments

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.