web-dev-qa-db-fra.com

Démarrage de JavaFX à partir de la méthode Main of the classe qui n’étend pas Application

J'ai un problème pour démarrer une application JavaFX à partir d'une méthode Main d'une classe qui ne s'étend pas javafx.application.Application

Dans mon application, il y a le MainApp.Java qui devrait démarrer la méthode surchargée start() dans le MainUIController.Java, qui étend Applciation

Lorsque je lance la méthode Main à partir du MainUIController.Java, tout fonctionne correctement.

MainApp.Java

public class MainApp {

    public static void main(String[] args) {
        PersonJDBCTemplate jdbc = connect();
        MainUIController mUIc = new MainUIController(jdbc);
        mUIc.start(new Stage());

    }

    public static PersonJDBCTemplate connect() {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "Beans.xml");
        PersonJDBCTemplate personJDBCTemplate = (PersonJDBCTemplate) context
                .getBean("personJDBCTemplate");
        return personJDBCTemplate;
    }
}

MainUIController.Java

public class MainUIController extends Application {

    private Stage stage;
    // private User loggedUser;
    private final double MINIMUM_WINDOW_WIDTH = 800.0;
    private final double MINIMUM_WINDOW_HEIGHT = 570.0;
    private String version = "0.6";
    private PersonJDBCTemplate jdbc;

    public MainUIController(PersonJDBCTemplate jdbc) {
        this.jdbc = jdbc;

    }

    @Override
    public void start(Stage primaryStage) {
        try {
            stage = primaryStage;
            stage.setTitle("Sharp");
            stage.setMinWidth(MINIMUM_WINDOW_WIDTH);
            stage.setMinHeight(MINIMUM_WINDOW_HEIGHT);
            stage.setResizable(false);
            gotoLogin();
            primaryStage.show();
        } catch (Exception ex) {
            Logger.getLogger(MainUIController.class.getName()).log(
                    Level.SEVERE, null, ex);
        }
    }

    public void gotoLogin() {
        try {
            LoginController login = (LoginController) replaceSceneContent("/fxml/Login.fxml");
            login.setApp(this);
        } catch (Exception ex) {
            Logger.getLogger(MainUIController.class.getName()).log(
                    Level.SEVERE, null, ex);
        }
    }
}

Après avoir exécuté le MainApp , l'erreur suivante apparaît:

Exception in thread "main" Java.lang.ExceptionInInitializerError
at javafx.stage.Window.<init>(Window.Java:1110)
at javafx.stage.Stage.<init>(Stage.Java:236)
at javafx.stage.Stage.<init>(Stage.Java:224)
at ch.kit.sharp.main.MainApp.main(MainApp.Java:15)
Caused by: Java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = main
at com.Sun.glass.ui.Application.checkEventThread(Application.Java:445)
at com.Sun.glass.ui.Screen.setEventHandler(Screen.Java:245)
at com.Sun.javafx.tk.quantum.QuantumToolkit.setScreenConfigurationListener(QuantumToolkit.Java:600)
at javafx.stage.Screen.<clinit>(Screen.Java:80)
... 4 more
12
Reubaer

En plus de ce que Nejinx a dit, vous ne devez pas appeler directement votre start(), mais appelez toujours launch() , car il configure le environnement JavaFX, y compris creation of stage et calls start() en lui transmettant l’étape.

Les docs a une note le précisant

REMARQUE: cette méthode est appelée sur le thread d'application JavaFX.

La launch() peut être appelée à partir de toute classe, en prenant en considération que si la classe n’est pas directement étendue javafx.application.Application , vous devez transmettre la classe en l’extendant comme argument à la méthode de lancement.

Par exemple, considérons que vous avez une classe JavaFXMain qui étend Application

class JavaFXMain extends Application {...}

Vous pouvez utiliser n'importe quelle autre classe pour démarrer l'application JavaFX.

class Main {
   ...
   public void someMethod() {
      ...
      JavaFXMain.launch(JavaFXMain.class); // Launch the JavaFX application
      ...
   }
}

Dans votre cas, vous pouvez essayer quelque chose comme ceci dans la méthode principale de MainApp:

// You may remove args if you don't intend to pass any arguments
MainUIController.launch(MainUIController.class, args) 
21
ItachiUchiha

Vous devez initialiser l'environnement JavaFX. Vous ne pouvez pas créer de nouvelle scène en dehors du lancement (args). être appelé en premier sur la classe qui étend Application.

2
nejinx

Cela a été très utile, mais laisse l’application FX en tant qu’application autonome. Vous ne pouvez pas transmettre d'objets de votre code non-FX et vous ne disposez d'aucun descripteur pour l'instance d'application créée.

J'ai proposé cette solution de contournement dont je ne suis pas folle mais qui autorise la transmission de paramètres.

package hacks;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * Created by WorkDay on 8/11/16.<br>
 * <br>
 * HelloWorld is a javaFX app that needs parameters that are real objects
 */

class AppParameterLauncher {
    public static void main(String[] args) {
        HelloWorld.launch(new ObjectThatContainsData("brave"), new ObjectThatContainsData("new"));
    }
}


public class HelloWorld extends Application {

    private static ObjectThatContainsData staticData1 = null;
    private static ObjectThatContainsData staticData2 = null;


    public static void launch(ObjectThatContainsData data1, ObjectThatContainsData data2) {
        HelloWorld.staticData1 = data1;
        HelloWorld.staticData2 = data2;
        Application.launch(HelloWorld.class);
    }

    private final ObjectThatContainsData data1 = HelloWorld.staticData1;
    private final ObjectThatContainsData data2 = HelloWorld.staticData2;

    @Override
    public void start(Stage primaryStage) {

        String Text = "Hello "+data1+" "+data2+" World!";
        primaryStage.setTitle(Text);
        Button btn = new Button();
        btn.setText("Say '"+Text+"'");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.setX(0);
        primaryStage.setY(0);
        primaryStage.show();
    }
}

class ObjectThatContainsData {
    public final String data;

    ObjectThatContainsData(String data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return data;
    }
}
0
Bday