Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FXML, JavaFX 8, TableView: Make a delete button in each row and delete the row accordingly

Tags:

fxml

javafx-8

I am working on a TableView (FXML) where I want to have all the rows accompanied with a delete button at the last column.

Here's a video that shows what I mean: YouTube Delete Button in TableView

Here's what I have in my main controller class:

public Button del() {
    Button del = new Button();
    del.setText("X");
    del.setPrefWidth(30);
    del.setOnAction(new EventHandler<ActionEvent>() {
        public void handle(ActionEvent event) {
            int i = index.get();
            if(i > -1) {
                goals.remove(i);
                list.getSelectionModel().clearSelection();
            }
        }
    });
    return del;
}

private SimpleIntegerProperty index = new SimpleIntegerProperty();

@Override
public void initialize(URL location, ResourceBundle resources){
    //DateFormat df = new SimpleDateFormat("dd MMM yyyy");
    sdate.setValue(LocalDate.now());
    edate.setValue(LocalDate.now());

    seq.setCellValueFactory(new PropertyValueFactory<Goals, Integer>("id"));
    gol.setCellValueFactory(new PropertyValueFactory<Goals, String>("goal"));
    sdt.setCellValueFactory(new PropertyValueFactory<Goals, Date>("sdte"));
    edt.setCellValueFactory(new PropertyValueFactory<Goals, Date>("edte"));
    prog.setCellValueFactory(new PropertyValueFactory<Goals, Integer>("pb"));
    del.setCellValueFactory(new PropertyValueFactory<Goals, Button>("x"));

    list.setItems(goals);
    list.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Object>() {
        @Override
        public void changed(ObservableValue<?> observable,
                Object oldValue, Object newValue) {
            index.set(goals.indexOf(newValue));
            System.out.println("Index is: "+goals.indexOf(newValue));
        }

    });
}

Each time I launch the application, I will try to click the delete button from random rows but it always delete the first row. I guess the addListener method I use for list is not properly implemented and indexOf(newValue) is always 0 at every initialisation.

However, it will work if I click a row first and then click the delete button. But this is not what I want. I want users to be able to delete any row if they press the delete button without selecting the row.

Appreciate your help guys!

like image 578
Kevin Mugianto Avatar asked Aug 29 '15 02:08

Kevin Mugianto


People also ask

How do I delete a row from a table in JavaFX?

forEach(row -> table. getItems(). remove(row));

How to select a row in TableView JavaFX?

It is possible to select rows programmatically in a JavaFX TableView. You do so via the TableViewSelectionModel object's many selection methods. To select a row with a specific index you can use the select(int) method.

How to select multiple rows in TableView in JavaFX?

I would add a multi-select button like android. Click the button the subsequent selections get added (or maybe removed after another click) to a list of selections.

How do I delete a button in JavaFX?

You just need to call projectList. getChildren(). remove(button); in the button's handler method. (As an aside, you should really use setOnAction , not setOnMouseClicked .)

How to get the selected rows of a JavaFX observablelist?

The only trick in this is from a Scala perspective: The JavaFX ObservableList class doesn’t have a foreach method, so you have to do something like getting an iterator from it to determine the TableView rows (items) that have been selected. Also, note that my delete button event handler is triggered because I call setOnAction like this:

Can You double wrap a list in JavaFX 8?

Sorting and filtering has become more convenient in JavaFX 8. But not everything is straight forward: double-wrapping a list, binding a Comparator, and creating a lambda expression inside another lambda expression are things that are not all too common. We were unable to load Disqus.

How do I sort a filtered list in a Tableview?

Wrap the FilteredList in a SortedList FilteredList is unmodifiable, so it cannot be sorted. We need to also wrap it in SortedList for this purpose. 4. Bind the SortedList comparator to the TableView comparator A click on the column header changes the sorting of the TableView.


1 Answers

You need a custom cell factory defined for the column containing the delete button.

TableColumn<Person, Person> unfriendCol = new TableColumn<>("Anti-social");
unfriendCol.setCellValueFactory(
    param -> new ReadOnlyObjectWrapper<>(param.getValue())
);
unfriendCol.setCellFactory(param -> new TableCell<Person, Person>() {
    private final Button deleteButton = new Button("Unfriend");

    @Override
    protected void updateItem(Person person, boolean empty) {
        super.updateItem(person, empty);

        if (person == null) {
            setGraphic(null);
            return;
        }

        setGraphic(deleteButton);
        deleteButton.setOnAction(
            event -> getTableView().getItems().remove(person)
        );
    }
});

Here is a sample app. It doesn't use FXML, but you could adapt it to work with FXML very easily. Just click on an "Unfriend" button in the "Anti-social" column to delete a friend. Do it a lot and you will soon run out of friends.

anti-social

import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class GestureEvents extends Application {
    private TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data =
        FXCollections.observableArrayList(
            new Person("Jacob", "Smith"),
            new Person("Isabella", "Johnson"),
            new Person("Ethan", "Williams"),
            new Person("Emma", "Jones"),
            new Person("Michael", "Brown")
        );

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        final Label label = new Label("Friends");
        label.setFont(new Font("Arial", 20));

        final Label actionTaken = new Label();

        TableColumn<Person, Person> unfriendCol = new TableColumn<>("Anti-social");
        unfriendCol.setMinWidth(40);
        unfriendCol.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue()));
        unfriendCol.setCellFactory(param -> new TableCell<Person, Person>() {
            private final Button deleteButton = new Button("Unfriend");

            @Override
            protected void updateItem(Person person, boolean empty) {
                super.updateItem(person, empty);

                if (person == null) {
                    setGraphic(null);
                    return;
                }

                setGraphic(deleteButton);
                deleteButton.setOnAction(event -> data.remove(person));
            }
        });

        TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(
                new PropertyValueFactory<>("firstName"));

        TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
                new PropertyValueFactory<>("lastName"));

        table.setItems(data);
        table.getColumns().addAll(unfriendCol, firstNameCol, lastNameCol);
        table.setPrefHeight(250);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 10, 10, 10));
        vbox.getChildren().addAll(label, table, actionTaken);
        VBox.setVgrow(table, Priority.ALWAYS);

        stage.setScene(new Scene(vbox));
        stage.show();
    }

    public static class Person {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;

        private Person(String fName, String lName) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String fName) {
            firstName.set(fName);
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String fName) {
            lastName.set(fName);
        }
    }
}
like image 176
jewelsea Avatar answered Sep 18 '22 14:09

jewelsea