我按照在线教程为我的JavaFX应用程序构建了一个启动画面。这是SplashController文件:
package splash;
import java.io.IOException;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
* SplashController controls the Splash.FXML file. This is the initial software display. After a
* designated amount of time, the MainMenu.FXML is run.
*
*/
public class SplashController {
@FXML
private StackPane splashRoot;
@FXML
private ImageView splashImage;
/**
* Called after all @FXML annotated members have been injected. Starts a new thread "SplashScreen()".
*/
@FXML void initialize() {
new SplashScreen().start(); //Start SplashScreen thread.
}
/**
* Inner class that extends thread. Displays the splash screen for a designated amount of time then loads
* MainMenu.FXML, sets a new stage, and displays the main menu. Hides the splash screen.
*
*/
class SplashScreen extends Thread {
@Override
public void run() {
try {
splashImage.fitWidthProperty().bind( splashRoot.widthProperty() ); // binds the image to the rootPane width.
Thread.sleep( 3000 ); // puts the thread (SplashScreen) to sleep in order to allow the splash to display long enough.
Platform.runLater( new Runnable() { // Forces the main menu scene to load onto the SplashScreen thread when it is available.
@Override
public void run() {
FXMLLoader loader = new FXMLLoader( getClass().getResource( "../mainMenu/MainMenu.FXML" ) ); // Places MainMenu.FXML into the loader.
Stage stage = new Stage(); // Creates a new stage.
try {
stage.setScene( new Scene( loader.load() ) ); // Sets the scene using the root node of the loaded FXML document.
} catch ( IOException e ) {
e.printStackTrace();
}
stage.setResizable(false); // Prevents user from resizing the window.
stage.setTitle( "Test" ); // Sets the stage title.
stage.show(); // Displays the stage.
splashRoot.getScene().getWindow().hide(); // Hides the splash screen and presumably ends the SplashScreen thread.
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我试图诠释我对线程如何在这里工作的理解,并希望你能为我澄清以下内容是否正确或回答问题:
1)如果我从不创建任何扩展thread
或创建任何新Runnable()
对象的新类,我可以假设我的JavaFX项目中的所有内容都在单个JavaFX应用程序线程上运行;
2)当我创建内部类SplashScreen extends Thread
并在其上调用start()
时,我是否创建了第二个线程?因此,我有两个线程 - 常规JavaFX应用程序线程和SplashScreen
线程;
3)当我然后调用Platform.runLater( new Runnable() { .... } )
时,是否在JavaFX应用程序线程,SplashScreen线程或新的第三个线程中设置了新阶段,FXML和控制器?
4)当我调用splashRoot.getScene().getWindow().hide()
时,是否结束了SplashScreen线程?或者该线程是否继续new Runnable()
调用的Platform.runLater()
?
答案 0 :(得分:2)
1)如果我从不创建任何扩展线程或新的类 创建任何新的Runnable()对象,我可以假设一切都在 我的JavaFX项目在单个JavaFX应用程序线程上运行;
只要您不调用任何内容(例如来自其他API)就行了。
2)当我创建内部类SplashScreen扩展Thread并调用时 start()就可以了,我创建了第二个线程吗?所以我有两个 线程 - 常规JavaFX应用程序线程和SplashScreen 螺纹;
是。请注意SplashScreen
在需要处理UI内容时使用Platform.runLater()
。
3)当我然后调用Platform.runLater(new Runnable(){....})时 它在JavaFX应用程序中设置了新阶段,FXML和控制器 线程,SplashScreen线程,还是新的第三个线程?
调用Platform.runLater()
的代码位于第二个线程上。 Runnable
内的Platform.runLater()
对象是一个放在JavaFX Application Thread的“队列”中的对象,线程在完成它正在做或需要做的任何事情之后将运行(即呈现UI等)
4)当我调用splashRoot.getScene()。getWindow()。hide()时,这样做结束了吗 SplashScreen线程?或者是那个线程继续新的 由Platform.runLater()调用的Runnable()?
它只是关闭托管启动画面的窗口。 线程结束,因为它是线程必须执行的。线程结束是因为在将Runnable
中的最后一行代码Runnable
放到JavaFX应用程序线程队列之后没有别的事情要做。