There's no particularly elegant way to do this that I'm aware of (other than creating structures that are very likely overkill for the task at hand), and whatever you do, at some point you have to type in the properties and associate them with each column. I really don't recommend subclassing TableColumn
or generating wrapper classes implementing custom interfaces defining functionality already in the standard API.
I usually just save excess code by writing a convenience method and invoking it. The basic idea is
private void configColumn(TableColumn<?,?> column, String property) {
column.setCellValueFactory(new PropertyValueFactory<>(property));
}
and then your initialization becomes
configColumn(date, "date");
configColumn(site_address, "site_address");
// etc ...
The productivity trick is to initially name the column something very short:
private void c(TableColumn<?,?> column, String property) {
column.setCellValueFactory(new PropertyValueFactory<>(property));
}
and now you have far less to type:
c(date, "date");
c(site_address, "site_address");
// ...
and then once you've put all that in, use your IDE to rename the method to something more readable (I use Eclipse, so you click on the method name in the definition, choose "Refactor" and "Rename" and then type the new name in. I assume NetBeans has similar functionality.) Don't omit this part, as otherwise your code will be very hard to read when you come back to it.
If you really want to do this with some kind of loop, then assuming your TableColumn
s all have the same names as the corresponding properties, you can use reflection, but again I think you lose more in readability than you gain with conciseness:
public void initialize() throws Exception {
List<String> colNames = Arrays.asList("date", "site_address", "bill_no" /*, ...*/);
for (String colName : colNames) {
Field f = this.getClass().getDeclaredField(colName);
TableColumn<?,?> column = (TableColumn<?,?>) f.get(this);
column.setCellValueFactory(new PropertyValueFactory(colName));
}
}
Note there's one other way, but (without some fairly ugly wiring) you can only use this trick where you have access to the FXMLLoader
(so you can't do this in the controller, only in the code where you load the FXML file). The FXMLLoader
gives access to a namespace
, which is a map between all the fx:id
attribute values and the objects created in the FXML (note that there are some other key-value pairs in here too, not just the ones defined with fx:id
). So, again assuming all your TableColumn
s have fx:id
attribute values matching the property value, you can do:
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml/file"));
Parent root = loader.load();
Map<String, Object> namespace = loader.getNamespace();
for (String fxid : namespace.keySet()) {
Object value = namespace.get(fxid);
if (value instanceof TableColumn) {
((TableColumn<?,?>)value).setCellValueFactory(new PropertyValueFactory(fxid));
}
}