如何从字符串动态加载fxml文档并从字符串编译/实例化其控制器

时间:2019-03-24 21:26:05

标签: javafx fxml fxmlloader dynamic-class-loaders

我想构建一个javafx应用程序,其中fxml文档及其控制器都存储在数据库中。 多亏了jewelsea,我可以使用以下代码动态加载fxml文档:

String fxmlDocument = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "\n" +
                "<?import javafx.scene.control.Button?>\n" +
                "<?import javafx.scene.layout.BorderPane?>\n" +
                "\n" +
                "\n" +
                "<BorderPane maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"400.0\" prefWidth=\"600.0\" xmlns=\"http://javafx.com/javafx/8.0.171\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"main.ControllerClass\">\n" +
                "   <center>\n" +
                "      <Button fx:id=\"button\" mnemonicParsing=\"false\" onAction=\"#onButtonClicked\" text=\"Button\" BorderPane.alignment=\"CENTER\" />\n" +
                "   </center>\n" +
                "</BorderPane>";

FXMLLoader loader = new FXMLLoader();
BorderPane layout = (BorderPane) loader.load(
  new ByteArrayInputStream(fxmlDocument.getBytes())
);

我的控制器首先存储在ControllerClass.java文件中

package main;

import javafx.scene.control.Button;
import javafx.event.ActionEvent;

public class ControllerClass {
    public Button button;

    public void onButtonClicked(ActionEvent event){
        System.out.println("Button's clicked");
    }
}

效果很好。

但是现在我的控制器存储在一个字符串中,因此我使用此链接[inmemory]:https://github.com/trung/InMemoryJavaCompiler来编译和实例化我的控制器,如下所示:

        StringBuilder fxmlController = new StringBuilder();

        fxmlController.append("package main;\n");
        fxmlController.append("import javafx.scene.control.Button;\n");
        fxmlController.append("import javafx.event.ActionEvent;\n");
        fxmlController.append("import java.util.ArrayList;\n");
        fxmlController.append("import java.util.List;\n");
        fxmlController.append("public class ControllerClass {\n");
        fxmlController.append("   public Button button;\n");
        fxmlController.append("   public void onButtonClicked(ActionEvent event){\n");
        fxmlController.append("     System.out.println(\"ControllerClass called\");");
        fxmlController.append("   }");
        fxmlController.append("   public List<String> test() {");
        fxmlController.append("     List<String> supplierNames = new ArrayList<String>();");
        fxmlController.append("     supplierNames.add(\"sup1\");");
        fxmlController.append("     supplierNames.add(\"sup2\");");
        fxmlController.append("     supplierNames.add(\"sup3\");");
        fxmlController.append("     supplierNames.add(\"sup4\");");
        fxmlController.append("     System.out.println(supplierNames.get(3));");
        fxmlController.append("     return supplierNames;");
        fxmlController.append("   }");
        fxmlController.append("}");
        Class<?> controllerClass = InMemoryJavaCompiler.newInstance().ignoreWarnings().compile("main.ControllerClass", fxmlController.toString());
        List<?> listSize = (List<?>) controllerClass.getMethod("test").invoke(controllerClass.newInstance());
        System.out.println("listSize.size()=" + listSize.size());

运行代码时,结果是:

sup4
res.size()=4

这意味着,如果我将fxml文档和控制器动态编译/实例化/加载在一起时出现错误,则控制器将正确编译并实例化,但是

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$154(LauncherImpl.java:182)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javafx.fxml.LoadException: 
unknown path:7

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:103)
    at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:922)
    at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
    at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
    at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
    at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
    at main.Main.start(Main.java:111)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
    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$147(WinApplication.java:177)
    ... 1 more
Caused by: java.lang.ClassNotFoundException: main.ControllerClass
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:920)
    ... 16 more
Exception running application main.Main

Process finished with exit code 1

问题是:

Caused by: javafx.fxml.LoadException: 
unknown path:7

我做错了什么,因为我的控制器已正确编译/实例化,但FXMLLoader并没有将其确认。 你能帮忙吗? 预先感谢。

0 个答案:

没有答案