简体   繁体   中英

View Injection in FXML

@Override
    public void start(Stage stage) throws Exception {
        

BorderPane root = FXMLLoader.load(getClass().getClassLoader().getResource("mainView.fxml"));

When i run this it doesnt show the injected views

Im building a new application with JavaFX for the main page im using 3 views build by 3 fxml files each view has its controller. for the main page i want to inject the three fxml files in a mainView.fxml via fx:include the mainView.fxml has also a controller how can i do that?

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.text.Font?>

<fx:root alignment="CENTER_LEFT" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="93.0" prefWidth="600.0" style="-fx-min-width: 800; -fx-min-height: 100; -fx-spacing: 30;" type="javafx.scene.layout.HBox" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Label fx:id="title" alignment="CENTER" prefHeight="91.0" prefWidth="179.0" style="-fx-label-padding: 20; -fx-line-spacing: 20;" text="News" textFill="#00a4f2">
         <font>
            <Font name="Arial Black" size="36.0" />
         </font>
         <opaqueInsets>
            <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
         </opaqueInsets></Label>
      <Button fx:id="refresh" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" style="-fx-alignment: CENTER; -fx-background-color: #66a6ff;" text="Button" textAlignment="CENTER">
         <opaqueInsets>
            <Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
         </opaqueInsets></Button>
      <Button fx:id="stat" alignment="CENTER" mnemonicParsing="false" style="-fx-background-color: #feada6;" text="Button">
         <opaqueInsets>
            <Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
         </opaqueInsets></Button>
   </children>
</fx:root>

This is per example the topView.fxml

package ch.bfh.spacenews;

import java.io.IOException;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;

public class TopBarController extends HBox {

    @FXML
    public Label title;
    @FXML
    public Button refresh;
    @FXML
    public Button stat;
    
    TopBarController(){
        FXMLLoader load = new FXMLLoader(getClass().getClassLoader().getResource("topView.fxml"));
        load.setRoot(this);
        load.setController(this);
        try {
            System.out.println("TopBarController");
            load.load();
        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

This is the corresponding controller of the topView.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>


<BorderPane fx:controller="ch.bfh.spacenews.mainController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
   <top>
      <fx:include fx:id="topBar" source="topView.fxml"/>
   </top>
   
   <center>
    <fx:include fx:id="article" source="sample.fxml"/>
   </center>
   
   <right>
      <fx:include fx:id="seacrh" source="searchView.fxml"/>  
   </right>
</BorderPane>

This is where i want to inject the topView.fxml

package ch.bfh.spacenews;


import javafx.fxml.FXML;



public class mainController {
    
    @FXML
    TopBarController topBarController;
    @FXML
    ArticleController articleController;
    @FXML
    SearchController searchController;
    
    @FXML
    public void initialize() {
        
    }

}

And this is the Controller of the mainView.fxml where i want to inject the topView.fxml

In the FXML custom component pattern the controller classes also serve as the wrapper for the view, by subclassing an appropriate Node subclass. This means you can just instantiate them directly in the FXML via the FXMLLoader . For example, the <TopBarController> element instructs the FXMLLoader to instantiate the TopBarController by calling its no-argument constructor. That constructor, as per your code, loads topView.fxml , etc. There is no need to use <fx:include> , which is an instruction for the FXMLLoader to load another FXML file, since you already have code in your TopBarController to do that.

So your main view FXML file should look like:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>

<?import ch.bfh.spacenews.TopBarController?>
<!-- other imports... -->


<BorderPane fx:controller="ch.bfh.spacenews.MainController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
   <top>
      <TopBarController fx:id="topBar" />
   </top>
   
   <center>
    <ArticleController fx:id="article" />
   </center>
   
   <right>
      <SearchController fx:id="search" />  
   </right>
</BorderPane>

And the corresponding controller is

package ch.bfh.spacenews;


import javafx.fxml.FXML;



public class MainController {
    
    @FXML
    TopBarController topBar;
    @FXML
    ArticleController article;
    @FXML
    SearchController search;
    
    @FXML
    public void initialize() {
        
    }

}

Note that it's really critical to follow standard naming conventions here. The FXMLLoader explicitly relies on the case of an element to determine if it's referring to a class name or a property name.

Main class: Launch.java

public class Launch extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Controller.show(stage);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

You can add view from controller:

public class Controller {
    public BorderPane mainPane; // fx:id of your pane
    public static Stage current;

    public static void show(Stage stage) {
        this.current = stage;
        Scene scene = null;
        BorderPane pane = null;
        try {
            scene = new Scene(FXMLLoader.load(getClass().getResource("mainView.fxml")));
            pane = (BorderPane) scene.lookup("#mainPane");

            // Add .fxml view to mainView
            pane.setCenter(FXMLLoader.load(getClass().getResource("sample.fxml")));
            pane.setTop(FXMLLoader.load(getClass().getResource("topView.fxml")));
            pane.setRight(FXMLLoader.load(getClass().getResource("searchView.fxml")));

        } catch (IOException e) {
            e.printStackTrace();
        }

        stage.setTitle("MainView");
        stage.setScene(scene);
        stage.show();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM