java - 如何获取包含的 FXML 的 Controller ?

标签 java javafx controller fxml

我有一个围绕 JavaFXML 和 scenebuilder 构建的简单的两个选项卡应用程序。这些选项卡目前什么都不做,因为我在尝试加载它们时无法通过空指针异常。

java 和 fxml 文件在 Netbeans 项目中的排列如下:

enter image description here

Main Application:应用主类MainApp.java布景,声明如下:

package tabpane;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;


public class MainApp extends Application {

  private static Stage primaryStage;
  private AnchorPane rootLayout;  


  public MainApp() {}

  @Override
  public void start(Stage primaryStage) {
    primaryStage.initStyle(StageStyle.UNDECORATED);
    MainApp.primaryStage = primaryStage;
    MainApp.primaryStage.setTitle("Account Names");
    initRootLayout();
  }

  public void initRootLayout() {
    try {
      FXMLLoader loader = new FXMLLoader();
      loader.setLocation(MainApp.class.getResource("view/MainView.fxml"));
      rootLayout = (AnchorPane) loader.load(); 
      Scene scene = new Scene(rootLayout);
      primaryStage.setScene(scene);
      primaryStage.show();

    } catch (IOException e) {
        Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, e);
        System.out.println("MainApp: IOException in method: initRootLayout" + e.getMessage());
        System.exit(0);
    }
  }

  public Stage getPrimaryStage() {
    return primaryStage;
  }

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

MainController 类为应用程序声明两个选项卡,输入选项卡和帐户选项卡,以及用于关闭程序的退出按钮。这是主视图。 fxml文件:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tabpane1.view.MainController">
   <children>
      <TabPane fx:id="tabPane" prefHeight="345.0" prefWidth="600.0" style="-fx-background-color: blue;" tabClosingPolicy="UNAVAILABLE">
        <tabs>
          <Tab fx:id="inputTab" closable="false" text="Input">
            <content>
                <fx:include source="InputView.fxml" />
            </content>
          </Tab>
          <Tab fx:id="detailTab" closable="false" text="Detail">
            <content>
               <fx:include source="DetailView.fxml" />
            </content>
          </Tab>
        </tabs>
      </TabPane>
      <Button fx:id="exitBtn" layoutX="529.0" layoutY="355.0" mnemonicParsing="false" onAction="#handleExitBtn" text="Exit" />
   </children>
</AnchorPane>

这是 MainController.java 中包含的主视图的 java Controller 类:

package tabpane1.view;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;

public class MainController implements Initializable    {
    @FXML public TabPane tabPane;
    @FXML public Tab inputTab;
    @FXML public Tab accountTab;
    @FXML private Button exitBtn;

    public DetailController detailController;      
    public InputController inputController;

    @Override
    public void initialize(URL location, ResourceBundle resources) { 
      detailController = new FXMLLoader(getClass().getResource("DetailView.fxml")).getController(); 
//      System.out.println(detailController.getClass());
      inputController = new FXMLLoader(getClass().getResource("InputView.fxml")).getController(); 
//      System.out.println(inputController.getClass());
    }

    @FXML private void handleExitBtn() {
        System.exit(0);
    }
}

这两个 println 语句只是试图获取对两个选项卡(即 detailController 和 inputController)的引用以执行某些操作。然而,当这些被取消注释并运行时,输出以下转储:

MainApp: IOException in method: initRootLayout
SEVERE: null
file:/G:/J2EE/TabPane_1/dist/run1314937364/TabPane_1.jar!/tabpane1/view/MainView.fxml
javafx.fxml.LoadException: 

file:/G:/J2EE/TabPane_1/dist/run1314937364/TabPane_1.jar!/tabpane1/view/MainView.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at tabpane1.MainApp.initRootLayout(MainApp.java:43)
    at tabpane1.MainApp.start(MainApp.java:33)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
    at tabpane1.view.MainController.initialize(MainController.java:24)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
    ... 13 more

当 printlns 被注释掉时,结果如预期的那样,即正确显示选项卡 Pane : Fig 2

如前所述,细节和输入 Controller 是空的,但为了完整起见,它们如下所示:

输入 View .fxml:

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

<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tabpane1.view.InputController">

</AnchorPane>

Controller InputController.java:

package tabpane1.view;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;

public class InputController implements Initializable   {

  @Override
  public void initialize(URL location, ResourceBundle resources) {}  
}

详细 View .fxml:

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

<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" style="-fx-background-color: transparent;" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tabpane1.view.DetailController" />

Controller DetailController.java:

package tabpane1.view;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;

public class InputController implements Initializable   {

  @Override
  public void initialize(URL location, ResourceBundle resources) {}  
}

最佳答案

this article 中描述了获取对嵌入式FXML Controller 的引用的方法。 .

您只需为包含的资源提供一个fx:id:

   <fx:include fx:id="IncludedView" source="InputView.fxml" />

MainController 中获取对 IncludedView 的引用:

@FXML private Parent IncludedView;

除了嵌入元素的变量名之外,只需附加单词 Controller 即可获取对其 Controller 的引用:

@FXML private InputController IncludedViewController;

就是这样。

测试它:

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;

public class MainController implements Initializable    {

    @FXML private Parent IncludedView;
    @FXML private InputController IncludedViewController; // $IncludedView;+Controller

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        System.out.println(IncludedView.getClass());
        System.out.println(IncludedViewController.getClass()    );
    }

    @FXML private void handleExitBtn() {
        System.exit(0);
    }
}

An MRE for the sake of future readers:


import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class GetEmbeddedController extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {
            Pane root = (Pane) FXMLLoader.load(getClass().getResource("MainView.fxml"));
            primaryStage.setScene(new Scene(root));
            primaryStage.show();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

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

MainView.fxml

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.1" 
  xmlns:fx="http://javafx.com/fxml/1" fx:controller="MainController">
   <children>  
      <fx:include fx:id="includedView" source="IncludedView.fxml" />         
      <Button layoutX="401.0" layoutY="354.0" onAction="#handleTestBtn" text="Test Included Controller" />
   </children>
</AnchorPane>

主 Controller .java

import javafx.fxml.FXML;
import javafx.scene.Parent;

public class MainController{

    @FXML private Parent includedView; //not used in this demo
    /*
     * Get a reference to IncludedView controller simply by appending
     * the word Controller in addition to the variable name of the embedded
     * element:$IncludedView;+Controller
     */
    @FXML private IncludedViewController includedViewController;

    @FXML private void handleTestBtn() {
        includedViewController.showAlert();
    }
}

IncludedView.fxml

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

<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Text?>

<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.1" 
xmlns:fx="http://javafx.com/fxml/1" fx:controller="IncludedViewController">
   <children>
      <Text layoutX="277.0" layoutY="196.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Included Fxml" />
   </children>
</AnchorPane>

IncludedViewController.java

import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;

public class IncludedViewController{

    void showAlert(){
        Alert alert = new Alert(AlertType.INFORMATION);
        alert.setContentText("Alert invoked by IncludedViewController ");
        alert.show();
    }
}

关于java - 如何获取包含的 FXML 的 Controller ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59551896/

相关文章:

java - 为什么此代码不生成随机代码?

java - 将 ComboBox#itemsProperty 绑定(bind)到 Map#keySet

css - 为什么这个组合框的底部有一行?

grails - grails:findallbyidinlist方法

javascript - 如何删除 Controller 先前实例的功能?

Java静态枚举方法返回默认枚举值

java - 远程调试器挂起最新版本的 IntelliJ IDEA 2018.3

javafx - FXML:绑定(bind)到 Controller

ruby-on-rails - 如果我调用 Factory.build 以使我的 Controller 测试快速,我怎样才能让 Factory Girl 永远不会访问数据库?

java - 在java中从parse.com转换时间戳