controlsfx / controlsfx/controlsfx
GridView does not unregister listeners of GridViewSkin if items-list is changed with setItems()
- Dominant language
- Java
- Stars
- 1.7k
- Forks
- 300
- Avg merge
- 16d 17h
- Merged PRs (30d)
- 1
Description
**[Original report](https://bitbucket.org/controlsfx/controlsfx/issue/874) by acuriousbison NA (Bitbucket: [acuriousbison](https://bitbucket.org/acuriousbison), GitHub: Unknown).**
----------------------------------------
If the items-list of a GridView is changed with setItems() the GridViewSkin does not remove its ListChangeListener("gridViewItemsListener") from the old items when updateGridViewItems() is called. If the old items-list changes afterwards, the listener is still triggered and calls updateRowCount() even though the old items-list is no longer associated with the GridView.
Sample code:
```
#!java
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.controlsfx.control.GridView;
public class GridViewListenerIssue extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList listA = FXCollections.observableArrayList();
listA.add("foo");
ObservableList listB = FXCollections.observableArrayList();
listB.add("bar");
GridView grid = new GridView<>();
grid.setItems(listA);
VBox root = new VBox(grid);
root.setPrefSize(400, 400);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
grid.setItems(listB);
// Changes to the old list will still trigger the GridViewSkin.gridViewItemsListener
listA.add("foo");
}
}
```
Looking at ListViewSkin, I suspect that the listener should be removed from the old items-list when updateGridViewItems() is called:
```
#!java
public class GridViewSkin {
public void updateGridViewItems() {
if (getSkinnable().getItems() != null) {
getSkinnable().getItems().removeListener(weakGridViewItemsListener);
}
if (getSkinnable().getItems() != null) {
getSkinnable().getItems().addListener(weakGridViewItemsListener);
}
updateRowCount();
flow.recreateCells();
getSkinnable().requestLayout();
}
}
public class ListViewSkin {
public void updateListViewItems() {
if (listViewItems != null) {
listViewItems.removeListener(weakListViewItemsListener);
}
this.listViewItems = getSkinnable().getItems();
if (listViewItems != null) {
listViewItems.addListener(weakListViewItemsListener);
}
rowCountDirty = true;
getSkinnable().requestLayout();
}
}
```
The described issue can also cause IndexOutOfBoundsException when using a FilteredList as items: The old FilteredList triggers the listener in GridViewSkin and when the GridCells try to update their index/item the indices of the (not yet changed) new FilteredList are being used.
Sample Code:
```
#!java
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.controlsfx.control.GridView;
public class GridViewListenerIssue2 extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList source = FXCollections.observableArrayList();
source.add("bar");
source.add("bar");
source.add("foo");
source.add("foo");
FilteredList filteredListFoo = source.filtered(s -> s.startsWith("foo"));
FilteredList filteredListBar = source.filtered(s -> s.startsWith("bar"));
GridView grid = new GridView<>();
grid.setItems(filteredListFoo);
VBox root = new VBox(grid);
root.setPrefSize(400, 400);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
grid.setItems(filteredListBar);
source.setAll("bar");
}
}
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.