My code gets the following error.
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: javafx.scene.Group cannot be cast to javafx.scene.control.TreeCell
Source code
private TreeItem getClickedTreeItem(EventTarget eventTarget){
TreeItem clickedTreeItem = null;
if(eventTarget instanceof TreeCellSkin){
clickedTreeItem = (TreeItem) ((TreeCell) ((TreeCellSkin)eventTarget).getParent()).getTreeItem();
}else if(eventTarget instanceof LabeledText){
clickedTreeItem = (TreeItem) ((TreeCell) ((LabeledText)eventTarget).getParent().getParent()).getTreeItem();
}else if(eventTarget instanceof ImageView){
clickedTreeItem = (TreeItem) ((TreeCell) ((ImageView)eventTarget).getParent().getParent()).getTreeItem();
}
return clickedTreeItem;
}
The console says this line:
clickedTreeItem = (TreeItem) ((TreeCell) ((ImageView)eventTarget).getParent().getParent()).getTreeItem();
This is legacy code that worked with Java 6, but gives the above exception using Java8?
What could be causing the ClassCastException
now, and how to fix it for Java8?
The current code is brittle as it relies on the internal structure of the TreeCell
. Also, TreeCellSkin
1 and LabeledText
are both internal classes. Internal code is subject to change without notice and without regards to third party reliance on it. Since this worked in Java 6 but not Java 8 I can only assume that the ImageView
's grandparent changed from being the TreeCell
to being a Group
between the two versions.
To fix this you could look into the implementation and see what you need to do so you reach the TreeCell
again, but that wouldn't really solve the problem. The use of EventTarget
says to me this code was implemented while not fully understanding how event handling works in JavaFX. From the apparent goal of this code you should be using the source of the event, not the target. In JavaFX, the source of the event is always the object for which the EventHandler
currently handling said Event
was added to2. In other words, if you added the EventHandler
to the TreeCell
then the source will be the TreeCell
. Using the source, and assuming EventHandler
is added to the TreeCell
, you can simply do:
TreeItem<?> item = ((TreeCell<?>) event.getSource()).getTreeItem();
Of course, if you're adding the EventHandler
to the TreeCell
you likely needn't bother with the source as you'll have access to the TreeCell
directly. For example:
TreeView<String> treeView = new TreeView<>();
treeView.setCellFactory(tv -> {
TreeCell<String> cell = new TreeCell<>(); // or some custom implementation
cell.setOnMouseClicked(event -> {
TreeItem<String> item = cell.getTreeItem();
// do something with item...
});
return cell;
});
1. TreeCellSkin
became public API in JavaFX 9 along with many (all?) skin implementations. They are part of the javafx.scene.control.skin
package.
2. There's more to it but that's beyond the scope of this answer.