Получение исключения Null Pointer и не могу понять почему - PullRequest
1 голос
/ 13 февраля 2020

Моя программа работает нормально при прокрутке вверх и вниз в главном ListView. Проблема возникает, когда я открываю TitledPane и быстро прокручиваю вниз или вверх с помощью колесика прокрутки мыши. Я также заметил, что если я перетаскиваю полосу прокрутки мышью после открытия TitledPane, все работает нормально. Я хотел бы думать, что я очень хорошо обнаруживаю и исправляю свои NullPointer ошибки, но это меня сбило с толку. Как определить причину ошибки и как ее исправить. Я мог бы, вероятно, понять вторую часть, если бы мог понять, что происходит.

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 + '}';
        }
    }

Примечание

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);
        }
    }
}

Сообщение об ошибке

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

Я хотел бы извиниться за ленивость и поблагодарить @kleopatra за создание MCVE перед У меня тоже есть шанс.

1 Ответ

2 голосов
/ 13 февраля 2020

Нет решения, просто MCVE, с которым можно поиграть, и некоторые наблюдения (мой контекст - Win10, fx11). Чтобы увидеть ошибку, нажмите кнопку в самой верхней ячейке, а затем прокрутите ее мышью вниз. Ошибка

  • происходит только при прокрутке колесом мыши
  • происходит только при прокрутке вниз
  • происходит только при наличии узла во внутренней ячейке (здесь простая кнопка) фокусируется при прокрутке

Так что, да, я бы сказал, что это ошибка в focusTraversal - но не в состоянии ее зафиксировать.

Пример:

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);
    }

}
...