【问题标题】:Switch FXML scene切换 FXML 场景
【发布时间】:2019-08-31 05:01:51
【问题描述】:

我正在完成我的程序的一部分,该程序涉及将用户从登录屏幕 (FIRST fxml) 发送到第二个屏幕。这应该在程序加载时发生(基于记忆)。

当我运行程序时,它会加载 FIRST 和 SECOND fxml,但会继续显示 FIRST fxml(当它应该显示 SECOND 时)。我可以使用具有相同代码的输入(IE 按钮)从第一个屏幕转到第二个屏幕。

我每次设置场景时都尝试使用不同的加载器并使用 .show() 方法,但这些(或其许多变体)都不起作用。

我在调用方法时打印 - 这就是我确定它们已加载的方式(打印行):

  1. START METHOD(主应用程序启动(Stage)方法)
  2. INIT1 METHOD(第一个控制器初始化方法)
  3. INIT2 METHOD(第二个控制器初始化方法的开始)
  4. 已加载输入 UI(第二个控制器初始化方法结束)
  5. INIT2 METHOD(每当我在文本上按 Enter 键时,这两行都会再次出现)
  6. 已加载输入 UI(此时它会切换到新的 FXML)

这是我的代码结构的最小表示:

public class Main extends Application {

    private static final FXMLLoader loader = new FXMLLoader();
    private static Stage mainStage;

    @Override
    public void start(Stage primaryStage) throws Exception {
        System.out.println("START METHOD");
        mainStage = primaryStage; //Copy Reference
        primaryStage.setScene(new Scene(Main.getLoader().load(Main.class.getResource("/res/screenOne.fxml"))));
        primaryStage.show();
    }

    public static FXMLLoader getLoader() {
        return loader;
    }

    public static Stage getStage() {
        return mainStage;
    }
}

/**
 * FXML Controller class
 */
public class firstUI implements Initializable {

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        System.out.println("INIT1 METHOD");
        try {
            Parent root = Main.getLoader().load(getClass().getResource("/res/screenTwo.fxml"));
            Main.getStage().setScene(new Scene(root));
        } catch (Exception ex) {
            Logger.getLogger(mainUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

/**
 * FXML Controller class
 */
public class secondUI implements Initializable {

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        System.out.println("INIT2 METHOD");
        System.out.println("Loaded Input UI");
    }
}

再次,我希望代码加载第一个UI,然后从第一个UI 加载第二个。

输出(如果 stage.show() 先出现,则在调试中)似乎是:

  1. firstUI 代码运行(从开始)并初始化(未显示)。
  2. secondUI 代码运行(从 firstUI init)并初始化(未显示)。
  3. secondUI 初始化代码完成并显示 firstUI。
  4. 只有当输入(具有相同的开关代码)被按下时,它才会从 firstUI 切换到 secondUI。

【问题讨论】:

  • 欢迎来到 SO。最小的表示是好的(我认为不需要 secondUI 来演示这个问题)。考虑添加 fxml 文件的最小表示以使代码为minimal reproducible example
  • initialize 方法在load 返回之前运行。您先设置第二个场景,然后再将其替换为第一个场景。此外,您不能重用 FXMLLoader 实例(至少不能不跳过一些圈子)。这样做的唯一原因是您正在使用 static load 方法。此外,在视图的初始化中混合登录逻辑是一个坏主意。您正在加载不需要加载的场景。将逻辑和例如分开会更好。在start 中做这样的事情:if(loginRequired()) gotoLogin(); else gotoMain();

标签: java javafx fxml scene


【解决方案1】:

你不需要加载器的引用来改变场景。
你可以有一个简单的Main 喜欢:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(new Scene(new FXMLLoader().load(getClass().getResource("/res/screenOne.fxml"))));
        primaryStage.show();
    }

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

screenOne.fxml 可以在哪里(注意窗格的 fx-id)。
(要进行测试,您需要使用正确的控制器路径进行编辑):

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

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

<AnchorPane fx:id="main" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="FirstUI">
   <children>
      <Label layoutX="155.0" layoutY="132.0" text="Screen 1">
         <font>
            <Font size="24.0" />
         </font>
      </Label>
      <Button layoutX="264.0" layoutY="246.0" mnemonicParsing="false" onAction="#changeScene" prefHeight="26.0" prefWidth="102.0" text="Change Scene" />
   </children>
</AnchorPane>

FirstUI 使用main 更新场景:

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;

public class FirstUI  {

    @FXML Pane main;

    public void changeScene(ActionEvent e) {
        try {
            main.getScene().setRoot(new FXMLLoader().load(getClass().getResource("/res/screenTwo.fxml")));
        } catch (Exception ex) {
          ex.printStackTrace();
        }
    }
}

这里的代码MRE是screenTwo.fxml

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

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

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" 
prefHeight="300.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/10.0.1" 
xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Label layoutX="155.0" layoutY="132.0" text="Screen 2">
         <font>
            <Font size="24.0" />
         </font>
      </Label>
   </children>
</AnchorPane>

【讨论】:

  • 谢谢!这适用于一个添加:main.getScene().setRoot(new FXMLLoader().load(Main.class.getResource("/res/screenTwo.fxml"))); 这行返回 null 所以我使用了 Platform.runLater 并且它可以工作。
  • 我认为不需要Platform.runLater。代码实际上应该是new FXMLLoader().load(FirstUI.class.getResource("screenTwo.fxml")) 或更好的new FXMLLoader().load(getClass().getResource("screenTwo.fxml"))
猜你喜欢
  • 2016-07-18
  • 1970-01-01
  • 2017-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多