Delay between Preloader and Stage shown - java

I have a program that uses a simple preloader while the init() method creates the main gui. Everything works fine but after the init() method completes and the preloader disappears, there's a noticeable delay before the main stage shows up. I say noticeable because it can be as much as 7 seconds, enough for a user to get confused.
I tried to put as little as possible in the start() method:
public void start(Stage stage) {
/*Scene*/
scene = new Scene(root, 1200, 700);
stage.setScene(scene);
scene.setFill(null);
/*Stage*/
stage.initStyle(StageStyle.TRANSPARENT);
stage.centerOnScreen();
stage.show();
}
Is there a way to reduce/eliminate this delay? Would it be better to scrap the preloader altogether and implement is as a stage in the main program? Thanks in advance.
EDIT:
I took Maverick283's advice and implemented a fadeOut of the preloader. There was still a bit of delay so I sent the final notification (from the main program to the preloader) after showing the main stage and it worked perfectly!
public void start(Stage stage) {
/*Scene*/
scene = new Scene(root, 1200, 700);
stage.setScene(scene);
scene.setFill(null);
/*Stage*/
stage.initStyle(StageStyle.TRANSPARENT);
stage.centerOnScreen();
stage.show();
notifyPreloader(new Preloader.ProgressNotification(0.99));
}

From Oracle:
The last state change notification received by the preloader before the application starts is StateChangeNotification.Type.BEFORE_START. After it is processed, the application's start() method is called. However, it can take time before the application is ready to display its stage after the start() method is called. If the preloader stage is already hidden, then there could be a period of time when the application shows nothing on the screen.
Thus they provide example code how to fix that:
#Override
public void handleStateChangeNotification(StateChangeNotification evt) {
if (evt.getType() == StateChangeNotification.Type.BEFORE_START) {
if (isEmbedded && stage.isShowing()) {
//fade out, hide stage at the end of animation
FadeTransition ft = new FadeTransition(
Duration.millis(1000), stage.getScene().getRoot());
ft.setFromValue(1.0);
ft.setToValue(0.0);
final Stage s = stage;
EventHandler<ActionEvent> eh = new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
s.hide();
}
};
ft.setOnFinished(eh);
ft.play();
} else {
stage.hide();
}
}
}
If you continue reading there is even a way of sharing the two stages (preloader and main application stage)...

I tried the solution shown before but not worked, then I wrote a code that worked for me, what I did was make the preloader dont be hiden by itself, it just get hided when the main app is shown, look:
On Preload:
I commented the stage.hide();
#Override
public void handleStateChangeNotification(StateChangeNotification scn) {
if (scn.getType() == StateChangeNotification.Type.BEFORE_INIT) {
//stage.hide();
}
}
I set stage as static
static Stage stage;
I added this code:
public static Stage getStage() {
return stage;
}
On main app:
#Override
public void start(Stage stage) throws IOException {
scene = new Scene(loadFXML("fxmlLoginGUI.fxml"), 640, 480);
stage.setScene(scene);
stage.show();
if (stage.showingProperty().get()) {
try {
UkhuluvelaERP_Preloader.getStage().hide();
} catch (Exception ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I check if the stage is already shown, then I set the preloader stage to hide() using a get method.
I hope this works for you guys as did for me. good luck. chers

Related

How to use JavaFX in Main

I am completly lost atm. I have been working with scenebuilder and javaFX in the past but I am stuck like 5 hours now and I didnt get a step further. Let me explain:
I have a working java Eclipse Project, using maven dependencies
The Main is where I want to use JavaFX or load a fxml into
The programm takes many many VCC Files and extracts the data to put it all together in an excel
The programm works but I cant load a FXML file into the main or even show a pane in there
Now does my Java Main class has to extend Application? I tried both ways - doenst work.
Some example code:
public void start(Stage primaryStage) {
try {
bpmain = new BorderPane(FXMLLoader.load(new File("src\\fxml\\UserInterface.fxml").toURI().toURL()));
primaryStage.setScene(new Scene(bpmain));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
or this (from original Docs)
public void start(Stage stage) {
Circle circ = new Circle(40, 40, 30);
Group root = new Group(circ);
Scene scene = new Scene(root, 400, 300);
stage.setTitle("My JavaFX Application");
stage.setScene(scene);
stage.show();
}
but this start method is just not getting called... where do I put that?
What my Programm should look like is pretty simple actually. I want a small UI Windows that lets you pick a Folder where the VCC data lives in and a OK Button that basically should run the Main method.
So a TextField that when its picked a Path in the Main gets replaced (filepath) and just a simple OK Button that says: yeah run the main - because the main works perfectly it is just that I cant show that ui and I dont know how to really connect it to the Main.java
Any help is appreciated - Ty
Option 1
public class Launch extends Application {
public static Stage stage = null;
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/Main.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
this.stage = stage;
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Option 2:
public class SidebarController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
void btnHome_OnMouseClicked(MouseEvent event) throws IOException {
BorderPane borderPane = (BorderPane) ((Node) event.getSource()).getScene().getRoot();
Parent sidebar = FXMLLoader.load(getClass().getResource("/fxml/ContentArea.fxml"));
borderPane.setCenter(sidebar);
}
}

Bringing a single stage to the front in windows in JavaFX

I am trying to create a stage in JavaFX that can pop up to the front in windows, while the main stage stays minimized.
This only works however, when the main stage is visible on the screen. I have tried making it work using Modality, but then the user can't interact with the main stage, which is not what i want.
The problem can be reproduced with the following Application:
public class MainApp extends Application {
#Override
public void start(Stage stage) throws Exception {
Scene mainScene = new Scene(new Parent() {});
Stage mainStage = new Stage();
mainStage.setScene(mainScene);
mainStage.show();
mainStage.setIconified(true);
Scene popUpScene = new Scene(new Parent() {});
Stage popUpStage = new Stage();
popUpStage.setScene(popUpScene);
Thread.sleep(5000);
popUp(popUpStage);
}
public static void popUp(Stage popUpStage){
if (popUpStage.isIconified()) popUpStage.setIconified(false);
popUpStage.show();
popUpStage.requestFocus();
popUpStage.toFront();
}
}
Is there anyone who has an answer to this problem?
Just add these two line to popUp. First line brings it to front. Second line allows interaction with the main stage or other windows.
popUpStage.setAlwaysOnTop(true);
popUpStage.setAlwaysOnTop(false);

JavaFX UNDECORATED Stage not showing

I've got problem with may e(fx)clipse application. I want to show a splash screen upon application startup. I successfully created class implementing StartupProgressTrackerService, and got my stateReached method invoked. However I've got problems with javafx itself. I want to create Stage with StageStyle.UNDECORATED. However when i invoke stage.show() method stage isn't rendered immediately and appears just after main window is created. It works fine e.g. with StageStyle.UTILITY. It also renders correctly when i use showAndWait() method, but it stops my app from loading until i close the stage.
Here is my code:
public class MyStartupProgressTrackerService implements StartupProgressTrackerService {
private Stage stage;
public MyStartupProgressTrackerService() {
}
#Override
public OSGiRV osgiApplicationLaunched(IApplicationContext applicationContext) {
applicationContext.applicationRunning();
return StartupProgressTrackerService.OSGiRV.CONTINUE;
}
#Override
public void stateReached(ProgressState state) {
if (DefaultProgressState.JAVAFX_INITIALIZED.equals(state)) {
stage = new Stage(StageStyle.UNDECORATED);
stage.initModality(Modality.WINDOW_MODAL);
stage.setAlwaysOnTop(true);
ImageView view = null;
try {
view = new ImageView(SPLASH_IMAGE);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BorderPane bp = new BorderPane();
bp.getChildren().add(view);
Scene scene = new Scene(bp, 400, 300);
stage.setScene(scene);
stage.show();
}
}
}
I found an ugly solution, but, at least, it works. I noticed that method stage.showAndWait() as a side effect finishes building all controls which haven't been rendered yet. So the trick is to initialize splash screen, and then create dummy stage, showAndWait() it and close() immediately. I know that this solution is far from ideal, so i would appreciate it if someone could show me alternate way to make it work :)
My code:
public void showSplash() {
splashScreen = createSplashScreen();
Stage stage2 = new Stage(StageStyle.TRANSPARENT);
splashScreen.show();
Platform.runLater(new Runnable() {
#Override
public void run() {
stage2.close();
}
});
stage2.showAndWait();
}
private Stage createSplashScreen() {
Stage stage = new Stage(StageStyle.UNDECORATED);
stage.setAlwaysOnTop(true);
VBox vbox = new VBox();
vbox.getChildren().add(new ImageView(splashImage));
Scene scene = new Scene(vbox, 400, 300);
stage.setScene(scene);
return stage;
}

Eliminating Previous Scene After New Scene Is Shown

I am just beginning to learn JAVAFX and I have run into a problem now. I have a login screen and after I clicked login, a dialog box appeared and the problem is I don't know how to eliminate the login screen after the dialog has showed up. Please help me. This is my code
Main.java (contains login screen)
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginScreen.fxml"));
primaryStage.setTitle("Weltes Mart O2 Tank Module");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
LoginController.java (showing a dialog box)
public class LoginController {
#FXML private Text loginStatusMessage;
#FXML private Button btnLogin;
#FXML public void handleLoginButton(ActionEvent event){
System.out.println("BUTTON PRESSED");
try {
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginSuccessDialog.fxml"));
Stage primaryStage = new Stage();
primaryStage.setScene(new Scene(root));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
You can use any Node in a Scene to get a reference to that scene. You can use a Scene to get the Window that contains it. You can close that window.
Assuming the Node fields are actually injected by the loader, you can close the Stage using this code:
btnLogin.getScene().getWindow().hide();

How do I get the close event of a stage in JavaFX?

In JavaFX, how can I get the event if a user clicks the Close Button(X) (right most top cross) a stage?
I want my application to print a debug message when the window is closed. (System.out.println("Application Close by click to Close Button(X)"))
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
// Any Event Handler
//{
System.out.println("Application(primaryStage) Closed by click to Close Button(X)");
//}
}
I got the answer for this question
stage.setOnHiding(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.runLater(new Runnable() {
#Override
public void run() {
System.out.println("Application Closed by click to Close Button(X)");
System.exit(0);
}
});
}
});
Another method for achieving the same effect, but remains more consistent with the way you start your application is to override stop();
According to the JavaFX documentation, the lifecycle of an instance of an Application is as follows:
The JavaFX runtime does the following, in order, whenever an application is launched:
Constructs an instance of the specified Application class
Calls the init() method
Calls the start(javafx.stage.Stage) method
Waits for the application to finish, which happens when either of the following occur:
the application calls Platform.exit()
the last window has been closed and the implicitExit attribute on Platform is true
Calls the stop() method
As a result you simply override stop()
#Override
public void stop(){
System.out.println("Stage is closing");
}
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
System.out.println("Stage is closing");
}
});

Categories

Resources