可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm having problem to start a JavaFX Application from a Main method of a class which doesn't extend javafx.application.Application
In my application there is the MainApp.java
which should start the overriden method start()
in the MainUIController.java
, which extends Applciation
When I start the Main method from the MainUIController.java
everything works fine.
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); } } }
After running the MainApp, I get the following Error :
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
回答1:
In addition to what Nejinx said, you must not directly call your start()
, always call launch()
, because it sets up the JavaFX environment, including creation of stage
and calls start()
passing the stage as an parameter to it.
The docs has a note specially stating this
NOTE: This method is called on the JavaFX Application Thread
The launch()
can be called from any class, taking into consideration if the class is directly not extending javafx.application.Application
, then you must pass the class extending it as an argument to the launch method.
For example, consider you have a class JavaFXMain
which extends Application
class JavaFXMain extends Application {...}
You can use any other class, to start the JavaFX Application.
class Main { ... public void someMethod() { ... JavaFXMain.launch(JavaFXMain.class); // Launch the JavaFX application ... } }
In your case, you can try something like this inside the main method of MainApp
:
// You may remove args if you don't intend to pass any arguments MainUIController.launch(MainUIController.class, args)
回答2:
You need to initialise the JavaFX environment, you cannot create a new Stage outside of launch(args); being called first on the class that extends Application.
回答3:
This was very helpful, but leaves the FX application as a stand alone application. You cannot pass in objects from your non-FX code and you are provided with no handle to the Application instance that is created.
I came up with this workaround that I am not crazy about but it does allow parameters to be passed in.
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; } }