Gluon Afterburner getPresenter() 仅返回 NoSuchElementException:不存在任何值

发布于 2025-01-18 12:02:18 字数 6428 浏览 5 评论 0原文

我使用 Glisten Afterburner (v2.1.0) 从 Gluon Start 生成一个简单的应用程序。这会生成三个类,其中两个是 Main 和 AppViewManager,使用 glisten.afterburner AppView 和 AppViewRegistry。我向生成的代码添加了一个附加视图(“其他”),并向 AppViewManager 添加了方法以获取与视图关联的 Presenter。

生成的 Main 类如下所示,我在其中添加了获取 Presenters 的静态调用: getMainPresenter() 和 getOtherPresenter():

public class Main extends Application {
    private final AppManager appManager = AppManager.initialize(this::postInit);

    @Override
    public void init() {
        AppViewManager.registerViewsAndDrawer();
    }

    @Override
    public void start(Stage stage) {
        appManager.start(stage);
    }

    private void postInit(Scene scene) {
    :
       // Get Main Presenter
       AppViewManager.getMainPresenter();
       // Get Other Presenter
       AppViewManager.getOtherPresenter();
    }
    :
}

AppViewManager 如下所示,我添加了附加视图(“其他”)并添加了获取 Presenters 的方法与视图相关联。在注册视图时,我添加了一些输出来查看发生了什么:

public class AppViewManager {
    private static final AppViewRegistry REGISTRY = new AppViewRegistry();

    public static final AppView MAIN_VIEW = view("Home", MainPresenter.class, MaterialDesignIcon.HOME, SHOW_IN_DRAWER, HOME_VIEW, SKIP_VIEW_STACK);
    public static final AppView OTHER_VIEW = view("Other", OtherPresenter.class, MaterialDesignIcon.NOTE, SHOW_IN_DRAWER, SKIP_VIEW_STACK);

    private static AppView view(String title, Class<?> presenterClass, MaterialDesignIcon menuIcon, AppView.Flag... flags ) {
        return REGISTRY.createView(name(presenterClass), title, presenterClass, menuIcon, flags);
    }

    private static String name(Class<?> presenterClass) {
        return presenterClass.getSimpleName().toUpperCase(Locale.ROOT).replace("PRESENTER", "");
    }

    public static void registerViewsAndDrawer()
    {
        for (AppView view : REGISTRY.getViews())
        {
            // What's in the REGISTRY?
            System.out.println("==> View: " +view.getId()+ ", Presenter: " +view.getPresenterClass().getCanonicalName());
            // Not sure what the following does, the javadoc is blank!
            view.registerView();
        }
    :
    }
    
    /**
     * Get MainPresenter.
     * See: .../AppViewRegistry.html#getPresenter(com.gluonhq.charm.glisten.afterburner.AppView)
     */
    public static void getMainPresenter()
    {
        MainPresenter mp = (MainPresenter)MAIN_VIEW.getPresenter().get();
        System.out.println("..Presenter..> " +mp.toString());
    }
    
    public static void getOtherPresenter()
    {
        OtherPresenter op = (OtherPresenter)OTHER_VIEW.getPresenter().get();
        System.out.println("..OtherPresenter..> " +op.toString());
    }
}

OtherPresenter 是一个简单的声明:

public class OtherPresenter {
    public void initialize() {}
}

OtherPresenter FXML 是:

<View fx:id="other" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.runtheworld.sample.OtherPresenter">
    <center>
        <VBox styleClass="box">
            <children>
                <Label text="Other!" />
            </children>
        </VBox>
    </center>
</View>

REGISTRY 输出中的内容符合预期(除了我期望的是“HOME_VIEW”而不是“home”):

==> View: home, Presenter: com.runtheworld.sample.MainPresenter
==> View: OTHER_VIEW, Presenter: com.runtheworld.sample.OtherPresenter

但无论我在哪里进行 getOtherPresenter() 调用,它都会返回:“Caused by: java.util.NoSuchElementException: No value present”。然而, getMainPresenter() 调用是有效的。事实上,该应用程序可以正常运行,显示 OtherPresenter(显示“其他!”),但仍然抛出“无值”。

为什么 Main 工作但其他不工作,是否有一些我错过的设置/初始化?

这是所有输出:

==> View: home, Presenter: com.runtheworld.sample.MainPresenter
==> View: OTHER_VIEW, Presenter: com.runtheworld.sample.OtherPresenter
Apr 03, 2022 11:24:16 AM com.gluonhq.attach.util.Platform <clinit>
INFO: [Gluon Attach] System Property javafx.platform is not defined. Platform will be set to Platform.DESKTOP
..MainPresenter..> com.runtheworld.sample.MainPresenter@686bbb76
java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.get(Optional.java:143)
    at com.runtheworld.sample.AppViewManager.getOtherPresenter(AppViewManager.java:54)
    at com.runtheworld.sample.Main.postInit(Main.java:41)
    at com.gluonhq.charm.glisten.application.AppManager.continueInit(AppManager.java:328)
    at com.gluonhq.charm.glisten.application.AppManager.start(AppManager.java:288)
    at com.runtheworld.sample.Main.start(Main.java:24)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:290)
    at java.base/java.lang.Thread.run(Thread.java:833)

编辑: 我决定避开 afterburner,简单地构建一个视图,如下所示:

public class OtherView {
    public static final String OTHER_VIEW = "OTHER_VIEW";
    
    public AbstractMap.SimpleEntry<String,AbstractMap.SimpleEntry<View,Presenter>> getViewController() {
        try {
            FXMLLoader f = new FXMLLoader(OtherView.class.getResource("/path/to/other.fxml"), ResourceBundle.getBundle("path.to.other"));
            View view = f.load();
            
            OtherPresenter controller = f.getController();
            return new AbstractMap.SimpleEntry(OTHER_VIEW,new AbstractMap.SimpleEntry(view,controller));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

视图和控制器在 FXML 中定义,这将视图名称与视图及其关联的控制器联系起来。 getViewController() 是从 Main.init() 调用的。

I generate a simple app from Gluon Start with Glisten Afterburner (v2.1.0). This generates three classes of which two are Main and AppViewManager using glisten.afterburner AppView and AppViewRegistry. I add an additional View to the generated code ("Other") and I add methods to AppViewManager to get the Presenter associated with a View.

The generated Main class looks like the following to which I have added the static calls to get Presenters: getMainPresenter() and getOtherPresenter():

public class Main extends Application {
    private final AppManager appManager = AppManager.initialize(this::postInit);

    @Override
    public void init() {
        AppViewManager.registerViewsAndDrawer();
    }

    @Override
    public void start(Stage stage) {
        appManager.start(stage);
    }

    private void postInit(Scene scene) {
    :
       // Get Main Presenter
       AppViewManager.getMainPresenter();
       // Get Other Presenter
       AppViewManager.getOtherPresenter();
    }
    :
}

AppViewManager looks like the following where I added the additional View ("Other") and added methods to get Presenters associated with Views. In registering Views, I added some output to see what is going on:

public class AppViewManager {
    private static final AppViewRegistry REGISTRY = new AppViewRegistry();

    public static final AppView MAIN_VIEW = view("Home", MainPresenter.class, MaterialDesignIcon.HOME, SHOW_IN_DRAWER, HOME_VIEW, SKIP_VIEW_STACK);
    public static final AppView OTHER_VIEW = view("Other", OtherPresenter.class, MaterialDesignIcon.NOTE, SHOW_IN_DRAWER, SKIP_VIEW_STACK);

    private static AppView view(String title, Class<?> presenterClass, MaterialDesignIcon menuIcon, AppView.Flag... flags ) {
        return REGISTRY.createView(name(presenterClass), title, presenterClass, menuIcon, flags);
    }

    private static String name(Class<?> presenterClass) {
        return presenterClass.getSimpleName().toUpperCase(Locale.ROOT).replace("PRESENTER", "");
    }

    public static void registerViewsAndDrawer()
    {
        for (AppView view : REGISTRY.getViews())
        {
            // What's in the REGISTRY?
            System.out.println("==> View: " +view.getId()+ ", Presenter: " +view.getPresenterClass().getCanonicalName());
            // Not sure what the following does, the javadoc is blank!
            view.registerView();
        }
    :
    }
    
    /**
     * Get MainPresenter.
     * See: .../AppViewRegistry.html#getPresenter(com.gluonhq.charm.glisten.afterburner.AppView)
     */
    public static void getMainPresenter()
    {
        MainPresenter mp = (MainPresenter)MAIN_VIEW.getPresenter().get();
        System.out.println("..Presenter..> " +mp.toString());
    }
    
    public static void getOtherPresenter()
    {
        OtherPresenter op = (OtherPresenter)OTHER_VIEW.getPresenter().get();
        System.out.println("..OtherPresenter..> " +op.toString());
    }
}

OtherPresenter is a simple declaration:

public class OtherPresenter {
    public void initialize() {}
}

The OtherPresenter FXML is:

<View fx:id="other" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.runtheworld.sample.OtherPresenter">
    <center>
        <VBox styleClass="box">
            <children>
                <Label text="Other!" />
            </children>
        </VBox>
    </center>
</View>

What's in the REGISTRY output is as expected (except I would have expected 'HOME_VIEW' rather than 'home'):

==> View: home, Presenter: com.runtheworld.sample.MainPresenter
==> View: OTHER_VIEW, Presenter: com.runtheworld.sample.OtherPresenter

But no matter where I make the getOtherPresenter() call, it returns: "Caused by: java.util.NoSuchElementException: No value present". The getMainPresenter() call, however, works. In fact, the app functions, showing OtherPresenter (displaying "Other!") but still throwing "No value".

Why does Main work but not Other, is there some setup/init I have missed?

Here's all the output:

==> View: home, Presenter: com.runtheworld.sample.MainPresenter
==> View: OTHER_VIEW, Presenter: com.runtheworld.sample.OtherPresenter
Apr 03, 2022 11:24:16 AM com.gluonhq.attach.util.Platform <clinit>
INFO: [Gluon Attach] System Property javafx.platform is not defined. Platform will be set to Platform.DESKTOP
..MainPresenter..> com.runtheworld.sample.MainPresenter@686bbb76
java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.get(Optional.java:143)
    at com.runtheworld.sample.AppViewManager.getOtherPresenter(AppViewManager.java:54)
    at com.runtheworld.sample.Main.postInit(Main.java:41)
    at com.gluonhq.charm.glisten.application.AppManager.continueInit(AppManager.java:328)
    at com.gluonhq.charm.glisten.application.AppManager.start(AppManager.java:288)
    at com.runtheworld.sample.Main.start(Main.java:24)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:290)
    at java.base/java.lang.Thread.run(Thread.java:833)

EDIT:
I decided to eschew afterburner and simply built a View as follows:

public class OtherView {
    public static final String OTHER_VIEW = "OTHER_VIEW";
    
    public AbstractMap.SimpleEntry<String,AbstractMap.SimpleEntry<View,Presenter>> getViewController() {
        try {
            FXMLLoader f = new FXMLLoader(OtherView.class.getResource("/path/to/other.fxml"), ResourceBundle.getBundle("path.to.other"));
            View view = f.load();
            
            OtherPresenter controller = f.getController();
            return new AbstractMap.SimpleEntry(OTHER_VIEW,new AbstractMap.SimpleEntry(view,controller));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

The View and Controller are defined in the FXML and this ties the View name to the View and its associated Controller. getViewController() is called from Main.init().

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文