-
Bug
-
Resolution: Fixed
-
P3
-
8u66
-
x86
-
linux_redhat_6.0
FULL PRODUCT VERSION :
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux knucklepuck 2.6.32-220.el6.x86_64 #1 SMP Tue Dec 6 19:48:22 GMT 2011 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
An ArrayIndexOutOfBoundsException is thrown on the JavaFX Application Thread when a TreeTableView's selection model is updated in response to a TreeItem being expanded.
The TreeTableView is allowing multiple selections, and my application is trying to select all child nodes of a selected TreeItem when that TreeItem is expanded.
There is a FilteredList that was created from the `getSelectedItems()` ObservableList of the TreeTableView's selection model. The exception is thrown when updating this FilteredList; removing the FilteredList prevents this exception from happening.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Select a non-leaf TreeItem that is a child of the root node in the TreeTableView.
2. Rapidly expand/collapse the selected TreeItem by clicking quickly on the expand icon.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The FilteredList should be properly updated with the selected items in the TreeTableView.
ACTUAL -
An ArrayIndexOutOfBoundsException is thrown when expanding/collapsing a selected TreeItem.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at javafx.collections.transformation.FilteredList.addRemove(FilteredList.java:269)
at javafx.collections.transformation.FilteredList.sourceChanged(FilteredList.java:144)
at javafx.collections.transformation.TransformationList.lambda$getListener$15(TransformationList.java:106)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:75)
at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.handleSelectedCellsListChangeEvent(TreeTableView.java:3312)
at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.lambda$new$125(TreeTableView.java:2313)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.transformation.SortedList.sourceChanged(SortedList.java:108)
at javafx.collections.transformation.TransformationList.lambda$getListener$15(TransformationList.java:106)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:102)
at com.sun.javafx.scene.control.SelectedCellsMap.addAll(SelectedCellsMap.java:146)
at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.selectIndices(TreeTableView.java:2832)
at javafx.scene.control.MultipleSelectionModel.selectRange(MultipleSelectionModel.java:176)
at TreeTableViewSample.selectChildrenOfRows(TreeTableViewSample.java:96)
at TreeTableViewSample.lambda$start$1(TreeTableViewSample.java:64)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:176)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:142)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
at javafx.scene.control.TreeTableView.setExpandedItemCount(TreeTableView.java:1088)
at javafx.scene.control.TreeTableView.updateExpandedItemCount(TreeTableView.java:1861)
at javafx.scene.control.TreeTableView.getExpandedItemCount(TreeTableView.java:1092)
at com.sun.javafx.scene.control.behavior.TreeTableCellBehavior.getItemCount(TreeTableCellBehavior.java:72)
at com.sun.javafx.scene.control.behavior.TableCellBehaviorBase.doSelect(TableCellBehaviorBase.java:110)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mouseReleased(CellBehaviorBase.java:159)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:388)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
at java.lang.Thread.run(Thread.java:745)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.*;
import javafx.application.Application;
import javafx.collections.*;
import javafx.collections.transformation.*;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.TreeTableColumn.CellDataFeatures;
import javafx.stage.Stage;
public class TreeTableViewSample extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
final TreeItem<String> childNode1 = new TreeItem<>("Child Node 1");
childNode1.getChildren().addAll(
new TreeItem<String>("Node 1-1"),
new TreeItem<String>("Node 1-2")
);
final TreeItem<String> root = new TreeItem<>("Root node");
root.setExpanded(true);
root.getChildren().add(childNode1);
TreeTableColumn<String,String> column = new TreeTableColumn<>("Column");
column.setPrefWidth(190);
column.setCellValueFactory((CellDataFeatures<String, String> p) ->
new ReadOnlyStringWrapper(p.getValue().getValue()));
final TreeTableView<String> treeTableView = new TreeTableView<>(root);
treeTableView.getColumns().add(column);
treeTableView.setPrefWidth(200);
treeTableView.setShowRoot(true);
treeTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
// Select all children of expanded node.
treeTableView.expandedItemCountProperty().addListener((observable, oldCount, newCount) -> {
if (newCount.intValue() > oldCount.intValue()) {
selectChildrenOfRows(treeTableView, treeTableView.getSelectionModel().getSelectedIndices());
}
});
filteredList = treeTableView.getSelectionModel().getSelectedItems().filtered(Objects::nonNull);
filteredList.addListener((ListChangeListener.Change<? extends TreeItem<String>> change) -> {
System.out.printf("Change: %s\n", change);
});
final Scene scene = new Scene(new Group(), 200, 400);
Group sceneRoot = (Group)scene.getRoot();
sceneRoot.getChildren().add(treeTableView);
stage.setTitle("Tree Table View Samples");
stage.setScene(scene);
stage.show();
}
private FilteredList<TreeItem<String>> filteredList;
private void selectChildrenOfRows(TreeTableView<String> table, Collection<Integer> selectedRows) {
for (int index: selectedRows) {
TreeItem<String> item = table.getTreeItem(index);
if (item != null && item.isExpanded() && !item.getChildren().isEmpty()) {
int startIndex = index + 1;
int maxCount = startIndex + item.getChildren().size();
table.getSelectionModel().selectRange(startIndex, maxCount);
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't create a FilteredList from the selectedItems property of a TreeTableView.
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux knucklepuck 2.6.32-220.el6.x86_64 #1 SMP Tue Dec 6 19:48:22 GMT 2011 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
An ArrayIndexOutOfBoundsException is thrown on the JavaFX Application Thread when a TreeTableView's selection model is updated in response to a TreeItem being expanded.
The TreeTableView is allowing multiple selections, and my application is trying to select all child nodes of a selected TreeItem when that TreeItem is expanded.
There is a FilteredList that was created from the `getSelectedItems()` ObservableList of the TreeTableView's selection model. The exception is thrown when updating this FilteredList; removing the FilteredList prevents this exception from happening.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Select a non-leaf TreeItem that is a child of the root node in the TreeTableView.
2. Rapidly expand/collapse the selected TreeItem by clicking quickly on the expand icon.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The FilteredList should be properly updated with the selected items in the TreeTableView.
ACTUAL -
An ArrayIndexOutOfBoundsException is thrown when expanding/collapsing a selected TreeItem.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at javafx.collections.transformation.FilteredList.addRemove(FilteredList.java:269)
at javafx.collections.transformation.FilteredList.sourceChanged(FilteredList.java:144)
at javafx.collections.transformation.TransformationList.lambda$getListener$15(TransformationList.java:106)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:75)
at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.handleSelectedCellsListChangeEvent(TreeTableView.java:3312)
at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.lambda$new$125(TreeTableView.java:2313)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.transformation.SortedList.sourceChanged(SortedList.java:108)
at javafx.collections.transformation.TransformationList.lambda$getListener$15(TransformationList.java:106)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:102)
at com.sun.javafx.scene.control.SelectedCellsMap.addAll(SelectedCellsMap.java:146)
at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.selectIndices(TreeTableView.java:2832)
at javafx.scene.control.MultipleSelectionModel.selectRange(MultipleSelectionModel.java:176)
at TreeTableViewSample.selectChildrenOfRows(TreeTableViewSample.java:96)
at TreeTableViewSample.lambda$start$1(TreeTableViewSample.java:64)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:176)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:142)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
at javafx.scene.control.TreeTableView.setExpandedItemCount(TreeTableView.java:1088)
at javafx.scene.control.TreeTableView.updateExpandedItemCount(TreeTableView.java:1861)
at javafx.scene.control.TreeTableView.getExpandedItemCount(TreeTableView.java:1092)
at com.sun.javafx.scene.control.behavior.TreeTableCellBehavior.getItemCount(TreeTableCellBehavior.java:72)
at com.sun.javafx.scene.control.behavior.TableCellBehaviorBase.doSelect(TableCellBehaviorBase.java:110)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mouseReleased(CellBehaviorBase.java:159)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:388)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
at java.lang.Thread.run(Thread.java:745)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.*;
import javafx.application.Application;
import javafx.collections.*;
import javafx.collections.transformation.*;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.TreeTableColumn.CellDataFeatures;
import javafx.stage.Stage;
public class TreeTableViewSample extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
final TreeItem<String> childNode1 = new TreeItem<>("Child Node 1");
childNode1.getChildren().addAll(
new TreeItem<String>("Node 1-1"),
new TreeItem<String>("Node 1-2")
);
final TreeItem<String> root = new TreeItem<>("Root node");
root.setExpanded(true);
root.getChildren().add(childNode1);
TreeTableColumn<String,String> column = new TreeTableColumn<>("Column");
column.setPrefWidth(190);
column.setCellValueFactory((CellDataFeatures<String, String> p) ->
new ReadOnlyStringWrapper(p.getValue().getValue()));
final TreeTableView<String> treeTableView = new TreeTableView<>(root);
treeTableView.getColumns().add(column);
treeTableView.setPrefWidth(200);
treeTableView.setShowRoot(true);
treeTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
// Select all children of expanded node.
treeTableView.expandedItemCountProperty().addListener((observable, oldCount, newCount) -> {
if (newCount.intValue() > oldCount.intValue()) {
selectChildrenOfRows(treeTableView, treeTableView.getSelectionModel().getSelectedIndices());
}
});
filteredList = treeTableView.getSelectionModel().getSelectedItems().filtered(Objects::nonNull);
filteredList.addListener((ListChangeListener.Change<? extends TreeItem<String>> change) -> {
System.out.printf("Change: %s\n", change);
});
final Scene scene = new Scene(new Group(), 200, 400);
Group sceneRoot = (Group)scene.getRoot();
sceneRoot.getChildren().add(treeTableView);
stage.setTitle("Tree Table View Samples");
stage.setScene(scene);
stage.show();
}
private FilteredList<TreeItem<String>> filteredList;
private void selectChildrenOfRows(TreeTableView<String> table, Collection<Integer> selectedRows) {
for (int index: selectedRows) {
TreeItem<String> item = table.getTreeItem(index);
if (item != null && item.isExpanded() && !item.getChildren().isEmpty()) {
int startIndex = index + 1;
int maxCount = startIndex + item.getChildren().size();
table.getSelectionModel().selectRange(startIndex, maxCount);
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't create a FilteredList from the selectedItems property of a TreeTableView.
- relates to
-
JDK-8189354 Change.getRemoved() list contains incorrect selected items when a TreeItem is collapsed
- Resolved
-
JDK-8157285 TreeTableView produces incorrect selection model state when requested from expandedItemCount property listener
- Resolved
-
JDK-8240287 SelectedItemsReadOnlyObservableList cleanup: remove unused code.
- Closed
-
JDK-8157205 TreeView / TreeTableView product incorrect output when items are collapsed
- Resolved
-
JDK-8189228 TreeView Multi-Selection does not work properly
- Closed