java - 如何在创建的原始窗口内的 Controller 之间进行转换

标签 java intellij-idea javafx fxml fxmlloader

我目前有 3 节课。

ScreenController( Controller 类):

import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.layout.AnchorPane;
import java.net.URL;
import java.util.ResourceBundle;

public class ScreenController implements Initializable
{
    private AnchorPane window;

    public ScreenController()
    {
        super();
    }

    public ScreenController(AnchorPane window)
    {
        setWindow(window);
    }

    public void setWindow(AnchorPane window)
    {
        this.window = window;
    }

    public void setScreen(String screen)
    {
        try
        {
            Parent root = FXMLLoader.load(getClass().getResource("/com/app/client/resources/fxml/" + screen + ".fxml"));
            window.getChildren().setAll(root);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

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

登录屏幕(主屏幕):

import com.app.client.java.controllers.ScreenController;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;

import java.io.IOException;

public class LoginScreen extends ScreenController
{
    @FXML
    private AnchorPane loginWindow;

    @FXML
    private Button goButton;

    public LoginScreen()
    {
        super();
        setWindow(loginWindow);
    }

    @FXML
    public void goButtonPressed(ActionEvent event) throws IOException
    {
        setScreen("Home");
        System.out.println("Success.");
    }
}
<?xml version="1.0" encoding="UTF-8"?>

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

<AnchorPane fx:id="loginWindow" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" opacity="0.5" prefHeight="500.0" prefWidth="850.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.app.client.java.classes.LoginScreen">
   <children>
      <Button fx:id="goButton" layoutX="205.0" layoutY="60.0" mnemonicParsing="false" onAction="#goButtonPressed" text="Button" />
   </children>
</AnchorPane>

主屏幕(辅助屏幕):

import com.app.client.java.controllers.ScreenController;
import javafx.fxml.FXML;
import javafx.scene.layout.AnchorPane;

public class HomeScreen extends ScreenController
{
    @FXML
    private static AnchorPane homeWindow = new AnchorPane();

    public HomeScreen()
    {
        super (homeWindow);
    }
}
<?xml version="1.0" encoding="UTF-8"?>

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


<AnchorPane fx:id="homeWindow" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.app.client.java.classes.HomeScreen">
   <children>
      <TextArea layoutX="200.0" layoutY="100.0" prefHeight="200.0" prefWidth="200.0" text="aksajkasjkasja" />
   </children>
</AnchorPane>
<小时/>

我希望能够使用 setScreen() 函数从主屏幕移动到辅助屏幕。但是,我发现该过程没有成功完成。

我发现有效的另一种方法是(尽管它调整窗口大小,而不是用新窗口的内容填充初始窗口):

Parent root = FXMLLoader.load(getClass().getResource("/com/app/client/resources/fxml/" + screen + ".fxml"));
Stage stage = (Stage) loginWindow.getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);

但是,我更愿意使用初始实现,因为它更简洁、可读,并且从理论上讲,提供了我想要的确切行为。

最佳答案

您当前遇到的问题有几个:

  1. 在您的 LoginScreen 构造函数中,您使用尚未注入(inject)的字段的值调用 setWindow:

    public LoginScreen()
    {
        super();
        setWindow(loginWindow);
    }
    

    在执行 Controller 的构造函数时,不会注入(inject)任何 FXML 字段,这意味着 loginWindownull。原因不言而喻:FXMLLoader 必须首先构造 Controller 实例,然后才能开始注入(inject)适当的字段。

    事件的顺序是:(1) Controller 实例化,(2) 字段注入(inject),(3) 调用初始化方法;我相信链接任何事件处理程序/更改监听器都包含在第二步中。这意味着需要对 FXML 字段进行的任何初始化都应该在 initialize 方法中完成。

    您在使用 super(homeWindow)HomeScreen 构造函数中遇到了同样的问题,尽管还有其他问题将在下一点中解决。

  2. 除了尝试访问构造函数中尚未注入(inject)的字段之外,还存在以下两个问题:

    @FXML
    private static AnchorPane homeWindow = new AnchorPane();
    

    第一个问题是初始化一个要注入(inject)的字段。 永远不要这样做。一个好的经验法则是:如果字段用 @FXML 注释,则不要手动为其分配值。 FXML 字段最终将被注入(inject),这意味着您之前分配给它的任何值都将被替换。这可能会导致微妙的问题,因为任何引用先前值的代码都不会使用实际添加到场景图中的对象。

    另一个问题是您的字段是静态的。 JavaFX 8+ 不支持注入(inject)静态字段。据我了解,它在旧版本中曾经是可能的,但这种行为从未得到正式支持(即是实现细节)。此外,让本质上基于实例的东西(FXML+ Controller )设置一个会影响所有实例的静态字段是没有意义的。

    额外的问题:当您将 homeWindow 设置为非静态时,您将无法再使用 super(homeWindow),因为您无法在调用 super 构造函数之前引用它.

使用两个修改后的类应该允许您的代码运行:

LoginScreen.java:

public class LoginScreen extends ScreenController {

    @FXML private AnchorPane loginWindow;
    @FXML private Button goButton;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        super.initialize(location, resources);
        setWindow(loginWindow); // set window in initialize method
    }

    @FXML
    public void goButtonPressed(ActionEvent event) throws IOException {
        setScreen("Home");
        System.out.println("Success.");
    }

}

HomeScreen.java:

public class HomeScreen extends ScreenController {

    @FXML private AnchorPane homeWindow;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        super.initialize(location, resources);
        setWindow(homeWindow); // set window in initialize method
    }

}

但是不要使用:

window.getChildren().setAll(root);

在您的 ScreenController#setScreen 方法中,它会导致一个微妙的问题。您将添加一个 root 作为 window 节点的子节点。但是,当发生这种情况时,ScreenController 的新实例(与新的root 关联)具有其window == root。换句话说,使用 LoginScreen 创建的 window 现在是使用 HomeScreen 创建的 window 的父级。根据更复杂的应用程序的设计方式,这可能会导致“根”的嵌套逐渐加深。

也就是说,您已经有了另一种方法来实际替换整个场景。正如您所说,您遇到的问题是 Stage 调整大小以适应新的 Scene。可以通过替换 Sceneroot 而不是 Scene 本身来解决此问题:

window.getScene().setRoot(root);
<小时/>

一些可能有用的资源:

关于java - 如何在创建的原始窗口内的 Controller 之间进行转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57580710/

相关文章:

java - 如何在sqlite android中通过循环限制添加的数据

java - CAS 单点注销不起作用

intellij-idea - 删除 IntelliJ 中的周围方法

intellij-idea - 在 IDEA 中使用方法/函数调用?

javascript - JSLint 抑制 IntellijJ 上的警告

javafx - 更新JavaFX中的两个文本对象,一个接一个,只看到两个更改的最终结果

java - 以前凌乱的任务仍然有一些我不明白的错误

java - 如何用 Java 读取 JPEG 文件属性?

java - 在 2 个 Controller 之间传递值时出现空指针异常

javafx-2 - 图标悬停效果