0

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?

4
  • Have you tried to do this with a BorderPane and VBox, putting all inside the layout (TableView, Buttons), following the indexing or the default row number and the state in which the row is (empty / Filled) ? (it's just a proposal) ! Commented Dec 25, 2016 at 20:08
  • Do you want a button in one of the column cells? Commented Dec 25, 2016 at 20:09
  • @BoHalim that's basically not the solution I'm looking for. I could do it that way, but it's not the thing I want Commented Dec 25, 2016 at 20:10
  • @LukeMelaia that's not the point of the question. I do, but I already have that running. I want a "Title" with a "Menu" for the whole TableView, basically Commented Dec 25, 2016 at 20:10

1 Answer 1

1

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);
    }
}

Result:

enter image description here

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.