JavaFX预加载程序问题

JavaFX预加载程序问题,java,javafx,Java,Javafx,你好,亲爱的Stackoverflow 关于JavaFX类预加载程序,我有几个问题。 经过长期的研究,我还没有找到任何解决问题的正确方法,我认为这并不是我的代码的问题,而是JavaFX本身在预加载类方面的局限性 让我直截了当地谈谈我的观点:难道不能使用FXML来定义预加载程序的设计吗?有趣的是,所有教程都只是通过在类外创建新实例来指导您创建预加载程序。(ProgressBar ProgressBar=新的ProgressBar();ie) 因此,让我们以下面的示例代码为例,与我一起测试: 测试预

你好,亲爱的Stackoverflow

关于JavaFX类预加载程序,我有几个问题。 经过长期的研究,我还没有找到任何解决问题的正确方法,我认为这并不是我的代码的问题,而是JavaFX本身在预加载类方面的局限性

让我直截了当地谈谈我的观点:难道不能使用FXML来定义预加载程序的设计吗?有趣的是,所有教程都只是通过在类外创建新实例来指导您创建预加载程序。(ProgressBar ProgressBar=新的ProgressBar();ie)

因此,让我们以下面的示例代码为例,与我一起测试:

测试预加载程序:

import com.sun.javafx.application.LauncherImpl;
import javafx.application.Preloader;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class TestPreloader extends Preloader {


    @FXML
    ProgressBar progressBar;

    public static void main(String[] args) {
        LauncherImpl.launchApplication(TestApplication.class, TestPreloader.class, args);
    }

    public void initialize() {
        System.out.println("initialize printed");
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.initStyle(StageStyle.TRANSPARENT);
        Parent root = FXMLLoader.load(getClass().getResource("preloader.fxml"));
        Scene scene = new Scene(root);
        scene.setFill(Color.TRANSPARENT);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.centerOnScreen();
        primaryStage.show();
    }

    @Override
    public void handleProgressNotification(ProgressNotification progressNotification) {
        // progressBar.setProgress(progressNotification.getProgress());
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification notification) {

        System.out.println(notification.getType().toString());
        switch (notification.getType()) {
            case BEFORE_START:
                //progressBar.setProgress(1);
                break;
            case BEFORE_LOAD: //this is where the TestApplication class will be constructed
                //progressBar.setProgress(1);
                break;

            case BEFORE_INIT:
                //progressBar.setProgress(1);
                break;
        }

    }
}
FXML

启动时的输出顺序如下:

initialize printed
BEFORE_LOAD
BEFORE_INIT
BEFORE_START
Application started!
现在,正如您所看到的,initialize()方法是第一手调用的,然后预加载程序的状态会发生变化,因此每次变化都会弹出通知——直到现在都很好

然而,困扰我的是,如果我在initialize方法中调用progressBar#setProgress,则进度实际上被设置为1,并且不会抛出任何错误。虽然这些状态发生在预加载程序初始化之后,但会出现空指针

为了理解我的意思,在handleStateNotification下取消对setProgress的注释(在BEFORE_LOAD语句下对我来说最有意义),您将看到弹出一个NullPointerException

现在,为什么会发生这种情况?如何解决此问题?这对我来说毫无意义。如果预加载程序已初始化且ProgressBar不为null,那么它如何在之后变为null?也许有一个单独使用自己类的新实例?但这对我来说没什么意义。你为什么要那样

我已经在这个问题上纠缠了几天了,我的意思是我可以制定一个时间表并“硬编码”它,但我想知道是什么导致了这些问题

TLDR; 当使用预加载程序类时,ProgressBar在初始化应用程序后将变为null,这是什么原因,我应该怎么做

编辑:
似乎该类没有在某个地方重建,idk i真的被卡住了lol

当FXMLLoader加载您的FXML文件时,它会创建指定控制器的新实例。然而,这并不是理想的结果。接收状态回调的对象应该是FXML窗口的控制器

FXMLLoader.load(…)
块替换为

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("preloader.fxml"));
fxmlLoader.setController(this);
Parent root = fxmlLoader.load();

从FXML中删除控制器属性会导致FXMLLoader使用给定的控制器实例(即接收状态回调的实例),而不是构造指定控制器类的新实例。

是否粘贴了所有FXML文件?我在里面看不到ProgressBar。@EmreDalkiran更新了它,很抱歉,是一个格式问题,与问题无关:为什么在
main
方法中使用
LauncherImpl
?它是一个内部(
com.sun.*
)方法。公共方法是
javafx.application.application.launch
.Duh,它来自一个教程,在我运行预加载程序之前,我不想费心寻找更有效的方法。不过,谢谢你指出。编辑:我刚刚注意到,如果我按照你说的那样做,它甚至不会运行代码。对不起,我不理解其中的含义(在独立应用程序中没有真正使用预加载程序)。在Java9+中,这个方法将对您隐藏。换个角度看。
initialize printed
BEFORE_LOAD
BEFORE_INIT
BEFORE_START
Application started!
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("preloader.fxml"));
fxmlLoader.setController(this);
Parent root = fxmlLoader.load();