Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8097169

TableView selected items listener reports wrong changes

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: 8u60
    • Fix Version/s: 9
    • Component/s: javafx
    • Environment:

      Fedora release 20 (Heisenbug)
      java version "1.8.0_60-ea"
      Java(TM) SE Runtime Environment (build 1.8.0_60-ea-b10)
      Java HotSpot(TM) 64-Bit Server VM (build 25.60-b10, mixed mode)

      Backports

        Description

        While a lot of things seem to have been fixed in 8u60 I just noticed new weird things with regards to the selected Items of a table. If you run the following program and do nothing (i.e. not select anything at all) I would expect that selectionChanged ist never called (since the selection does not in fact change).

        However the output is:
        Added: [0Doe]
        Reloading
        Removed:[0Doe, 1Doe, 2Doe, 3Doe, 4Doe, 5Doe, 6Doe, 7Doe, 8Doe, 9Doe, 10Doe, 11Doe, 12Doe, 13Doe, 14Doe, 15Doe, 16Doe, 17Doe, 18Doe, 19Doe, 20Doe, 21Doe, 22Doe, 23Doe, 24Doe, 25Doe, 26Doe, 27Doe, 28Doe, 29Doe, 30Doe, 31Doe, 32Doe, 33Doe, 34Doe, 35Doe, 36Doe, 37Doe, 38Doe, 39Doe, 40Doe, 41Doe, 42Doe, 43Doe, 44Doe, 45Doe, 46Doe, 47Doe, 48Doe, 49Doe]
        Added: [0Doe]

        ---- SNIP ---

        import javafx.animation.KeyFrame;
        import javafx.animation.Timeline;
        import javafx.application.Application;
        import javafx.beans.property.SimpleStringProperty;
        import javafx.beans.property.StringProperty;
        import javafx.collections.FXCollections;
        import javafx.collections.ListChangeListener.Change;
        import javafx.collections.ObservableList;
        import javafx.scene.Scene;
        import javafx.scene.control.SelectionMode;
        import javafx.scene.control.TableColumn;
        import javafx.scene.control.TableView;
        import javafx.scene.control.cell.PropertyValueFactory;
        import javafx.stage.Stage;
        import javafx.util.Duration;

        @SuppressWarnings("all")
        public class TableViewSelectionBug extends Application {

            ObservableList<Person> items = FXCollections.observableArrayList();
            TableView<Person> table = new TableView<Person>();
            Timeline reloadTimeline = new Timeline();

            public TableViewSelectionBug() {
            }

            @Override
            public void start(Stage primaryStage) throws Exception {
                table.setItems(items);
                TableColumn<Person, String> firstNameCol = new TableColumn<Person, String>("First Name");
                firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
                TableColumn<Person, String> lastNameCol = new TableColumn<Person, String>("Last Name");
                lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
                table.getColumns().setAll(firstNameCol, lastNameCol);
                table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
                table.getSelectionModel().getSelectedItems().addListener(this::selectionChanged);
                addPersons();

                // reload data in 5 seconds
                reloadTimeline.getKeyFrames().add(new KeyFrame(Duration.seconds(5), "Reload", (ActionEvent) -> {
                    reload();
                }));
                reloadTimeline.play();

                Scene scene = new Scene(table, 400, 400);
                primaryStage.setScene(scene);
                primaryStage.show();
            }

            // simulate server call, usually this would take sort order property into account
            private void addPersons() {
                for (int i = 0; i < 50; i++) {
                    Person p = new Person();
                    int idx = items.size();
                    p.setFirstName(idx + " John");
                    p.setLastName(idx + "Doe");
                    items.add(p);
                }
            }

            private void reload() {
                System.out.println("Reloading");
                table.getSelectionModel().clearSelection();
                items.clear();
                addPersons();
            }

            private void selectionChanged(Change<? extends Person> c) {
                while (c.next()) {
                    if (c.wasRemoved()) {
                        System.out.println("Removed:" + c.getRemoved());
                        // ^^^ will throw Exception in thread "JavaFX Application Thread" java.util.NoSuchElementException, when a column header is clicked
                    }
                    if (c.wasAdded()) {
                     System.out.println("Added: " + c.getAddedSubList());
                    }
                }
            }

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

            public class Person {
                private StringProperty firstName;

                public void setFirstName(String value) {
                    firstNameProperty().set(value);
                }

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

                public StringProperty firstNameProperty() {
                    if (firstName == null)
                        firstName = new SimpleStringProperty(this, "firstName");
                    return firstName;
                }

                private StringProperty lastName;

                public void setLastName(String value) {
                    lastNameProperty().set(value);
                }

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

                public StringProperty lastNameProperty() {
                    if (lastName == null)
                        lastName = new SimpleStringProperty(this, "lastName");
                    return lastName;
                }
                
                @Override
                public String toString() {
                 return getLastName();
                }
            }
        }

          Attachments

            Issue Links

              Activity

                People

                Assignee:
                jgiles Jonathan Giles
                Reporter:
                rlichtenbjfx Robert Lichtenberger (Inactive)
                Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                  Dates

                  Created:
                  Updated:
                  Resolved:
                  Imported: