Location of stylesheet for javafx development

Bob B's Avatar

Bob B

06 Aug, 2020 01:56 AM

I've create my very first javafx extension and it's running but looks ugly as sin lol. I created a stylesheet to style the window (beautifully, if I do say so myself) but now I'm at a loss as to where to put it so that the extension can find it.

When I debug, there's an error :

Aug. 05, 2020 6:44:26 P.M. com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
WARNING: Resource "DailyPerformance.css" not found.

I've tried putting the css file in the extension folder, everywhere in the moneydance folders but nothing works.

Of course, this may all be because I don't know what I'm doing, and I'm not sure how the build process works with an extension. Can it be bundeld 'inside' the extension? Any help is gratefully accepted.

  1. 1 Posted by Bob B on 07 Aug, 2020 02:34 AM

    Bob B's Avatar

    I finally got this working in debug mode - window is styled nicely. To fix the issue I had to play around with the path and make also made sure the path was in the build file. However, since the css file is in the extension file, I don't know how to have it reference on the user's might configure (not a biggie, just wondering).

    BUT the bigger issue is that I can only run in debug mode from Intellij. When I try to run from MD directly and not in debug mode, the extension dialog opens but is empty and when I close the dialog, MD also shuts down.

    Is there anyway that i can 'debug' running version of MD? Can I somehow use the -d option when I start it and have the output go to text file? This is all new to me so any help is appreciated greatly.

  2. Support Staff 2 Posted by Sean Reilly on 07 Aug, 2020 08:40 AM

    Sean Reilly's Avatar

    As for quitting when you close the window, do you need to ensure that the exitOnClose setting is false on one of your windows? I'm not familiar with javafx so I'm just guessing on that.

    By default all logging to stderr/stdout will go to the errlog.txt file that is stored in moneydance's internal folder. If you can monitor that file then I suppose there's no need for passing the -d flag. If you'd like to also enable moneydance's own internal logging to stderr (and also that file) you can set com.moneydance.apps.md.controller.Main.DEBUG = true

    --
    Sean Reilly
    Developer, The Infinite Kind
    https://infinitekind.com

  3. 3 Posted by Mike Bray on 07 Aug, 2020 09:23 AM

    Mike Bray 's Avatar

    I am playing with JavaFX and have found a number of issues. Firstly MD has a class loader class that is used to load extensions. Not all of the ClassLoader methods are overridden so these don't work. If you set the FX Scene stylesheet these are not loaded. You need to load your .css file separately and set the style on the root node.

    public Scene createScene(){  
               menuBox = new VBox();
            mainScreen = new GridPane();
            menuBar = new MainMenu(this);
            menuBox.getChildren().addAll(menuBar,mainScreen);
            scene = new Scene(menuBox,iFRAMEDEPTH,iFRAMEWIDTH);
            String css="";
            try {
                java.io.InputStream in =                Main.loader.getResourceAsStream(Constants.RESOURCES+"datadatapane.css");
                if (in != null) {
                    ByteArrayOutputStream bout = new ByteArrayOutputStream(1000);
                    byte buf[] = new byte[256];
                    int n = 0;
                    while((n=in.read(buf, 0, buf.length))>=0)
                        bout.write(buf, 0, n);
                    css = bout.toString();
                }
            } catch (Throwable e) {
                e.printStackTrace();
                return scene;
            }
            menuBox.setStyle(css);
            return scene;
        }
    

    Secondly I use Eclipse as my IDE and when running in debug mode the resources are not found as the class hierarchy is different.

    I must admit I have been considering switching back to Swing as using FX with the JFXPanel class causes some issues, especially with data access as this must be done on the Swing EDT.

  4. 4 Posted by Bob B on 07 Aug, 2020 05:31 PM

    Bob B's Avatar

    This is the error I'm getting when running directly from the app - It cant seem to find the loaded class.

    prior to loader creation
    Exception in thread "JavaFX Application Thread" java.lang.NoClassDefFoundError: javafx/fxml/FXMLLoader

    Here is the source:
     System.err.println("prior to loader creation");

     FXMLLoader loader = new FXMLLoader();

    System.err.println("new FXMLoader created");
                    loader.setLocation(getClass().getResource("DailySecurityPerformance.fxml"));
    System.err.println("loader setLocation passed");
    Parent parent = loader.load();
    System.err.println("loader.load passed");
    Scene scene = new Scene(parent, 975, 600);

  5. 5 Posted by Bob B on 07 Aug, 2020 05:34 PM

    Bob B's Avatar

    BTW: the following now works for me to get the css

    String css = this.getClass().getResource("/DailyPerformance.css").toExternalForm(); scene.getStylesheets().add(css);

  6. 6 Posted by Bob B on 07 Aug, 2020 11:29 PM

    Bob B's Avatar

    UPDATE: hereis what I have tried (all without success). Extension runs in debug but fails in MD direct with :
    ava.lang.NoClassDefFoundError: javafx/fxml/FXMLLoader

    I've tried replacing javafx 14.0.2.1 with 11.0.2

    I tried
     String test1 = Scene.class.getPackageName();
     System.err.println("test1: " + test1); (that works so javafx is being found)

    but

     String test1 = FXMLLoader.class.getPackageName() (FAILS)

    Anyone have any ideas, I'm an amateur and flummoxed!

  7. Support Staff 7 Posted by Sean Reilly on 07 Aug, 2020 11:34 PM

    Sean Reilly's Avatar

    It seems like FXMLLoader needs access to the classloader, which may not work because moneydance tries to keep extensions from breaking out of their sandbox. If we allow too much access to the class loader then all security is out of the window as any code can be loaded and run within the app.

    Unfortunately I'm not familiar with what FXMLLoader is used for, but if you have a stack trace for that exception maybe it might have some useful information?

    Thanks,
    Sean

  8. 8 Posted by Mike Bray on 08 Aug, 2020 07:30 AM

    Mike Bray 's Avatar

    Hi Sean and Bob

    My take on this is:

    The MD class loader (the one that loadss extensions) overrides
    getResourceAsStream but not getResource so if you use getResource then
    it uses the parent classloader which does not know about .mxt files.  I
    am assuming that getResource will not find the .css file if it is in the
    .mxt file.  Hence my code works as it uses getResourceAsStream in the
    same way as getIcon in the Main class gets the extension icon.

    Sean, I understand the need to isolate the extensions so it does not
    interfere with the core code, could the MD class loader be extended to
    support more of the classloader methods?

    Mike

  9. Support Staff 9 Posted by Sean Reilly on 08 Aug, 2020 08:05 PM

    Sean Reilly's Avatar

    Hi Mike,

    Moneydance does override the findResource(String) method in the class loader which is called by the default getResource(String) implementation, so I'm not sure what is missing here. Are there specific methods which don't work, or can you provide a case (and sample extension) when getResource(String) should work but isn't?

    Thanks,
    Sean

  10. 10 Posted by Bob B on 09 Aug, 2020 03:56 AM

    Bob B's Avatar

    Thanks Sean and MIke. This discussion is going a bit (to say the least) over my head. I'n new to this and so I learn by example (thanks Mike for all your examples, they have been invaluable to me when trying to figure this out - particularly the build process).

    So my problem is that FXMLoader was not being found - i fixed that part by adding the javafx.fxml.jar into my ant build :

    I copied an example from Mike for other jars. I have no idea if this is the correct thing to do, but the FXMLoader Class is now found. But the resource it's looking for (the fxml file) is not found.

    The FXML file contains the source for the javafx 'window'. FXML is an XML-based language designed to build the user interface for JavaFX applications. You can use FXML to build an entire Scene or part of a Scene . FXML allows application developers to separate the logic for building the UI from the business logic.

    Does that help your understanding?

    Mike, you were talking about the css file. Have you managed to get the FXML file to load?

    private  void initFX(JFXPanel fxPanel) {
            // This method is invoked on the JavaFX thread
            try {
                    FXMLLoader loader = new FXMLLoader();
                    loader.setLocation(getClass().getResource("DailySecurityPerformance.fxml")); //the file is in the same location as the rest of the code
                    Parent parent  = loader.load();
                    // I never get this far unless running in debug mode
                    Scene scene = new Scene(parent, 975, 600);
                  
                    String css = this.getClass().getResource("/DailyPerformance.css").toExternalForm();
                    scene.getStylesheets().add(css);
                    
                    fxPanel.setScene(scene);
                }
    

    This is the error in the MD errlog.txt

    java.lang.NullPointerException: inputStream is null.
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2480)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
        at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
        at com.moneydance.modules.features.dailyperformance.DailyPerformanceFX.initFX(DailyPerformanceFX.java:74)
        at com.moneydance.modules.features.dailyperformance.DailyPerformanceFX$1.run(DailyPerformanceFX.java:53)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
        at java.base/java.security.AccessController.doPrivileged(Unknown Source)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
    

    Thanks again for your help. If I can provide any additional information, please let me know.

  11. 11 Posted by Mike Bray on 09 Aug, 2020 04:53 AM

    Mike Bray 's Avatar

    Hi Sean
    I don't have a specific example as I found out early on that getResource does not work. In the quote loader source (which you have) the class ExchangeList loads two files from the .mxt file and I have had to use 'getResourceAsStream' to get it to work.

    From what Bob is experiencing I suspect the FX .css problem is more involved. I know that setting the Scene stylesheet does not work. The code I provided does work, but not in debug, which is a problem with Edclipse.
    Regards
    Mike

  12. 12 Posted by hleofxquotes on 10 Aug, 2020 03:32 PM

    hleofxquotes's Avatar

    @ Bob, after you instantiate the FXMLLoader, try to see if you can force it to use the extension classLoader (which in theory knows how to get to your resource in the mxt file).

      loader.setClassLoader(extClassLoader)
    

    (https://docs.oracle.com/javase/8/javafx/api/javafx/fxml/FXMLLoader....)

    where extClassLoader the extension classLoader. You probably can get extClassLoader from one of the classes that is IN your extension mxt file. Off the top of my head ....

       extClassLoader = OneOfMyClassInMxtFile.class.getClassLoader();
    

    In terms of getting the resource from your mxt file, the ultimate fallback is to do it yourself ;-). You can open the extension file up as a JarFile or use JarClassLoader() and go from there.

  13. 13 Posted by Bob B on 10 Aug, 2020 08:58 PM

    Bob B's Avatar

    UPDATE: (are you sick of me yet!)

    I create a new simple project. It has a Controller class and a FXML file that displays a label with text. No stylesheet is used at this time.

    Once I made sure the FXML file was in the MXT. I was able to get the FXML to load using Mike's technique:

    String pathFXML =  "com/moneydance/modules/features/myextension/";
                    classLoader=this.getClass().getClassLoader();
                    InputStream inpFXML = classLoader.getResourceAsStream(pathFXML+ "testFXML.fxml");
                    FXMLLoader loaderFXML = new FXMLLoader();
                    Parent parent = loaderFXML.load(inpFXML);
                    Scene scene = new Scene(parent, 300, 300);
                    fxPanel.setScene(scene);
    

    However, I got this error because it couldn't find the Controller class named in the FXML:

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
        at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:930)
        at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:980)
        at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:227)
        at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:752)
        at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
        at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2450)
        at com.moneydance.modules.features.myextension.TestXML.initFX(TestXML.java:45)
        at com.moneydance.modules.features.myextension.TestXML$1.run(TestXML.java:30)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
        at java.base/java.security.AccessController.doPrivileged(Unknown Source)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
    Caused by: java.lang.ClassNotFoundException: com.moneydance.modules.features.myextension.Controller
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
    

    So I thought I'd just set the Controller prior to loading and remove it from the FXML file:

    String pathFXML =  "com/moneydance/modules/features/myextension/";
                    classLoader=this.getClass().getClassLoader();
                    InputStream inpFXML = classLoader.getResourceAsStream(pathFXML+ "testFXML.fxml");
                    FXMLLoader loaderFXML = new FXMLLoader();
                    loaderFXML.setController(new Controller());
                    Parent parent = loaderFXML.load(inpFXML);
                    Scene scene = new Scene(parent, 300, 300);
                    fxPanel.setScene(scene);
    

    BUT now I get this error and I'm stumped again (I've attached the project in case that helps).

    Exception in thread "JavaFX Application Thread" java.lang.IllegalAccessError: class javafx.fxml.JavaFXBuilderFactory (in unnamed module @0x754d1e06) cannot access class com.sun.javafx.reflect.ConstructorUtil (in module javafx.base) because module javafx.base does not export com.sun.javafx.reflect to unnamed module @0x754d1e06
        at javafx.fxml.JavaFXBuilderFactory.scanForConstructorAnnotations(JavaFXBuilderFactory.java:173)
        at javafx.fxml.JavaFXBuilderFactory.getBuilder(JavaFXBuilderFactory.java:160)
        at javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1013)
        at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:754)
        at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
        at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2450)
        at com.moneydance.modules.features.myextension.TestXML.initFX(TestXML.java:45)
        at com.moneydance.modules.features.myextension.TestXML$1.run(TestXML.java:30)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
        at java.base/java.security.AccessController.doPrivileged(Unknown Source)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
    
  14. 14 Posted by hleofxquotes on 11 Aug, 2020 02:24 PM

    hleofxquotes's Avatar
    Exception in thread "JavaFX Application Thread" java.lang.IllegalAccessError: class javafx.fxml.JavaFXBuilderFactory (in unnamed module @0x754d1e06) cannot access class com.sun.javafx.reflect.ConstructorUtil (in module javafx.base) because module javafx.base does not export com.sun.javafx.reflect to unnamed module @0x754d1e06
        at javafx.fxml.JavaFXBuilderFactory.scanForConstructorAnnotations(JavaFXBuilderFactory.java:173)
        at javafx.fxml.JavaFXBuilderFactory.getBuilder(JavaFXBuilderFactory.java:160)
    ...
    

    Couple of places to look for a problem like this:

    • Duplicate classes: if MD is providing javafx and you also include javafx in your mxt file. To fix: If MD is already providing the javafx class you need at runtime, then you don't have to include them in your mxt file.
    • Mis-match of modules vs non-module ("because module javafx.base does not export com.sun.javafx.reflect to unnamed module". To fix: this one is harder to fix because you will need to modify the JVM start arguments. See: 'https://openjfx.io/openjfx-docs/#install-javafx', note the usage of --add-modules
  15. 15 Posted by Bob B on 11 Aug, 2020 05:05 PM

    Bob B's Avatar

    Thanks hleofxquotes for your help. MD does include javafx but it does not seem to include javafx.fxml (at least I get a classNotFound error unless I include in my mxt). I'm not including any other javafx beside that one.

    I'm trying to follow your second point but the link talks about add-modules (which I needed to do in Intellij when I configure the debug run environment).

    So i did a little further reading and found this: (https://blog.codefx.org/java/five-command-line-options-hack-java-mo...)

    If i'm following the discussion (and that a big IF), it sounds like i need to add something to the jvm when running MD. Moneydance has a file: Moneydance.vmoptions that seems to provide the options for the jvm.

    # Enter one VM parameter per line
    # For example, the following line sets the maximum memory usage to 1GB 
    -Xmx1024m
    
    # to set the maximum memory limit to 2GB, remove the # from the following line
    -Xmx2048m
    
    
    --add-opens javafx.base/javafx.reflect=ALL-UNNAMED
    
    # To include another file, uncomment the following line:
    # -include-options <path to other .vmoption file>
    

    I added the --add-opens line but it made no difference. Perhaps I've done it incorrectly.

    Sean do you have any ideas, since you know the inner working of MD.

  16. 16 Posted by hleofxquotes on 11 Aug, 2020 06:00 PM

    hleofxquotes's Avatar

    I think you have a couple of options depending on what the end goal is

    • If this extension is for general distribution, I don't think the path of modifying the startup argument will be viable. In that case, you will need to find out what javafx modules are being provided at runtime by MD and limit your usage to those.
    • If this extension is for your own use and you can deal with additional JVM arguments, the better approach is to add the "missing" javafx module to the command-line the same way current modules are being added.

    That way all the javafx modules are in the same "module" per se rather than having them mixed.

    • You want to look for argument --add-modules module1,module2
    • and also a path to where the javafx modules are (–module-path “path/to/javafx/...)
  17. 17 Posted by Bob B on 11 Aug, 2020 09:41 PM

    Bob B's Avatar

    Thanks again hleofxquotes. I feel guilty about you taking this much time to help me. I really do appreciate it.

    I did as you said, although I may have misunderstood. I removed the --add-opens and added --module-path and --add-modules

    # Enter one VM parameter per line
    # For example, the following line sets the maximum memory usage to 1GB 
    -Xmx1024m
    
    # to set the maximum memory limit to 2GB, remove the # from the following line
    -Xmx2048m
    
    --module-path "C:/Program Files/Java/javafx-sdk-14.0.2.1/lib"
    --add-modules javafx.fxml  
    
    # To include another file, uncomment the following line:
    # -include-options <path to other .vmoption file>
    

    I also tried adding all the javafx modules but still no luck.

    --module-path "C:/Program Files/Java/javafx-sdk-14.0.2.1/lib"
    --add-modules javafx.fxml,javafx.base,javafx.controls,javafx.graphics,javafx-swt
    
    I get the same error when running the extension through MD instead of in debugging mode in Intellij.
    Exception in thread "JavaFX Application Thread" java.lang.IllegalAccessError: class javafx.fxml.JavaFXBuilderFactory (in unnamed module @0x26fb7b92) cannot access class com.sun.javafx.reflect.ConstructorUtil (in module javafx.base) because module javafx.base does not export com.sun.javafx.reflect to unnamed module @0x26fb7b92
        at javafx.fxml.JavaFXBuilderFactory.scanForConstructorAnnotations(JavaFXBuilderFactory.java:173)
        at javafx.fxml.JavaFXBuilderFactory.getBuilder(JavaFXBuilderFactory.java:160)
        at javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1013)
        at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:754)
        at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
        at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2450)
        at com.moneydance.modules.features.myextension.TestXML.initFX(TestXML.java:45)
        at com.moneydance.modules.features.myextension.TestXML$1.run(TestXML.java:30)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
        at java.base/java.security.AccessController.doPrivileged(Unknown Source)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
    

    I think using javafx to build a mxt, is not a viable option right now. I'm exploring not using and FXML file and creating the UI and bindings in java classes. I have the UI displaying without styling or bindings so at least I know that works.

    Sean if you are still reading this, can you provide any additional info re: support for FXML in javafx extensions.

  18. Support Staff 18 Posted by Sean Reilly on 11 Aug, 2020 10:01 PM

    Sean Reilly's Avatar

    Hi Bob,

    I think the best approach would be to tell the FXXMLLoader to use the extension's classloader, so that it has access to the bundled XML through the classloader rather than through the specific input stream.

    If your XML is referencing any com.sun classes then I think you might run into trouble, because I'd expect them to be private to the module that contains them.

    classLoader = this.getClass().getClassLoader();
    FXMLLoader loaderFXML = new FXMLLoader();
    loaderFXML.setClassLoader(classLoader);
    
    // then ask the loader to load your XML "normally"
    loaderFXML.setLocation(getClass().getResource("DailySecurityPerformance.fxml"));
    Parent parent = loaderFXML.load();
    Scene scene = new Scene(parent, 300, 300);
    fxPanel.setScene(scene);
    

    I've very little experience with javafx, so the above is just a guess based on knowing how the classloaders generally work.

    Thanks,
    Sean

    --
    Sean Reilly
    Developer, The Infinite Kind
    https://infinitekind.com

  19. 19 Posted by hleofxquotes on 12 Aug, 2020 01:39 PM

    hleofxquotes's Avatar

    Thanks again hleofxquotes. I feel guilty about you taking this much time to help me. I really do appreciate it.

    You are welcome.

    I think you are very close. I just try using your moneydance-devkit-test.zip file. I made the following change and was able to display the extension window/frame

    • I excluded the javafx files from being included in the extension file since we are going to have MD to provide it a runtime.
        <jar destfile="${dist}/myextension.mxt">
          <fileset dir="${src}" includes="
     ...
    <!--
          <zipgroupfileset  dir="${javafx}" includes="**/javafx.fxml.jar" />
    -->
        </jar>
    
    • You might not need the following since it sounded as if you were able to start. But for me, I had to modify Moneydance.vmoptions using separate lines as followed
    --add-modules
    javafx.fxml
    --module-path
    /Users/xxx/java/javafx-sdk-13.0.1/lib
    

    Not sure which platform you are on but key thing is to check the JVM process and see if it is actually running the above arguments

    See attached screenshot.

  20. 20 Posted by Bob B on 12 Aug, 2020 11:31 PM

    Bob B's Avatar

    Thanks very much but I think I'm jinxed lol. I did exactly as you demonstrated:

    I removed the the reference to javahx from the build file, and checked and made sure they were not in the mxt file.

    I modified the moneydance.vmoptions as you did but no variation of entering th data made any difference. The FXMLLoader class is not found.

    I tried moving the java fx lb to a different path, I tried the full path name, I tried setting up an environment variable, I tried putting the path on the same line as --module-path ; on a different line (line you) nothing made any difference.

    I'm running on Windows and I don't know how to check the JVM process to ensure it is reading the values.

  21. 21 Posted by hleofxquotes on 12 Aug, 2020 11:40 PM

    hleofxquotes's Avatar
  22. 22 Posted by Bob B on 13 Aug, 2020 07:00 PM

    Bob B's Avatar

    I've wmic and while moneydance is listed, there are no command line parameters.

    I'm pretty sure the vmoptions file is being read because when I change the entries for memory usage, task manager memory usage climbs.

    -Xmx2048m
    -Xms2048m
    

    I've tried to turn on class logging but no log file is ever created anywhere on my system and no existing file is modified anywhere etiher (except errlog.txt from MD but that doesn't have any increased information.

    -verbose:class
    -XX:+TraceClassLoading
    

    So I'm back to being stumped. there is something odd about how the file vmoptions is used with Windows or maybe there is something the MD does to limit it somehow.

    Sean, any insights? With the fact that hleofxquotes can get my little test extension program to run, I have hope that there is something simple I am missing (that may be famous last words).

  23. Support Staff 23 Posted by Sean Reilly on 13 Aug, 2020 08:06 PM

    Sean Reilly's Avatar

    Hi Bob,

    I've not been following all the details but have you set the classloader?

    loaderFXML.setClassLoader(this.getClass().getClassLoader());

    Thanks,
    Sean

  24. 24 Posted by Bob B on 13 Aug, 2020 11:19 PM

    Bob B's Avatar

    Summary for Sean:
    1) Your solution doesn't work because the underlying problem is that I can't instantiate the FXMLLoader class because MD does not include javafx.fxml in the javafx that you ship with. I get the following error in the MD error log (I've highlighted the crux of the matter between \\\ lines):

    Exception in thread "JavaFX Application Thread" java.lang.NoClassDefFoundError: javafx/fxml/FXMLLoader
        at com.moneydance.modules.features.myextension.TestXML.initFX(TestXML.java:43)
        at com.moneydance.modules.features.myextension.TestXML$1.run(TestXML.java:30)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
        at java.base/java.security.AccessController.doPrivileged(Unknown Source)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
    //////////////////////////////////////////////////////////////////////////
    Caused by: java.lang.ClassNotFoundException: javafx/fxml/FXMLLoader.class
    //////////////////////////////////////////////////////////////////////////
        at com.moneydance.apps.md.controller.ModuleLoader$FMClassLoader.loadResource(ModuleLoader.java:323)
        at com.moneydance.apps.md.controller.ModuleLoader$FMClassLoader.loadClass(ModuleLoader.java:380)
        at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
        ... 9 more
    

    2) If I include javafx.fxml in the mxt build, that solves the above error but now I get:

    Exception in thread "JavaFX Application Thread" java.lang.IllegalAccessError: class javafx.fxml.JavaFXBuilderFactory (in unnamed module @0x754d1e06) cannot access class com.sun.javafx.reflect.ConstructorUtil (in module javafx.base) because module javafx.base does not export com.sun.javafx.reflect to unnamed module @0x754d1e06
        at javafx.fxml.JavaFXBuilderFactory.scanForConstructorAnnotations(JavaFXBuilderFactory.java:173)
        at javafx.fxml.JavaFXBuilderFactory.getBuilder(JavaFXBuilderFactory.java:160)
    ...
    
    3) hleofxquotes has been helpful and suggested I remove it from the build and add the module via the moneydance.vmoptions files as follows (not a solution if I wanted to distribute the extension but good enough for me):
    --add-modules javafx.fxml
    --module-path <<substitute path to javafx sdk>>
    
    He did that to the sample basic simple FX extension that I included in the thread above and was able to get the dialog to display without error (see above) [after he removed javafx.fxml from the build.xml]. He's on unix i think.

    4) I tried the same thing (on Windows 10) but it makes no difference. The javafx.fxml is not found. That's where I'm stuck now. I tried many permutations in the vmoptions file for the path but none work.

  25. 25 Posted by hleofxquotes on 14 Aug, 2020 03:42 AM

    hleofxquotes's Avatar

    Bob, I started up a Windows VM and am seeing what you are seeing. I do have some pointers for you but I think it will be best to have that discussion via email. Send me email hleofxquotes at gmail dot com.

  26. Support Staff 26 Posted by Sean Reilly on 14 Aug, 2020 06:58 AM

    Sean Reilly's Avatar

    If you wouldn't mind reporting back if you find a solution I'd love to hear about it, and have it here on "on the record" for anyone else searching for the same solution.

    Would this all be solved if I simply included the javafx.fxml module in the JRE that's bundled with Moneydance?

    Thanks!
    Sean

  27. 27 Posted by hleofxquotes on 14 Aug, 2020 02:57 PM

    hleofxquotes's Avatar

    Would this all be solved if I simply included the javafx.fxml module in the JRE that's bundled with Moneydance?

    Yes, that probably is the best fix.

  28. 28 Posted by Bob B on 14 Aug, 2020 04:06 PM

    Bob B's Avatar

    I agree, that would probably fix everything but you might want to test it on the little sample app above. I will post any solution I come up with to help others get going with this. Thanks

    Not to get greedy but if you come if a solution to have an external stylesheet for an extension, that would be awesome. Although it's really just a nice to have not that I've figured out how to bundle it inside the extension as a resource.

  29. 29 Posted by Bob B on 14 Aug, 2020 05:31 PM

    Bob B's Avatar

    INTERIM WINDOWS SOLUTION (thank you so much hleofxquotes):

    Create a bat file and run MD from there as follows - everything needs to be on one line. You will need to adjust the 3 paths in the following to reflect the locations in your setup. This will get you by until a more permanent solution is available from MD.

    "C:\Program Files\Moneydance\jre\bin\java" -cp "C:\Program Files\Moneydance\lib\*" --module-path "C:\Program Files\Java\javafx-sdk-14.0.2.1\lib" --add-modules=javafx.swing,javafx.controls,javafx.graphics,javafx.fxml -Dsun.java2d.dpiaware=true -Xmx2048m com.moneydance.apps.md.controller.Main
    

Reply to this discussion

Internal reply

Formatting help / Preview (switch to plain text) No formatting (switch to Markdown)

Attaching KB article:

»

Attached Files

You can attach files up to 10MB

If you don't have an account yet, we need to confirm you're human and not a machine trying to post spam.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac