Reputation: 5874
Is it possible to have a TableView that is able to maintain different kinds of objects during runtime, but only objects of one kind at a time?
The specific case I am facing is a TableView that I want to use to display results of searches. These searches may produce different "objects" as outcomes, let's say the obligatory Person
and Address
. When the user searches for either, the outcome would be a set of either Person
or Address
.
After a search the table would be accordingly changed (getItems().clear();
and getColumns().clear();
) however I am already stuck at implementing the filling.
I got the TableView declared as TableView<?> searchResults
that is initialized with FXML. Now I tried to add a new TableColumn<Person, String>
to the table and faced an error:
'add(javafx.scene.control.TableColumn<capture<?>,?>)' in 'java.util.List' cannot be applied to '(javafx.scene.control.TableColumn<de.wolfsburg.stadt.beurteilungFX.controllers.tabletypes.CheckNote,java.lang.String>)'
So this does not appear to be working clearly.
As the classes I got are both implementing the same Interface I also tried declaring the TableView as TableView<? extends MyInterface>
and TableView<MyInterface>
with no success in either case.
Eventhough they implement the same Interface the classes differ in number of fields and name of fields.
So the question again: Can one have a TableView that supports multiple objects of the same class and multiple classes?
Note: I found this question during research but seems to be a question asking about different classes at the same time whereas mine asks for objects of the same class at first and change of class later.
Sure an alternative would be having two TableView
s at the same time and hiding one or the other. But this would consume a lot of memory in bigger usecases where 10+ different classes might need to be supported.
Upvotes: 0
Views: 1856
Reputation: 209225
You can do this easily using the interface, as shown below:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class TableViewViaInterface extends Application {
private TableView<TableEntry> table ;
@Override
public void start(Stage primaryStage) {
table = new TableView<>();
BorderPane root = new BorderPane(table);
Button showPersonTable = new Button("Person table");
showPersonTable.setOnAction(e -> showPersonTable());
Button showAddressTable = new Button("Address table");
showAddressTable.setOnAction(e -> showAddressTable());
HBox buttons = new HBox(5, showPersonTable, showAddressTable);
buttons.setAlignment(Pos.CENTER);
buttons.setPadding(new Insets(5));
root.setBottom(buttons);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private void showPersonTable() {
table.getColumns().clear();
TableColumn<TableEntry, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));
table.getColumns().add(firstNameCol);
TableColumn<TableEntry, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));
table.getColumns().add(lastNameCol);
// populate table...
}
private void showAddressTable() {
table.getColumns().clear();
TableColumn<TableEntry, String> streetCol = new TableColumn<>("Street");
streetCol.setCellValueFactory(new PropertyValueFactory<>("street"));
table.getColumns().add(streetCol);
TableColumn<TableEntry, String> cityCol = new TableColumn<>("City");
cityCol.setCellValueFactory(new PropertyValueFactory<>("city"));
table.getColumns().add(cityCol);
// populate table...
}
public interface TableEntry {}
public class Person implements TableEntry {
private final StringProperty firstName = new SimpleStringProperty();
private final StringProperty lastName = new SimpleStringProperty();
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final java.lang.String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final java.lang.String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final java.lang.String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final java.lang.String lastName) {
this.lastNameProperty().set(lastName);
}
}
public class Address implements TableEntry {
private final StringProperty street = new SimpleStringProperty();
private final StringProperty city = new SimpleStringProperty();
public final StringProperty streetProperty() {
return this.street;
}
public final java.lang.String getStreet() {
return this.streetProperty().get();
}
public final void setStreet(final java.lang.String street) {
this.streetProperty().set(street);
}
public final StringProperty cityProperty() {
return this.city;
}
public final java.lang.String getCity() {
return this.cityProperty().get();
}
public final void setCity(final java.lang.String city) {
this.cityProperty().set(city);
}
}
public static void main(String[] args) {
launch(args);
}
}
Though I would recommend replacing the table entirely when you want to switch tables:
public class TableViewViaInterface extends Application {
private BorderPane root ;
private TableView<? extends TableEntry> table ;
@Override
public void start(Stage primaryStage) {
root = new BorderPane();
Button showPersonTable = new Button("Person table");
showPersonTable.setOnAction(e -> showPersonTable());
Button showAddressTable = new Button("Address table");
showAddressTable.setOnAction(e -> showAddressTable());
HBox buttons = new HBox(5, showPersonTable, showAddressTable);
buttons.setAlignment(Pos.CENTER);
buttons.setPadding(new Insets(5));
root.setBottom(buttons);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private void showPersonTable() {
TableView<Person> personTable = new TableView<>();
personTable.getColumns().clear();
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
personTable.getColumns().add(firstNameCol);
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
personTable.getColumns().add(lastNameCol);
// populate table...
this.table = personTable ;
root.setCenter(personTable);
}
private void showAddressTable() {
TableView<Address> addressTable = new TableView<>();
addressTable.getColumns().clear();
TableColumn<Address, String> streetCol = new TableColumn<>("Street");
streetCol.setCellValueFactory(cellData -> cellData.getValue().streetProperty());
addressTable.getColumns().add(streetCol);
TableColumn<Address, String> cityCol = new TableColumn<>("City");
cityCol.setCellValueFactory(cellData -> cellData.getValue().cityProperty());
addressTable.getColumns().add(cityCol);
// populate table...
this.table = addressTable ;
root.setCenter(addressTable);
}
// interface and classes as above...
}
Note that when you switch tables, the previous table and all its data become eligible for garbage collection, as there are no references to the old table retained.
Upvotes: 1