RichTextFX icon indicating copy to clipboard operation
RichTextFX copied to clipboard

VirtualScrollPane causes exception during initial layout "java.util.NoSuchElementException: Cell ## is not visible"

Open swpalmer opened this issue 4 years ago • 7 comments

Expected Behavior

Scroll bars for my CodeArea

Actual Behavior

Exception in Application start method
java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Exception in Application start method
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
	at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.util.NoSuchElementException: Cell 2 is not visible
	at org.fxmisc.flowless.CellPositioner.getVisibleCell(CellPositioner.java:37)
	at org.fxmisc.flowless.Navigator.distanceFromGround(Navigator.java:373)
	at org.fxmisc.flowless.Navigator.fillViewportFrom(Navigator.java:333)
	at org.fxmisc.flowless.Navigator.visit(Navigator.java:131)
	at org.fxmisc.flowless.StartOffStart.accept(TargetPosition.java:85)
	at org.fxmisc.flowless.Navigator.layoutChildren(Navigator.java:80)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1207)
	at org.fxmisc.flowless.VirtualFlow.layoutChildren(VirtualFlow.java:257)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1207)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Scene.doLayoutPass(Scene.java:576)
	at javafx.graphics/javafx.scene.Scene.preferredSize(Scene.java:1750)
	at javafx.graphics/javafx.scene.Scene$2.preferredSize(Scene.java:393)
	at javafx.graphics/com.sun.javafx.scene.SceneHelper.preferredSize(SceneHelper.java:66)
	at javafx.graphics/javafx.stage.Window$12.invalidated(Window.java:1086)
	at javafx.base/javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
	at javafx.base/javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:145)
	at javafx.graphics/javafx.stage.Window.setShowing(Window.java:1174)
	at javafx.graphics/javafx.stage.Window.show(Window.java:1189)
	at javafx.graphics/javafx.stage.Stage.show(Stage.java:273)

Reproducible Demo

This example gives a slightly different exception during layout. The horizontal scrollbar is misplaced and the layout is broken. In my full application the exception happens earlier - there is no initial layout, the start method fails and the app exits. If I remove the VirtualScrollPane the issue goes away. I'm having a a hard time making a small example that gives the exact error above.

public class Bug extends Application {

 public static void main(String [] args) {
     launch(args);
 }

 public void start(Stage stage) {
        CodeArea editor = new CodeArea();

        try {
            // Use the path of some file that doesn't fit in the view
            editor.appendText(Files.readString(Path.of("\\pick\\a\\file\\Bug.java")));
        } catch (IOException ex) {
            System.err.println("Crap..." + ex);
        }
        editor.setParagraphGraphicFactory(LineNumberFactory.get(editor));
        editor.setLineHighlighterOn(true);

        Region wrapper = new Pane(new VirtualizedScrollPane<>(editor));
        editor.prefWidthProperty().bind(wrapper.widthProperty());
        editor.prefHeightProperty().bind(wrapper.heightProperty());

        Tab tab = new Tab("Editor", wrapper);
        TabPane tabs = new TabPane(tab);
        SplitPane splitter = new SplitPane(new Label("placeholder"), tabs);
        BorderPane bp = new BorderPane(splitter);

        Scene scene = new Scene(bp);
        stage.setScene(scene);
        stage.setWidth(800);
        stage.setHeight(600);
        stage.setTitle("VirtualScrollPane Layout Issue");
        stage.show();
    }

}

Environment info:

  • RichTextFX Version: 0.10.5
  • Operating System: Windows 10 Pro 64-bit
  • Java version: openjdk version "15.0.1" 2020-10-20 OpenJDK Runtime Environment Zulu15.28+51-CA (build 15.0.1+9) OpenJDK 64-Bit Server VM Zulu15.28+51-CA (build 15.0.1+9, mixed mode, sharing) ("JDK FX" version)

Current Workarounds

Have not been able to get VirtualScrollPane to work without issues. Scrolling works via trackpad without it though.

swpalmer avatar Dec 15 '20 14:12 swpalmer

If I'm not mistaken a clunky workaround is to only add the VirtualizedScrollPane to the Scene after the Stage is shown.

Jugen avatar Dec 15 '20 14:12 Jugen

Sorry, a better workaround would be to only add/append the text to the editor AFTER the scene/stage is shown.

Jugen avatar Dec 15 '20 15:12 Jugen

That does seem to work for the initial exception. However now I notice that scrolling is not as smooth, particularly in the horizontal direction, and I've seen several occurrences of this exception:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException: Cannot invoke "org.fxmisc.richtext.model.Paragraph.length()" because "this.paragraph" is null
	at org.fxmisc.richtext.ParagraphText.getClampedCaretPosition(ParagraphText.java:319)
	at org.fxmisc.richtext.ParagraphText.getCurrentLineStartPosition(ParagraphText.java:295)
	at org.fxmisc.richtext.ParagraphBox.getCurrentLineStartPosition(ParagraphBox.java:179)
	at org.fxmisc.richtext.GenericStyledArea.getCurrentLineStartInParargraph(GenericStyledArea.java:1185)
	at org.fxmisc.richtext.GenericStyledArea.lambda$setLineHighlighterOn$36(GenericStyledArea.java:1255)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
	at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
	at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
	at java.base/java.lang.Thread.run(Thread.java:832)

When resizing the window, it eventually locks up the layout with this exception:

Exception in thread "JavaFX Application Thread" java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.get(Optional.java:141)
	at org.fxmisc.flowless.CellListManager.getPresentCell(CellListManager.java:65)
	at org.fxmisc.flowless.CellPositioner.getVisibleCell(CellPositioner.java:33)
	at org.fxmisc.flowless.Navigator.distanceFromGround(Navigator.java:373)
	at org.fxmisc.flowless.Navigator.fillViewportFrom(Navigator.java:333)
	at org.fxmisc.flowless.Navigator.visit(Navigator.java:131)
	at org.fxmisc.flowless.StartOffStart.accept(TargetPosition.java:85)
	at org.fxmisc.flowless.Navigator.layoutChildren(Navigator.java:80)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1207)
	at org.fxmisc.flowless.VirtualFlow.layoutChildren(VirtualFlow.java:257)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1207)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
	at javafx.graphics/javafx.scene.Scene.doLayoutPass(Scene.java:576)
	at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2476)
	at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:413)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
	at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:412)
	at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:439)
	at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:563)
	at javafx.graphics/com.sun.javafx.tk.quantum.PaintCollector.liveRepaintRenderJob(PaintCollector.java:327)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$ViewEventNotification.run(GlassViewEventHandler.java:883)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$ViewEventNotification.run(GlassViewEventHandler.java:843)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleViewEvent$15(GlassViewEventHandler.java:924)
	at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:412)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleViewEvent(GlassViewEventHandler.java:923)
	at javafx.graphics/com.sun.glass.ui.View.handleViewEvent(View.java:540)
	at javafx.graphics/com.sun.glass.ui.View.notifyResize(View.java:880)
	at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
	at java.base/java.lang.Thread.run(Thread.java:832)

swpalmer avatar Dec 16 '20 00:12 swpalmer

I think the current master version (to be released as 0.10.6 end of January) addresses the NullPointerException and maybe also the NoSuchElementException.

Jugen avatar Dec 16 '20 06:12 Jugen

Please test with the latest version (0.10.6) that's been released now, and give feedback if needed.

Jugen avatar Mar 23 '21 09:03 Jugen

Please test with the latest version (0.10.6) that's been released now, and give feedback if needed.

@Jugen I still get these confusing exceptions in 0.10.8.

Glavo avatar May 15 '22 09:05 Glavo

Ah, when I repeatedly open a file in my editor, when I use RichTextFX 0.10.8, an exception occurs probabilistically and the opening fails. Exceptions that may occur are NullPointerException, NoSuchElementException·, IndexOutOfBoundsExceptionandConcurrentModificationException`.

I just tried updating to 0.10.9 and I was surprised that these exceptions no longer occur, although this fix is not mentioned at all in the changelog. Unfortunately, I also need to be compatible with Java 8, so I can't upgrade for the time being.

Glavo avatar May 15 '22 09:05 Glavo