palexdev / VirtualizedFX

GNU Lesser General Public License v3.0
46 stars 4 forks source link

NPE when table with variable columns is empty #4

Closed stefanofornari closed 1 year ago

stefanofornari commented 1 year ago

How to reproduce it:

Expected behaviour: The app starts with empty content Current behaviour: The app crashes with the following stack trace:

java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465)
    at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1081)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
    at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
    at java.base/java.lang.Thread.run(Thread.java:1589)
Caused by: java.lang.NullPointerException: Cannot invoke "io.github.palexdev.virtualizedfx.table.TableColumn.getRegion()" because "column" is null
    at VirtualizedFX@11.8.1/io.github.palexdev.virtualizedfx.table.TableHelper$VariableTableHelper.computePositions(TableHelper.java:957)
    at VirtualizedFX@11.8.1/io.github.palexdev.virtualizedfx.table.VirtualTableSkin$1.layoutChildren(VirtualTableSkin.java:98)
    at javafx.graphics@19/javafx.scene.Parent.layout(Parent.java:1207)
    at javafx.graphics@19/javafx.scene.Parent.layout(Parent.java:1214)
    at javafx.graphics@19/javafx.scene.Parent.layout(Parent.java:1214)
    at javafx.graphics@19/javafx.scene.Parent.layout(Parent.java:1214)
    at javafx.graphics@19/javafx.scene.Parent.layout(Parent.java:1214)
    at javafx.graphics@19/javafx.scene.Parent.layout(Parent.java:1214)
    at javafx.graphics@19/javafx.scene.Parent.layout(Parent.java:1214)
    at javafx.graphics@19/javafx.scene.Parent.layout(Parent.java:1214)
    at javafx.graphics@19/javafx.scene.Scene.doLayoutPass(Scene.java:592)
    at javafx.graphics@19/javafx.scene.Scene.preferredSize(Scene.java:1786)
    at javafx.graphics@19/javafx.scene.Scene$2.preferredSize(Scene.java:409)
    at javafx.graphics@19/com.sun.javafx.scene.SceneHelper.preferredSize(SceneHelper.java:66)
    at javafx.graphics@19/javafx.stage.Window$12.invalidated(Window.java:1163)
    at javafx.base@19/javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
    at javafx.base@19/javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:145)
    at javafx.graphics@19/javafx.stage.Window.setShowing(Window.java:1239)
    at javafx.graphics@19/javafx.stage.Window.show(Window.java:1254)
    at javafx.graphics@19/javafx.stage.Stage.show(Stage.java:277)
    at com.github.stefanofornari.virtualizedflowtable@0.0-SNAPSHOT/com.github.stefanofornari.virtualizedflowtable.App.start(App.java:27)
    at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
    at javafx.graphics@19/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
    at javafx.graphics@19/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics@19/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
    at javafx.graphics@19/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics@19/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics@19/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:316)

NOTES:

  1. With fixed column layout it works (that's why you do not see it in the test app)
  2. You can't imagine the headache trying to figure out what I was doing wrongly!!! :D :D :D
palexdev commented 1 year ago

I'm sorry haha I tested VirtualizedFX as best as I could I'll try to fix it by this day if it's an easy one Thanks for reporting

P.S: Oh, also I know I still have to answer to the scrolling question, will do asap

stefanofornari commented 1 year ago

eheh :) no worries and thanks!

have you ever explored to use better testfx and practice a bit of TDD? you'll realize you save a lot of time ;)

palexdev commented 1 year ago

Fixed by 275da4637e7c20dd4525a3628bda6a9bcf31afe7

I know the TDD technique, and yes, in some cases it saves a lot of time, as both the logic and the verification code are written at the same time. I recently used it for another project, separated in backend and frontend modules. I'm a bit skeptical about testing GUIs with unit tests. I feel like interactive apps are a better way to test them, it's a bit boring and cumbersome to reproduce issues, yet I find it more immediate

stefanofornari commented 1 year ago

It's a separate discussion than this bug indeed, but you may want to give it a try. I was skeptical as well, but after using in in flutter and now testfx I am a big fan of it. A few reasons:

  1. It really saves you a lot of time; as soon as you start using it you realize how many "run the app, follow the path, check it works" you save
  2. It saves you a lot of time; when you release a new version you can avoid to execute all your test cases (which I am pretty sure nobody does)
  3. It saves you a lot of time; you can leave some details to the test cases, they will document better and hey won't get out of date
  4. It saves who reads the code a lot of time; they can relate to the test to understand the logic
  5. It saves you a lot of time; in this case TDD in particular, because you focus more on what you want to achieve and not overdesign and overcomplicate things just for the sake of doing it
  6. You end up with better and better designed code; you have do code for testability, which encourages modularity, clear interfaces, etc
  7. You will be more confident of your code and therefore you can release more often
  8. ...

In the case of UI you won't probably go to the granularity of testing if a corner is rounded enough, but you can find your own balance.

HTH