My problem is that my ListView
(checkbox list view) does not update when the ObservableList
changes.
This problem only happens when I use a dated version of JavaFX and a dated JRE (jre6 and jfx2.2). When I use jre8 and the JavaFX that it includes, the problem is gone and the list refreshes nicely.
Working source code on latest JavaFX described above:
The list:
public ObservableList<TestCaseCheckboxModel> TestCases;
//Constructor
public SessionTestCaseModel() {
TestCases = FXCollections.observableArrayList(new Callback<TestCaseCheckboxModel, Observable[]>(){
@Override
public Observable[] call(TestCaseCheckboxModel model) {
return new Observable[]{model.TestCaseName, model.TestCaseStatus, model.TestCaseSelected};//selected might not be needed since it's bound to the listview anyways
}
});
}
The Class the list uses has these properties:
public StringProperty TestCaseName = new SimpleStringProperty();
public IntegerProperty TestCaseStatus = new SimpleIntegerProperty();
public BooleanProperty TestCaseSelected = new SimpleBooleanProperty();
The List is populated externally.
The ListView
:
@FXML
private ListView<TestCaseCheckboxModel> testcaseListView;
//bind the checkbox select to the model property
testcaseListView.setCellFactory(CheckBoxListCell.forListView(new Callback<TestCaseCheckboxModel, ObservableValue<Boolean>>() {
@Override
public ObservableValue<Boolean> call(TestCaseCheckboxModel item) {
return item.TestCaseSelected;
}
}));
//initiate the checkbox list view with the model items
testcaseListView.setItems(getModel().TestCases);
The problem is that when I change the List items, the ListView won't change on the old JavaFX version.
It might be worth mentioning that after I add/remove an item from the list, the items that are in the list update (like they are supposed to when they themselves change). But, as far as I know, calling the add
function of the list triggers the ListView
update, no matter what.
On the other hand, when the item properties change, this will trigger, with both the old and new JavaFX versions, so the Callback
extractor is working as intended:
getModel().TestCases.addListener(new ListChangeListener<TestCaseCheckboxModel>(){
@Override
public void onChanged(Change change) {
System.out.println(change);
}
});
Is there a known workaround for this?
Thank you for your help.
Answering my own question with help from this thread: https://stackoverflow.com/a/25962110/4073727
I implemented a custom ListViewSkin
that is capable of updating the ListView "from the inside":
public class UpdateableListViewSkin<T> extends ListViewSkin<T> {
public UpdateableListViewSkin(ListView<T> arg0) {
super(arg0);
}
public void refresh() {
super.flow.recreateCells();
}
}
Then I add the ObservableList
to the ListView
, instantiate the Skin
and set it to the ListView
.
//initiate the checkbox list view with the model items
testcaseListView.setItems(getModel().TestCases);
UpdateableListViewSkin<TestCaseCheckboxModel> skin = new UpdateableListViewSkin<TestCaseCheckboxModel>(testcaseListView);
testcaseListView.setSkin(skin);
The key is that you need to add a working onChange
listener to the ObservableList
, which will trigger the Skin
's .refresh()
method. I did this right after I set the Skin
to the ListView
:
getModel().TestCases.addListener(new ListChangeListener<TestCaseCheckboxModel>(){
@SuppressWarnings("unchecked")
@Override
public void onChanged(Change change) {
((UpdateableListViewSkin<TestCaseCheckboxModel>)testcaseListView.getSkin()).refresh();
}
});
This workaround triggers the ListView
's update functions, like it does on the new version of JavaFX.