Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX Application (that uses a preloaded) exits prematurely

I have a Java application that initializes with a Preloader. Once the Preloader hides, the main application starts and successfully loads the resources. The application window then briefly loads and then exits with no exceptions thrown.

Main application code:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.adrian.mobsters.gui;

import com.adrian.mobsters.resource.Resource;
import com.adrian.mobsters.resource.ResourceFactory;
import java.io.IOException;
import java.util.logging.Level;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *
 * @author aelder
 */
public class MainGUI extends Application {

    BooleanProperty ready = new SimpleBooleanProperty(false);

    public void loadResources() {
        Task task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                java.util.logging.Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
                System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");

                double index = 0;
                for (ResourceFactory factory : ResourceFactory.values()) {
                    index++;
                    Resource resource = factory.getResource();

                    if (resource != null) {
                        resource.importResources();
                        notifyPreloader(new ProgressNotification(((double) index)/ResourceFactory.values().length));
                    }
                }

                ready.setValue(Boolean.TRUE);
                notifyPreloader(new StateChangeNotification(
                        StateChangeNotification.Type.BEFORE_START));
                return null;
            }
        };

        new Thread(task).start();
    }

    @Override
    public void start(Stage primaryStage) throws IOException {  
        loadResources();
        Parent root = FXMLLoader.load(MainGUI.class.getResource("main.fxml"));
        Scene scene = new Scene(root);

        primaryStage.setTitle("Mobsters Bot 2.0 - by Adrian Elder");
        primaryStage.setScene(scene);

        // After the app is ready, show the stage
        ready.addListener(new ChangeListener<Boolean>(){
            public void changed(
                ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
                    if (Boolean.TRUE.equals(t1)) {
                        Platform.runLater(new Runnable() {
                            public void run() {
                                primaryStage.show();
                            }
                        });
                    }
                }
        });;  
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

The preloader code:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package resourceloader;

import javafx.application.Preloader;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

/**
 * Simple Preloader Using the ProgressBar Control
 *
 * @author aelder
 */
public class ResourceLoader extends Preloader {

    ProgressBar bar;
    Stage stage;

    private Scene createPreloaderScene() {
        bar = new ProgressBar();
        BorderPane p = new BorderPane();
        p.setCenter(bar);
        return new Scene(p, 300, 150);      
    }

    @Override
    public void start(Stage stage) throws Exception {
        this.stage = stage;
        stage.setScene(createPreloaderScene());     
        stage.show();
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification scn) {
        if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
            stage.hide();
        }
    }

    @Override
    public void handleProgressNotification(ProgressNotification pn) {
        bar.setProgress(pn.getProgress());
    }   
}

Update: It seems it has something to do with executing the Stage show() method in the runLater method. For some reason, this causes the application to exit prematurely.

My current solution is to sleep until the resources have been loaded and then execute the show method on the application thread.

public void start(Stage primaryStage) throws IOException {
    this.primaryStage = primaryStage;

    primaryStage.setTitle("Mobsters Bot 2.0 - by Adrian Elder");
    primaryStage.getIcons().add(new Image(MainGUI.class.getResourceAsStream("/icons/sword.png")));

    currentThread = Thread.currentThread();
    primaryStage.setScene(new Scene(parent.get()));
    primaryStage.show();
}

@Override
public void init() throws InterruptedException {
    // After the app is ready, show the stage
    loadResources();

    while(!ready.get()) {
        Thread.sleep(100);
    }
}
like image 559
Adrian Elder Avatar asked May 20 '17 15:05

Adrian Elder


1 Answers

Move your primaryStage.show(); out of the event and put it after primaryStage.setScene(scene); and see if the application is opening properly.. I think the problem is with the event that marking it as ready

This works for me.. Try commenting the logger and resource and then uncomment partly.. It will help in debug. As I do not have your libraries I can not do further.

public class Main extends Application {

    BooleanProperty ready = new SimpleBooleanProperty(false);

    public void loadResources() {
        Task task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                //java.util.logging.Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
                //System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");

                /*double index = 0;
                for (ResourceFactory factory : ResourceFactory.values()) {
                    index++;
                    Resource resource = factory.getResource();

                    if (resource != null) {
                        resource.importResources();
                        notifyPreloader(new ProgressNotification(((double) index) / ResourceFactory.values().length));
                    }
                }*/

                ready.setValue(Boolean.TRUE);
                notifyPreloader(new StateChangeNotification(StateChangeNotification.Type.BEFORE_START));
                return null;
            }
        };

        new Thread(task).start();
    }

    @Override
    public void start(Stage primaryStage) throws IOException {

        //Parent root = FXMLLoader.load(Main.class.getResource("main.fxml"));
        Scene scene = new Scene(new Label("Application started"), 400, 400);

        primaryStage.setTitle("Mobsters Bot 2.0 - by Adrian Elder");
        primaryStage.setScene(scene);

        // After the app is ready, show the stage
        ready.addListener(new ChangeListener<Boolean>() {
            public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
                if (Boolean.TRUE.equals(t1)) {
                    Platform.runLater(new Runnable() {
                        public void run() {
                            primaryStage.show();
                        }
                    });
                }
            }
        });
        loadResources();
    }

    /**
     * @param args
     *            the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}
like image 132
A Paul Avatar answered Oct 31 '22 16:10

A Paul