我需要有人解释一下Preloader在JavaFX应用程序中的工作原理。我已经发现了生命周期,我知道首先调用preloader的start(..)然后启动(..)Application,但是这两个方法是从同一个Thread调用的吗?我试图在应用程序的启动方法中创建一个简单的应用程序,放入Thread.sleep(8000),并在Preloader的开头我创建了一个简单的阶段并显示它。但是当我运行应用程序时,它只是在黑色阶段冻结,并且仅在8秒后正确显示预加载器阶段,但为什么?
使用源代码更新我的帖子:
public class PreloaderApp扩展Preloader {
public void init(){
System.out.println("Thread Preloader ID:"+ Thread.currentThread().getId());
System.out.println(" ------ ");
Pane effectRegion = LoaderFrame.getInstance().getEffectPane();
JFXFillTransition fill = new JFXFillTransition();
fill.setDuration(Duration.millis(400));
fill.setRegion(effectRegion);
fill.setAutoReverse(true);
fill.setCycleCount(Animation.INDEFINITE);
fill.setFromValue(Color.WHITE);
fill.setToValue(Color.rgb(0,77,147));
fill.play();
}
@Override
public void start(Stage primaryStage){
System.out.println("Thread Preloader(start) ID:"+ Thread.currentThread().getId());
System.out.println(" ------ ");
LoaderFrame.getInstance().show();
}
}
public class LoaderFrame extends Stage {
private static final LoaderFrame instance = new LoaderFrame();
public static LoaderFrame getInstance(){
return instance;
}
private Scene scene;
private AnchorPane root;
private BorderPane wraper;
private StackPane effectPane;
private JFXButton loaderPathButton;
public LoaderFrame(){
initScene();
this.initStyle(StageStyle.TRANSPARENT);
this.getIcons().add(new Image("file:imgs/favico/icon48.png"));
}
public void initScene(){
FXMLLoader loader = new FXMLLoader(Main.class.getResource("xml/loader_frame.fxml"));
root = null;
try {
root = loader.load();
wraper = (BorderPane) root.lookup("#rootPane");
loaderPathButton = (JFXButton) root.lookup("#loaderPathButton");
effectPane = (StackPane) root.lookup("#effectPane");
scene = new Scene(root);
scene.setFill(Color.TRANSPARENT);
scene.getStylesheets().add("file:css/loader.css");
this.setScene(scene);
} catch (IOException e) {
e.printStackTrace();
}
}
public Pane getEffectPane(){
return effectPane;
}
}
答案 0 :(得分:0)
要调查Preloader
生命周期,您可以将以下行添加到Preloader
类:
@Override
public void handleStateChangeNotification(StateChangeNotification info) {
System.out.println("state: " + info.getType());
}
在Application
课程中,您可以在System.out.prinln
/ init
方法中添加start
条消息。这会显示Preloader
正在运行其不同的状态:BEFORE_LOAD
,BEFORE_INIT
,BEFORE_START
。
在Preloaders start method
上调用JavaFXThread
时,您必须将来电包裹在Thread.sleep
中的Platform.runlater
。
请注意,预加载器遵循与其他JavaFX应用程序相同的规则,包括FX线程规则。特别是,类构造函数和init()方法将在非FX线程上调用,start()将在FX应用程序线程上执行。这也意味着应用程序构造函数/ init()将与preloader start()同时运行。
如果您需要花费一些时间进行初始化,则应该在Apps init
方法中执行此操作。当Preloader state
更改为BEFORE_START
后,您可以隐藏Preloader stage
public class App extends Application {
private static final int PRELOADER_SHOWTIME_MILLIS = 2000;
@Override
public void init() throws Exception {
long start = System.currentTimeMillis();
// time consuming initializations
long duration = System.currentTimeMillis() - start;
long remainingShowTime = PRELOADER_SHOWTIME_MILLIS - duration;
if(remaingShowTime > 0 ){
Thread.sleep(remainingShowTime);
}
}
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane(new Label("application"));
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
public class TestPreloader extends Preloader {
private Stage stage;
@Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
Rectangle rect = new Rectangle(200, 200, Color.RED);
FadeTransition transition = new FadeTransition(Duration.seconds(2), rect);
transition.setFromValue(0);
transition.setToValue(1);
Label lbl = new Label("preloader");
StackPane root = new StackPane(rect, lbl);
primaryStage.setScene(new Scene(root));
primaryStage.show();
transition.play();
}
@Override
public void handleStateChangeNotification(StateChangeNotification info) {
if (info.getType() == Type.BEFORE_START) {
stage.hide();
}
}
}
public class Main {
public static void main(String[] args) {
LauncherImpl.launchApplication(App.class, TestPreloader.class, args);
}
}