I want to rerun java FX application from another class. But error throws “Exception in thread “main” java.lang.IllegalStateException: Application launch must not be called more than once”. How to resolve this.
In my code I do console part and FX part. I do the console part in a single class and FX part in another class. So I just want to call the FX part to my console class(to the switch case). Means I just want to call FX part when I required it. it can be several times. When I select the FX option from the menu i t should call the FX part in different class.
Just simply I want to call the FX application from my menu many times. But when I do it throws an exception. How to avoid it and what is the way to do it
import javafx.application.Application; import java.util.Scanner; public class Test2{ static Scanner sc = new Scanner(System.in); public static void main(String[] args){ System.out.print("ENTER THE CHOICE [OPTION NUMBER]: "); String option = sc.nextLine(); switch (option){ case ("1"): test(); break; case("2"): Application.launch(Application1.class,args);// I WANT TO RE RUN THIS SEVERAL TIMES break ; default: System.out.println("invalid option. please re enter"); } } private static void test() { } }
import javafx.application.Application; import javafx.stage.Stage; public class Application1 extends Application{ @Override public void start(Stage primaryStage){ //SOMETHING FX } }
Advertisement
Answer
As suggested in the comments, don’t use the predefined application lifecycle defined by the Application
class. Just make the UI a regular Java class:
import javafx.scene.Parent; import javafx.scene.control.Button; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; public class Ui { private final Pane view ; public Ui() { view = new StackPane(); Button button = new Button("Close"); button.setOnAction(e -> button.getScene().getWindow().hide()); view.getChildren().add(button); } public Parent getView() { return view ; } }
and then start the JavaFX platform “by hand”, and show a window as needed. You just need to take a little care here to ensure that UI tasks are performed on the FX Application Thread.
You probably want to wait to prompt the user again until the window is closed. I use a CountDownLatch
for this. If you want the prompt to appear again immediately (so the user can have multiple windows open at the same time), just omit that logic.
import java.util.Scanner; import java.util.concurrent.CountDownLatch; import javafx.application.Platform; import javafx.scene.Scene; import javafx.stage.Stage; public class App { public static void main(String[] args) { // Start the JavaFX Platform: Platform.startup(() -> {}); // Don't exit JavaFX platform when the last window closes: Platform.setImplicitExit(false); try (Scanner scanner = new Scanner(System.in)) { while (true) { System.out.println("Enter choice (1=test, 2=Show UI, 3=Exit):"); switch(scanner.nextLine()) { case "1": test(); break ; case "2": showUI(); break ; case "3": System.exit(0); default: System.out.println("Invalid option"); } } } } private static void test() { System.out.println("Test"); } private static void showUI() { // latch to indicate window has closed: CountDownLatch latch = new CountDownLatch(1); // create and show new window on FX Application thread: Platform.runLater(() -> { Stage stage = new Stage(); Ui ui = new Ui(); Scene scene = new Scene(ui.getView(), 600, 600); stage.setScene(scene); // signal latch when window is closed: stage.setOnHidden(e -> latch.countDown()); // show window: stage.show(); }); try { // Wait for latch (i.e. for window to close): latch.await(); } catch (InterruptedException exc) { Thread.currentThread().interrupt(); } } }