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

时间:2015-07-16 14:50:53

标签: java javafx guice

我有一个使用SceneBuilder创建的JavaFx项目。 我也在使用Guice插件架构。 我有一个.fxml文件,其中有一个窗格,我想成为另一个.fxml文件的内容。 有没有简单的方法将.fxml内容从一个文件链接到另一个文件? 我之前没有使用过fx.guice插件架构。使用插件控件有更简单的方法吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

This was a big problem for us since we also are using Guice and JavaFX.

tl;dr I've attached some code at the bottom that we've been using for a year and a bit now without issue.

edit: I should've mentioned we did all this stuff before fx,guice existed, so this exists entirely outside that, and I probably should be using it.

Yes, but you will have to modify the view tree from java, and you must instantiate two controllers. If you're willing to let the fxml loader instantiate your controllers (we're not, more in a sec), then you simply need to have code along the lines of

solution 1:

span:hover:after {
    color:red;
}

which isn't nice because it means the FX loader will try to create your controller for you, but you probably want guice to do that

luckily you can call 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); } (or setController) to leverage guice, so now we have

solution 2:

setControllerFactory

which is better but requires a 3rd party to load your components. What you really want, a le dependency-injection, is to have the child view be resolved first and as part of the resolution of the parent view.

For us, this brings us to

Solution 3:

@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);
}

And finally, in the name of 'convention over configuration', we created a few classes (attached below) that attempt to 'automatically' find the view by reflecting on the controllers name (eg 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); ) and assuming that it will find an FXML view view in the same directory as the controller's class file with the word OuterController replaced with controller (eg OuterView.fxml)). We also leveraged a neat trick in super-ctor-order in java to allow us to have pre-setup FXML values.

So now we get:

solution4 :

view

you can get the source code for the PreloadedFX and View-By-Convention code here: https://gist.github.com/Groostav/ff35eb2d19b348f2e25c

which is as elegant as I've been able to make this particular union of frameworks.

Hope that helps!