How to create multiple javafx controllers with different fxml files?
Asked Answered
L

4

31

I've been looking at some blogs and other stackoverflow questions, and I'm not seeing a direct answer to my question. I am creating a javafx gui client and I want to have my menubar be one controller in one fxml and then i want the content area to be additional fxml files. The login screen will be one fxml, after the login screen will be the main content of the application and that will be in one fxml. How do i go about doing this?

I just don't want to have all of my code for my login, menubar, and main content in the same file. This is an image of what i am working on:

enter image description here

Listed answered 13/10, 2013 at 5:38 Comment(2)
Some sample code using concepts from some of the question answers.Tamie
Another example here: linkSuperconductivity
F
36

Use FXML as components by using a custom java class as fx:root and as fx:controller of your FXML file: http://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm

To do so, you need to call in the constructor of your custom java class FXMLLoader which will load your FXML. The advantage is to change the way FXML load components.

The classic way to instanciate components via FXMLLoader with nested controllers is: FXML first, then controller for each part.

With this technique this is: controller first, then FXML for each component. And you won't load FXML in FXML directly, you will import your custom java classes in the FXML.

This is a better abstraction (no need to know how a component is implemented when you import them in FXML) and helps reusing code as it is like implementing a custom widget with FXML support. To make your component reusable, make sure your implementation doesn't have tight coupling with other parts, or use IOC to do so (for instance, with Spring integration with JavaFX). This way, you will be able to import your component in any part of your application (just like a DateInput widget) without worry and you won't duplicate code.

In your case you will have:

public class MenuBox extends VBox {

@FXML
private LoginBox loginBox;

@FXML
private ProfilesBox profilesBox;

public MenuBox() {
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("menu.fxml"));
    fxmlLoader.setRoot(this);
    fxmlLoader.setController(this);
    try {
        fxmlLoader.load();
    } catch (IOException exception) {
        throw new RuntimeException(exception);
    }
}

public class LoginBox extends VBox {
public LoginBox() {
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("login.fxml"));
    fxmlLoader.setRoot(this);
    fxmlLoader.setController(this);
    try {
        fxmlLoader.load();
    } catch (IOException exception) {
        throw new RuntimeException(exception);
    }
}

public class ProfilesBox extends VBox {
public ProfilesBox() {
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("profiles.fxml"));
    fxmlLoader.setRoot(this);
    fxmlLoader.setController(this);
    try {
        fxmlLoader.load();
    } catch (IOException exception) {
        throw new RuntimeException(exception);
    }
}

And you will import LoginBox and ProfilesBox in menu.fxml that manages the global layout for your page:

<?import com.foo.bar.LoginBox ?>
<?import com.foo.bar.ProfilesBox ?>
<fx:root type="javafx.scene.layout.VBox"
    xmlns:fx="http://javafx.com/fxml">

<!-- Stuff here to declare the menu bar-->

    <HBox>
       <ProfilesBox fx:id="profilesBox"/>
       <LoginBox fx:id="loginBox"/>
    </HBox>

</fx:root>

login.fxml and profiles.fxml contain just basic components.

Flammable answered 13/10, 2013 at 6:18 Comment(4)
I kind of understand what your saying, I just don't think I'm getting the full picture. Do you have any more elaborate examples?Listed
And it's okay to create your own widgets (i.e. ProfilesBox & LoginBox) and place them in the fxml file? And what do the login.fxml and profiles.fxml look like?Listed
To add to already fine example, you just need to make sure that you import your custom control into the FXML. E.g. <?import com.foo.bar.LoginBox ?>.Weird
In addition to this answer, this article helped: javacodegeeks.com/2013/03/javafx-2-with-spring.htmlListed
A
5
  1. You can include FXML documents one within the other - this should help you with separating the design logic

  2. This means you can have Nested Controllers - one for each document.

From the documentation, you can now setup your code such that logic can be separated as well as invoked from the root controller (if need be).

Hope that helps.

Accompanist answered 13/10, 2013 at 5:53 Comment(1)
I've looked at the Nested Controllers documentation, and if I could see what is in the include fxml, what is in the main controllers initialize method, and what the dialog controller looks like, i think that would be super helpful. I just don't see how the fine details are working.Listed
T
1

I needed a popup window with similar requirements (more control over the nodes and the layout).

Having worked my way through the recommendations, I found a solution that might be useful.

First, I created a second fxml document and second controller (in NetBeans, New -> Empty FXML ... -> Use Java Controller -> Create New ...).

A little challenging was to figure out how to build the stage in the main controller and connect it to the popup controller.

The link Passing Parameters JavaFX FXML gives some real good insights and techniques.

The final code looks like this (I hope it can help someone):

// Anchor Pane from the popup
@FXML
AnchorPane anchorPanePopup;

@FXML
private void soneButtonAction(ActionEvent event) throws IOException {     
    Stage newStage = new Stage();
    AnchorPane anchorPanePopup = (AnchorPane) FXMLLoader.load(getClass().getResource("Popup_FXML.fxml"));
    Scene scene = new Scene(anchorPanePopup);
    newStage.setScene(scene);
    newStage.initModality(Modality.APPLICATION_MODAL);
    newStage.setTitle("Dialog Window");
    newStage.showAndWait();        
}
Tineid answered 29/12, 2016 at 22:6 Comment(0)
V
0
package javafxapplication11;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.stage.Stage;

public class FXMLDocumentController implements Initializable {
@FXML
private CheckBox c1;

@FXML
private CheckBox c2;

public void clicked1(ActionEvent e) throws IOException {
Parent home_page_parent 
=FXMLLoader.load(getClass().getResource("AddDcuFXML.fxml"));
 Scene home_page_scene = new Scene(home_page_parent);
 Stage app_stage = (Stage) ((Node) e.getSource()).getScene().getWindow();
  app_stage.hide(); //optional
  app_stage.setScene(home_page_scene);
  app_stage.show();
   }
   public void clicked2(ActionEvent e) throws IOException {
   Parent home_page_parent 
    =FXMLLoader.load(getClass().getResource("ViewDCU.fxml"));
   Scene home_page_scene = new Scene(home_page_parent);
   Stage app_stage = (Stage) ((Node) e.getSource()).getScene().getWindow();
    app_stage.hide(); //optional
      app_stage.setScene(home_page_scene);
         app_stage.show();
     }
      public void clicked3(ActionEvent e) throws IOException {
     Parent home_page_parent 
   =FXMLLoader.load(getClass().getResource("ViewDCU.fxml"));
    Scene home_page_scene = new Scene(home_page_parent);
    Stage app_stage = (Stage) ((Node) e.getSource()).getScene().getWindow();
     app_stage.hide(); //optional
     app_stage.setScene(home_page_scene);
     app_stage.show();
      }
     @Override
       public void initialize(URL arg0, ResourceBundle arg1) {
        // TODO Auto-generated method stub
           } 
               }
Vo answered 12/3, 2018 at 0:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.