java - 链接来自不同 fxml 文件的内容

标签 java javafx guice

我有一个使用 SceneBuilder 创建的 JavaFx 项目。 我也在使用 Guice 插件架构。 我有一个 .fxml 文件,其中有一个 Pane ,我想将其作为另一个 .fxml 文件的内容。 有什么简单的方法可以将 .fxml 内容从一个文件链接到另一个文件? 我以前没有使用过 fx.guice 插件架构。使用插件控制是否有更简单的方法?

谢谢!!

最佳答案

这对我们来说是个大问题,因为我们还使用 Guice 和 JavaFX。

tl;dr 我在底部附加了一些代码,我们已经使用了一年多了,现在没有问题。

编辑:我应该提到我们在 fx、guice 存在之前就做了所有这些事情,所以它完全存在于它之外,我可能应该使用它。

是的,但是你必须从 java 修改 View 树,并且你必须实例化两个 Controller 。如果您愿意让 fxml 加载器实例化您的 Controller (我们不是,稍后会更多),那么您只需要按照以下行编写代码

解决方案一:

loadMergedView(){
    fxmlLoader.setLocation(getClass().getResource("/com/yourpkg/YourOuterView.fxml"));   
    Pane outerRoot = fxmlLoader.load();

    fxmlLoader.setLocation(getClass().getResource("/com/yourpkg/YourInnerView.fxml"));
    Pane innerView = fxmlLoader.load();

    ((Region)outerRoot.getChildren().get(2))...getChildren().add(innerView);
}

这不太好,因为这意味着 FX 加载器将尝试为您创建 Controller ,但您可能希望 guice 这样做

幸运的是,您可以调用 setController(或 setControllerFactory)来利用 guice,所以现在我们有

解决方案2:

@Inject private OuterController outerController
@Inject private InnerController innerController

loadMergedView(){
    fxmlLoader.setLocation(getClass().getResource("/com/yourpkg/YourOuterView.fxml"));   
    //using the setControllerFactory instead of the setController 
    //means you can still declare the controller type in FXML
    //which is good for our IDE intelliJ and general readability
    fxmlLoader.setControllerFactory(() -> outerController);
    Pane outerRoot = fxmlLoader.load();

    fxmlLoader.setLocation(getClass().getResource("/com/yourpkg/YourInnerView.fxml"));
    fxmlLoader.setControllerFactory(() -> innerController);
    Pane innerView = fxmlLoader.load();

    ((Region)outerRoot.getChildren().get(2))...getChildren().add(innerView);
}

哪个更好,但需要第 3 方来加载您的组件。您真正想要的,即依赖注入(inject),是首先解析 subview ,并将其作为父 View 解析的一部分。

对我们来说,这将我们带到

解决方案 3:

class OuterController{

    @FXML Pane rootPane;
    @FXML Stuff otherStuffBoundInFXML;
    @FXML AnchorPane innerContactPaneOne;

    @Inject
    public OuterController(InnerController inner, FXMLLoader loader){
    
        loader.setControllerFactory(type -> this);
        loader.setLocation(getClass().getResource("/com/yourpkg/YourOuterView.fxml"));
        loader.load();      
        
        innerContactPaneOne.getChildren().add(inner.getRootView());
        
    }
}

class InnerController{
    
    @FXML Pane innerContentPaneTwo; //this will be a child of PaneOne in OuterController
    @FXML Button otherStuff;
    
    @Inject
    public InnerController(FXMLLoader loader){
        loader.setControllerFactory(type -> this);
        loader.setLocation(getClass().getResource("/com/yourpkg/YourInnerVIew.fxml"));
        loader.load();
    }
    
    public Node getRootView(){
        return innerContentPaneTwo;
    }    
}

//with somebody calling
OuterController rootController = injector.getInstance(OuterController.class);

最后,以“约定优于配置”的名义,我们创建了一些类(附在下面),它们试图通过反射(reflect) Controller 名称(例如 OuterController)来“自动”找到 View ) 并且假设它将在与 Controller 的类文件相同的目录中找到一个 FXML View View ,其中单词 controller 替换为 view(例如外部 View .fxml))。我们还在 java 中利用 super 构造函数顺序中的巧妙技巧来允许我们拥有预先设置的 FXML 值。

现在我们得到:

解决方案4:

class OuterController extends PreloadedFX{

    @FXML Pane rootPane;
    @FXML Stuff otherStuffBoundInFXML;
    @FXML AnchorPane innerContactPaneOne;
    @FXML Checkbox importantCheckbox;
    @FXML Label importantLabel;
    
    // because of 'PrealoadedFX' getting called first, 
    // you can actually inline initialize object constants
    // like this
    private final ObservableBooleanValue isSelected = importantCheckbox.selectedProperty();
    
    // or using an initializer
    {
        int x = 4;
        importantLabel.setText(importantLable.getText() + x);
    }

    @Inject
    public OuterController(InnerController inner, FXMLLoader loader){
        super(loader);      
        
        innerContactPaneOne.getChildren().add(inner.getRootView());
        
    }
}

class InnerController extends PreloadedFX{
    
    @FXML Pane innerContentPaneTwo; //this will be a child of PaneOne in OuterController
    @FXML Button otherStuff;
    
    @Inject
    public OuterController(FXMLLoader loader){
        super(loader);
    }
    
    public Node getRootView(){
        return innerContentPaneTwo;
    }    
}

//with somebody calling
OuterController rootController = injector.getInstance(OuterController.class);

您可以在此处获取 PreloadedFX 和 View-By-Convention 代码的源代码: https://gist.github.com/Groostav/ff35eb2d19b348f2e25c

这和我能够创建这个特定的框架联合一样优雅。

希望对您有所帮助!

关于java - 链接来自不同 fxml 文件的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31457638/

相关文章:

java - 在不显示的情况下在 Ubuntu 服务器上部署 JavaFX

java - 从不同的文件夹注入(inject) bean

java - 哪些变量在 JavaFX/Hibernate 应用程序中使用

java - 扩展 guice - guicy 的方式

java - 从字符串解析到日期

java - loadjava 上 Oracle 10g 中的断言失败 Aurora (ORA-29516)

JavaFX : How to manage the z-index of stages

java - 如何仅在截断的单元格上动态设置工具提示

scala - 使用依赖注入(inject)测试带有 SecureSocial 的 Play2 应用程序

java - 使用 Guice 多次绑定(bind)到同一个提供程序实例