【问题标题】:JavaFx nested controllers?JavaFx 嵌套控制器?
【发布时间】:2016-12-08 01:38:54
【问题描述】:

我有一个调用超级构造函数的类。超类加载一个 FXML 包装器布局,然后加载另一个 FXML 布局作为包装器内元素的子级,如下所示:

// Reference 'outer' FXML
URL outer_url = getClass().getResource("/main/resources/fxml/RootNode.fxml");
FXMLLoader outer_loader = new FXMLLoader(outer_url);
outer_loader.setRoot(this);
outer_loader.setController(this);

// Reference 'inner' FXML
URL inner_url = getClass().getResource(fxml_path);
FXMLLoader inner_loader = new FXMLLoader(inner_url);

try {
    outer_loader.load();

    /* The root of inner_loader is a component of outer_loader FXML,
     * thus outer_loader.load() must be called first. */
    inner_loader.setRoot(outer_loader.getNamespace().get("vbox_center"));
    inner_loader.setController(controller);
    inner_loader.load();
} catch (IOException e) {
    e.printStackTrace();
}

我需要这个类成为 inner_loader 的控制器。这可能吗?我尝试通过超级构造函数传递对类的引用,但是在调用超级构造函数之前我无法引用“this”。

有什么想法吗?提前致谢。

编辑:我也尝试通过内部 FXML 文件直接指定控制器,但这会导致问题。

编辑 2:我忘了指定,加载两个 FXML 布局的超类是由多个节点继承的,这就是为什么我不能只创建一个 Controller 的实例并将其直接传递给 inner_loader。我需要(以某种方式)将实例引用传递给超类并将其用作控制器。

【问题讨论】:

  • 我确实看到了这个问题 - 与我的不同之处在于加载 FXML 的超类由多个不同的节点继承,因此需要将实例引用传递给它 - 我不能每次只创建一个新的。
  • “我需要将实例引用传递给超类”:我真的不明白你的意思是什么。当前对象 (this) 当然是它自己的类的实例,因此也是超类的实例。你可以传递this,这会很奇怪,因为你会为两个不同的FXML文件使用同一个对象作为控制器,并且initialize()方法(如果有的话)会被调用两次。
  • 另请注意,无需通过加载程序的命名空间查找vbox_center。由于this 是控制器,此时应该通过@FXML 注入。

标签: java class javafx controller nested


【解决方案1】:

您要做什么并不完全清楚,但您似乎正在尝试使用继承和FXML-based custom components 来创建具有特化的模板。

这是可能的。您可以在构造函数中以通常的方式加载 FXML。因为每个构造函数都会调用它的超类构造函数,所以超类FXML会在子类FXML之前被加载。

项目布局:

模板:

模板.fxml:

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

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.VBox?>

<fx:root xmlns:fx="http://javafx.com/fxml/1" type="BorderPane">
    <top>
        <MenuBar>
            <menus>
                <Menu text="File">
                    <items>
                        <MenuItem text="Quit" onAction="#quit"/>
                    </items>
                </Menu>
            </menus>
        </MenuBar>
    </top>

    <center>
        <VBox fx:id="vboxCenter"/>
    </center>

</fx:root>

组件(Template.java):

package template;

import java.io.IOException;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;

public class Template extends BorderPane {

    @FXML
    private VBox vboxCenter ;

    public Template() throws IOException {
        FXMLLoader loader = new FXMLLoader(Template.class.getResource("Template.fxml"));
        loader.setRoot(this);
        loader.setController(this);
        loader.load();
    }

    protected final VBox getCenterContentHolder() {
        return vboxCenter ;
    }

    @FXML
    private void quit() {
        vboxCenter.getScene().getWindow().hide();
    }
}

专业:

Home.fxml:

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

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.text.Font?>

<fx:root xmlns:fx="http://javafx.com/fxml/1" type="VBox" alignment="CENTER">
    <Label fx:id="welcomeLabel" text="Welcome" />
</fx:root>

组件(Home.java):

package home;

import java.io.IOException;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.text.Font;
import template.Template;

public class Home extends Template {

    @FXML
    private Label welcomeLabel ;

    public Home() throws IOException {

        // not necessary to explicitly call super(), it is called by default
        // this call loads the template defined by the superclass
        super();

        FXMLLoader loader = new FXMLLoader(Home.class.getResource("Home.fxml"));
        loader.setRoot(getCenterContentHolder());
        loader.setController(this);

        loader.load();

        welcomeLabel.setFont(Font.font("Arial", 48));
    }
}

应用:

package application;

import java.io.IOException;

import home.Home;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        Scene scene = new Scene(new Home(), 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

【讨论】:

  • 这帮助很大。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-12
  • 2013-01-18
  • 2021-03-01
  • 1970-01-01
相关资源
最近更新 更多