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
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)
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.
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;
}
}