Reputation: 13859
My program seems to work fine when scrolling up and down in the main ListView
. The problem happens when I open a TitledPane
and scroll down or up fast using the mouse scroll-wheel. I also noticed that if I use the mouse to drag the scrollbar after opening a TitledPane
, everything works fine. I would like to think that I am very good a spotting and fixing my NullPointer
errors, but this one has me baffled. How do I pinpoint the cause of the error and how do I fix it. I can probably figure the second part out if I could understand what is going on.
Main
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class NPEDiggingSO extends Application
{
private static class OuterListCell extends ListCell<MainListViewCellData>
{
private final ListView<Note> cellListView;
public OuterListCell()
{
setPrefHeight(300);
setPrefWidth(300);
cellListView = new ListView<>();
cellListView.setCellFactory(v -> new NoteCell());
}
@Override
protected void updateItem(MainListViewCellData item, boolean empty)
{
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
}
else {
cellListView.getItems().setAll(item.getNotes());
setGraphic(cellListView);
}
}
}
private Parent createContent()
{
DataModel model = new DataModel();
ListView<MainListViewCellData> outer = new ListView<>(model.getMainListViewData());
outer.setCellFactory(c -> new OuterListCell());
BorderPane content = new BorderPane(outer);
return content;
}
@Override
public void start(Stage stage) throws Exception
{
stage.setScene(new Scene(createContent(), 700, 500));
//stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
DataModel
import java.util.ArrayList;
import java.util.List;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
/**
*
* @author blj0011
*/
public class DataModel
{
public DataModel()
{
}
public ObservableList<MainListViewCellData> getMainListViewData()
{
ObservableList<MainListViewCellData> observableList = FXCollections.observableArrayList();
for (int i = 0; i < 250; i++) {
MainListViewCellData mainListViewCellData = new MainListViewCellData();
List<Note> notes = new ArrayList();
notes.add(new Note("note title " + i, "note text " + 1));
mainListViewCellData.setNotes(notes);
observableList.add(mainListViewCellData);
}
return observableList;
}
}
MainListViewCellData
import java.util.List;
import javafx.collections.FXCollections;
/**
*
* @author blj0011
*/
public class MainListViewCellData
{
private List<Note> notes;
public MainListViewCellData(List<Note> notes)
{
this.notes = notes;
}
public MainListViewCellData()
{
this.notes = FXCollections.observableArrayList();
}
public List<Note> getNotes()
{
return notes;
}
public void setNotes(List<Note> notes)
{
this.notes = notes;
}
@Override
public String toString()
{
return '{' + "notes=" + notes + '}';
}
}
Note
public class Note
{
private String title;
private String text;
public Note(String title, String text)
{
this.title = title;
this.text = text;
}
public String getText()
{
return text;
}
public void setText(String text)
{
this.text = text;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(", title=").append(title);
sb.append(", text=").append(text);
sb.append('}');
return sb.toString();
}
}
NoteCell
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ListCell;
import javafx.scene.control.TextArea;
import javafx.scene.control.TitledPane;
public class NoteCell extends ListCell<Note>
{
TextArea textArea = new TextArea();
TitledPane titledPane = new TitledPane("", textArea);
ObservableList<Note> observableList = FXCollections.observableArrayList();
@Override
public void updateItem(Note item, boolean empty)
{
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
}
else {
titledPane.setExpanded(false);
titledPane.setText(item.getTitle());
titledPane.setAnimated(false);
textArea.setText(item.getText());
setGraphic(titledPane);
}
}
}
Error Message
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at com.sun.javafx.scene.control.skin.VirtualFlow$4.findOwnerCell(VirtualFlow.java:848)
at com.sun.javafx.scene.control.skin.VirtualFlow$4.select(VirtualFlow.java:822)
at com.sun.javafx.scene.traversal.TraversalEngine.select(TraversalEngine.java:103)
at com.sun.javafx.scene.traversal.TopMostTraversalEngine.trav(TopMostTraversalEngine.java:77)
at javafx.scene.Scene.traverse(Scene.java:2005)
at javafx.scene.Scene.focusIneligible(Scene.java:2024)
at javafx.scene.Scene.access$3400(Scene.java:159)
at javafx.scene.Scene$ScenePulseListener.focusCleanup(Scene.java:2370)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2385)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:398)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:397)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:424)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:561)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:541)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:534)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:340)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$3(WinApplication.java:177)
at java.lang.Thread.run(Thread.java:748)
PS
I would like to apologize for being lazy and thank @kleopatra for creating the MCVE before I got the chance too.
Upvotes: 1
Views: 1142
Reputation: 51524
No solution, just a MCVE to play with and some observations (my context is Win10, fx11). To see the error, click on the button in the top-most cell, then scroll down by mouseWheel. The error
So, yeah, I would say it's a bug around focusTraversal - but unable to nail it.
The example:
public class NPEDiggingSO extends Application {
private static class InnerListCell extends ListCell<String> {
private Button button;
public InnerListCell() {
button = new Button();
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
} else {
button.setText(item);
setGraphic(button);
}
}
}
private static class OuterListCell extends ListCell<String> {
private ListView<String> cellListView;
public OuterListCell() {
setPrefHeight(300);
setPrefWidth(300);
cellListView = new ListView<>();
cellListView.setCellFactory(c -> new InnerListCell());
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
} else {
cellListView.getItems().setAll(item);
setGraphic(cellListView);
}
}
}
private Parent createContent() {
ObservableList<String> model = FXCollections.observableArrayList(
"item1", "item2", "item3", "item4", "item5");
ListView<String> outer = new ListView<>(model);
outer.setCellFactory(c -> new OuterListCell());
BorderPane content = new BorderPane(outer);
return content;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 3