gpt4 book ai didi

java - 通过 FXML 管理 JavaFX 中的场景切换(性能问题)

转载 作者:行者123 更新时间:2023-12-02 01:51:26 26 4
gpt4 key购买 nike

我正在使用 JavaFX 和 FXML 加载的各种场景。所以我想到编写一个处理场景切换的管理器。

到目前为止一切正常,但我不确定这是否是一个好的实现。

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

public class SceneManager {
private static final String[] fxmlFiles = {"../gui/MainWindow.fxml", "../gui/NewGameWindow.fxml"};
private static SceneManager instance = null;
private static Stage rootStage = null;

private FXMLLoader[] loadedFxml;
private Pane[] loadedPanes;
private Scene[] scenes;

public enum States {
MAIN_MENU, NEW_GAME;
}

private SceneManager() {
try {
this.loadedFxml = new FXMLLoader[States.values().length];
this.loadedPanes = new Pane[States.values().length];
this.scenes = new Scene[States.values().length];

for(int i = 0; i < fxmlFiles.length; i++) {
loadedFxml[i] = new FXMLLoader(getClass().getResource(fxmlFiles[i]));
loadedPanes[i] = loadedFxml[i].load();
scenes[i] = new Scene(loadedPanes[i]);
}

rootStage.setScene(scenes[0]);
rootStage.setResizable(false);
rootStage.show();
} catch(IOException e) {
e.printStackTrace();
}
}

public static SceneManager getInstance() {
if(instance == null) {
instance = new SceneManager();
}
return instance;
}

public static void setUp(Stage stage) {
SceneManager.rootStage = stage;
}

public void switchScene(States state) {
rootStage.setScene(scenes[state.ordinal()]);
}
}

所以我打算做的是,通过加载器加载 FXML,将其分配给一个 Pane ,创建所有场景。

然后我将一个场景设置为其起始场景,并通过 Controller 中的 getInstance().switchScene() 方法完成其余操作。

效果很好,但我不确定这是否是一个好方法。

最佳答案

由于以下几个原因,实现效果非常糟糕:

单例模式没有正确实现

单例模式用于通过静态方法访问包含相关数据/功能的实例,但该实例应包含所有相关数据作为实例字段。

rootStagesetUp静态

您将数据存储在不再需要的字段中

您永远不会在循环之外读取 loadedFxmlloadedPanes 。您可以在循环体中创建局部变量。

所有内容都会立即加载

对于几个小场景,这可能没有太大区别,但随着您添加越来越多的场景,这将增加启动时间。考虑延迟加载场景。

场景数据保存在不同的数据结构中

问题不大,但它使类更难维护。 enum 存储用于创建/访问场景 fxmlFiles 包含另一半的数据。每次添加/删除场景时,您都需要更新代码的两部分。在这种情况下,最好将 url 数据存储在枚举本身中:

public enum States {
MAIN_MENU("../gui/MainWindow.fxml"), NEW_GAME("../gui/NewGameWindow.fxml");
private final url;

States(String url) {
this.url = url;
}
}
for(States state : States.values()) {
FXMLLoader loader = new FXMLLoader(getClass().getResource(state.url));
...
}

请注意,如果您将程序打包为 jar,则在此处的 url 中使用 .. 将不再起作用。

但是首先使用enum是一个值得怀疑的决定。这样,您将无法在不重新编译的情况下添加/删除场景。

使用static似乎根本没有必要

如果可能的话,最好避免使用static。 (参见Why are static variables considered evil?)。

如果我的假设是您仅使用由其加载的场景中的 SceneManager 类(并用于显示初始场景)是正确的,那么传递 SceneManager 并不难场景 Controller 的实例,以避免在这些类中使用 SceneManager.getInstance (请参阅 Passing Parameters JavaFX FXML ):

Controller 的父类(super class)

public class BaseController {
protected SceneManager sceneManager;
void setSceneManager(SceneManager sceneManager) { // if SceneManager and BaseController are in different packages, change visibility
this.sceneManager = sceneManager;
}
}
FXMLLoader loader = ...
Pane pane = loader.load();
BaseController controller = loader.getController();
controller.setSceneManager(this);
<小时/>

为了简单起见,使用 url 作为场景的标识符,您可以改进实现:

public class SceneManager {

private final Stage rootStage;

public SceneManager(Stage rootStage) {
if (rootStage == null) {
throw new IllegalArgumentException();
}
this.rootStage = rootStage;
}

private final Map<String, Scene> scenes = new HashMap<>();

public void switchScene(String url) {
Scene scene = scenes.computeIfAbsent(url, u -> {
FXMLLoader loader = new FXMLLoader(getClass().getResource(u));
try {
Pane p = loader.load();
BaseController controller = loader.getController();
controller.setSceneManager(this);
return new Scene(p);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
});
rootStage.setScene(scene);
}
}

这使您可以

  • 为不同阶段创建不同的管理者
  • 在需要时首先加载场景
  • 动态添加更多场景
  • 防止调用 switchScene 但舞台为 null 的状态
  • 将对 Controller 类中的 SceneManager 的访问简化为 sceneManager.switchScene
  • SceneManager 可能可在程序完成之前进行垃圾回收,因为没有对其的静态引用。

关于java - 通过 FXML 管理 JavaFX 中的场景切换(性能问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52930361/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com