Reputation: 5647
I have a TableView in my fxml as container for a complex POJO.
I have successfully customized the display to give me a nice Pane for each instance of said complex POJO, but now I want to edit the underlying collection.
For that purpose I could just add a Button in my view with an action-listener and yadda yadda.
But that's a bit incoherent and I'd prefer to have the add-button directly at my TableView. Preferrably in something like a "title bar" on the right side.
I did something similar with a GridPane, but don't want to restructure my code completely so here's a screencap of the effect I'd like to achieve:
The topmost row would be a Table caption, and accordingly styled a bit differently. Am I missing something terribly simple?
Upvotes: 0
Views: 145
Reputation: 6123
This answer is based on this gist:
For the +
button in header you just need to create a TableColumn
and set its graphic to a button.
Button addButton = new Button("+");
TableColumn<Person, Object> buttonColumn = new TableColumn<>();
buttonColumn.setGraphic(addButton);
For -
buttons in every row, you need to customize the updateItem
method of TableCell
class to allow buttons in each row. In order to handle each row's button's action we use a CallBack
:
public class ButtonTableCell<S,T> extends TableCell<S,T> {
private Button button;
public ButtonTableCell(final Callback<Integer, Void> pressedCallback) {
this(pressedCallback, null, null);
}
public ButtonTableCell(final Callback<Integer, Void> pressedCallback, String buttonText, Node buttonGraphic) {
this.button = new Button(buttonText, buttonGraphic);
this.button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
pressedCallback.call(getTableRow().getIndex());
}
});
}
@Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if(empty) {
setGraphic(null);
} else {
setGraphic(button);
button.disableProperty().bind(Bindings.not(
getTableView().editableProperty().and(
getTableColumn().editableProperty()).and(
editableProperty())
));
}
}
}
And then make the buttoned column's CellFactory
to use this modified TableCell
:
public class TableViewWithButtonColumnDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
TableView<Person> tableview = new TableView<>(
FXCollections.observableArrayList(
new Person("Person", "1"),
new Person("Person", "2"),
new Person("Person", "3")));
TableColumn<Person, String> firstNameColumn = new TableColumn<>("First Name");
firstNameColumn.setCellValueFactory(new PropertyValueFactory("firstName"));
TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setCellValueFactory(new PropertyValueFactory("lastName"));
Button addButton = new Button("+");
addButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
tableview.getItems().add(new Person("person", String.valueOf(tableview.getItems().size()+1)));
}
});
TableColumn<Person, Object> buttonColumn = new TableColumn<>();
buttonColumn.setGraphic(addButton);
buttonColumn.setCellFactory(new Callback<TableColumn<Person,Object>, TableCell<Person,Object>>() {
@Override
public TableCell<Person, Object> call(TableColumn<Person, Object> param) {
Callback<Integer, Void> pressedCallback = new Callback<Integer, Void>() {
@Override
public Void call(Integer index) {
Person buttonPressedPerson = tableview.getItems().get(index);
tableview.getItems().remove(buttonPressedPerson);
return null;
}
};
return new ButtonTableCell<>(pressedCallback, "-", null);
}
});
tableview.setEditable(true);
tableview.getColumns().addAll(firstNameColumn, lastNameColumn, buttonColumn);
primaryStage.setScene(new Scene(tableview));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 1