【问题标题】:View Injection in FXML在 FXML 中查看注入
【发布时间】:2021-08-12 03:41:55
【问题描述】:
@Override
    public void start(Stage stage) throws Exception {
        

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

当我运行它时,它不会显示注入的视图

我正在使用 JavaFX 为主页构建一个新应用程序,我使用由 3 个 fxml 文件构建的 3 个视图 每个视图都有它的控制器。对于主页,我想通过 fx:include 将三个 fxml 文件注入 mainView.fxml 中,mainView.fxml 还有一个控制器,我该怎么做?

<?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>

这是每个示例的 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();
        }
    }
}

这是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>

这是我要注入 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() {
        
    }

}

这是我要注入 topView.fxml 的 mainView.fxml 的控制器

【问题讨论】:

标签: java user-interface javafx fxml


【解决方案1】:

主类: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);
    }
}

您可以从控制器添加视图:

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

【讨论】:

    【解决方案2】:

    FXML custom component pattern 中,控制器类还充当视图的包装器,通过子类化适当的Node 子类。这意味着您可以通过 FXMLLoader 在 FXML 中直接实例化它们。例如,&lt;TopBarController&gt; 元素通过调用其无参数构造函数来指示FXMLLoader 实例化TopBarController。该构造函数根据您的代码加载topView.fxml 等。无需使用&lt;fx:include&gt;,这是FXMLLoader 加载另一个FXML 文件的指令,因为您的TopBarController 中已有代码这样做。

    所以您的主视图 FXML 文件应如下所示:

    <?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>
    

    而对应的控制器是

    package ch.bfh.spacenews;
    
    
    import javafx.fxml.FXML;
    
    
    
    public class MainController {
        
        @FXML
        TopBarController topBar;
        @FXML
        ArticleController article;
        @FXML
        SearchController search;
        
        @FXML
        public void initialize() {
            
        }
    
    }
    

    请注意,在此处遵循标准命名约定非常重要。 FXMLLoader 明确依赖元素的大小写来确定它是指类名还是属性名。

    【讨论】:

    • 是的,一次又一次地发生在我们身上,这就是让我咯咯笑的原因:)谢谢
    • 感谢@James_D 的回答,现在我明白了