it-roy-ru.com

Запуск JavaFX из метода Main класса, который не расширяет Application

У меня проблема с запуском JavaFX-приложения из метода Main класса, который не расширяет javafx.application.Application

В моем приложении есть MainApp.Java, который должен запускать переопределенный метод start() в MainUIController.Java, который расширяет Applciation

Когда я запускаю метод Main из MainUIController.Java, все работает нормально.

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

После запуска MainApp я получаю следующую ошибку:

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

В дополнение к тому, что сказал Nejinx, вы не должны напрямую вызывать свою функцию start(), всегда вызывать launch() , потому что она устанавливает среда JavaFX, включая creation of stage и calls start(), передавая ей этап в качестве параметра.

Документы имеет примечание, специально заявляющее об этом

ПРИМЕЧАНИЕ. Этот метод вызывается в потоке приложений JavaFX.

launch() можно вызывать из любого класса, учитывая, что класс напрямую не расширяется javafx.application.Application , тогда вы должны передать класс, расширяющий его, в качестве аргумента для метод запуска.

Например, предположим, что у вас есть класс JavaFXMain, который расширяет Application

class JavaFXMain extends Application {...}

Вы можете использовать любой другой класс для запуска приложения JavaFX.

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

В вашем случае вы можете попробовать что-то подобное в основном методе MainApp:

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

Вам нужно инициализировать среду JavaFX, вы не можете создать новый этап за пределами запуска (аргументы); вызывается первым в классе, который расширяет приложение.

2
nejinx

Это было очень полезно, но оставляет приложение FX в качестве отдельного приложения. Вы не можете передать объекты из своего не-FX-кода, и вам не дается дескриптор созданного экземпляра приложения.

Я нашел этот обходной путь, от которого я не в восторге, но он позволяет передавать параметры.

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