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

[TableView] selectedItem and selectedIndex inconsistent

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P4
    • Resolution: Fixed
    • Affects Version/s: 8u20
    • Fix Version/s: 8u40
    • Component/s: javafx
    • Environment:

      Fedora release 20 (Heisenbug)
      java version "1.8.0_20"
      Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
      Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)

      Description

      When Ctrl+Clicking a selected item in a table, the item retains a blue border (probably to indicate it is the anchor).
      However selectedIndex will remain the value it was, while selectedItem will become null.

      The following example demonstrates the problem by displaying two bound checkboxes together with a table. Both checkboxes should always have the same state (since selectedIndex < 0 should be equivalent to selectedItem == null), but they are not, if a selected item is Ctrl-clicked.

      import javafx.application.Application;
      import javafx.beans.property.SimpleStringProperty;
      import javafx.beans.property.StringProperty;
      import javafx.beans.value.ObservableValue;
      import javafx.collections.FXCollections;
      import javafx.collections.ObservableList;
      import javafx.scene.Scene;
      import javafx.scene.control.CheckBox;
      import javafx.scene.control.TableColumn;
      import javafx.scene.control.TableView;
      import javafx.scene.control.cell.PropertyValueFactory;
      import javafx.scene.layout.GridPane;
      import javafx.stage.Stage;

      public class TableViewHasSelection extends Application {

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

          public TableViewHasSelection() {
          }

          @Override
          public void start(Stage primaryStage) throws Exception {
           GridPane grid = new GridPane();
          
          
              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().selectedIndexProperty().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> { selectionChanged(); });
              table.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends Person> observable, Person oldValue, Person newValue) -> { selectionChanged(); });
              addPersons();
              grid.add(table, 0, 1, 3, 1);
              
              CheckBox cb1 = new CheckBox("selectedIndex < 0");
              cb1.selectedProperty().bind(table.getSelectionModel().selectedIndexProperty().lessThan(0));
              grid.add(cb1, 0, 0);
              
              CheckBox cb2 = new CheckBox("selectedItem.isNull");
              cb2.selectedProperty().bind(table.getSelectionModel().selectedItemProperty().isNull());
              grid.add(cb2, 1, 0);
              
              
              Scene scene = new Scene(grid, 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 selectionChanged() {
           System.out.println(
           "isEmpty: " + table.getSelectionModel().isEmpty()
           + ", vs. selectedIndex: " + table.getSelectionModel().getSelectedIndex()
           + " vs. item.isNull: " + (table.getSelectionModel().getSelectedItem() == null)
           );
          }

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

        Attachments

          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: