JavaFX 8, ListView with Checkboxes scrollpane issu

2019-03-04 02:23发布

I am using cell factory for listview with checkboxes like:

  listView.setCellFactory(CheckBoxListCell.forListView(new Callback < Bean, ObservableValue < Boolean >> () {
  @Override
  public ObservableValue < Boolean > call(Bean item) {
    BooleanProperty observable = new SimpleBooleanProperty();
    observable.addListener((obs, wasSelected, isNowSelected) -> {
      if (isNowSelected) {
        if (!beanChoices.contains(item.toString())) {
          beanChoices.add(item.toString());
          observable.setValue(true);
          //listView.scrollTo(listView.getItems().size() - 1);
        }
      } else if (wasSelected) {
        if (beanChoices.contains(item.toString())) {
          beanChoices.remove(item.toString());
          observable.setValue(false);
        }
      }
    });
  /* [Code] which compares values with bean item string value and select observable to true for that for edit mode
    but here the observer not called for beanItem that are under scrollpane of listview. But on scroll it gets called. */
    return observable;
  }
}));

It works fine but not for all cases. Case: When I have say more than 10 entries, the scrollpane comes. Say I have beanChoices to be checked that are at 8 or 9 index(you have to scroll to view them).
The listener is not called for the items not visible(that are under scrollpane).
On Debug, I found that listener is called when I scroll down.

Problem: when I get checked values from beanChoices for above case, it return empty.
Detail: I have beanChoices which I need to make checked for listview items (edit mode). When I update without changing anything. (Assume that the value which is under the scrollpane of listview will be selected and added to beanChoices)

1条回答
太酷不给撩
2楼-- · 2019-03-04 02:49

The Callback is used to retrieve the property for the checked state when the item is associated with a cell. The item may be removed from a cell and put in a new one at any time. This is how ListView (and similar controls like TableView) works. CheckBoxListCell simply gets the checked state property every time a new item is associated with the cell.

The return value is also used to set the initial state of the CheckBox. Since you do not properly initialize the property with the correct value the initial state is not preserved.

Also note that it makes little sense to update the value of the property to the new value in the change listener. It happens anyway.

Since BooleanProperty is a wrapper for primitive boolean the possible values are true and false; the ChangeListener only gets called when !Objects.equals(oldValue, newValue) you can be sure that isNowSelected = !wasSelected.

Of course you also need to return the value:

@Override
public ObservableValue < Boolean > call(Bean item) {
    final String value = item.toString();
    BooleanProperty observable = new SimpleBooleanProperty(beanChoices.contains(value));
    observable.addListener((obs, wasSelected, isNowSelected) -> {
        if (isNowSelected) {
            beanChoices.add(value);
        } else {
            beanChoices.remove(value);
        }
    });
    return observable;
}

I also recommend using a Collection of Beans instead of relying on the string representation of the objects. toString many not produce unique results and Beans.equals would be the better choice to compare the objects.

查看更多
登录 后发表回答