如何获取包含的FXML的控制器? [英] How to get the controller of an included FXML?

查看:92
本文介绍了如何获取包含的FXML的控制器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个围绕JavaFXML和scenebuilder构建的简单的两个选项卡应用程序。这些选项卡目前不起作用,因为尝试加载它们时我无法克服nullpointer异常。

I have a simple two tab application build around JavaFXML and scenebuilder. The tabs do nothing at present because I cannot get past a nullpointer exception when trying to load them.

Java和fxml文件在Netbeans项目中的排列方式如下:

The java and fxml files are arranged in a Netbeans project like this:

主应用程序:应用程序主类MainApp。 java设置场景并声明如下:

Main Application: The application main class MainApp.java sets the scene and is declared as follows:

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类声明了两个选项卡,即Input选项卡应用程序的帐户标签和用于关闭程序的退出按钮。这是MainView。 fxml文件:

The MainController class declares the two tabs, the Input tab and Account tab, for the application and an exit button for closing the program. This is the MainView. fxml file:

<?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控制器类:

This is the java controller class for the main view contained in MainController.java:

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,以执行某些操作。但是,当这些注释取消注释并运行时,将输出以下转储:

The two println statements are simply trying to get the references to the two tabs, which are detailController and inputController, to do something. However, when these are uncommented and run, the following dump is output:

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被注释掉时,结果符合预期,即正确显示了选项卡窗格:

When the printlns are commented out, the outcome is as expected, that is the tab pane is correctly displayed:

如前所述,详细信息和输入控制器为空,但出于完整性考虑,它们是如下所示:

As mentioned the detail and input controllers are empty, but for completeness they are as follows:

InputView.fxml:

InputView.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>

控制器InputController.java:

The 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) {}  
}

DetailView.fxml:

DetailView.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" />

控制器DetailController.java:

The 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) {}  
}


推荐答案

获取对嵌入式FXML -nested-controllers / rel = nofollow noreferrer>这篇文章。

The way to get reference to the controller of an embedded FXML is described in this article.

您只需给出 fx:id 到包含的资源:

You simply have to give an fx:id to the included resource:

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

在<<中获取对 IncludedView 的引用code> MainController :

Get a reference to IncludedView in the MainController:

@FXML private Parent IncludedView;

只需在嵌入式变量名称后附加控制器一词即可获得对其控制器的引用元素:

Get a reference to its controller simply by appending the word Controller in addition to the variable name of the embedded element:

@FXML private InputController IncludedViewController;

仅此而已。

That is all.

使用以下命令进行测试:

Test it with:

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








为将来的读者起见, MRE







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>

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

这篇关于如何获取包含的FXML的控制器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆