There are two major, and distinct, problems with your approach:
The call to Application.launch(...)
blocks execution until the JavaFX platform exits. From the documentation:
The launch method does not return until the application has exited, either via a call to Platform.exit()
or all of the application windows have been closed.
If you call Application.launch()
more than once, an exception will be thrown. Quoting the same documentation:
It must not be called more than once or an exception will be thrown.
Thus your code won't work at all. Firstly, the "CLI" thread will be blocked the first time you call launch()
, and it won't be able to do anything until the JavaFX runtime exits. You could avoid that blocking by calling launch()
in a background thread, but then as soon as you tried to call launch()
a second time, the call would fail with an exception.
It's not really clear what you're trying to achieve here. It would be highly unusual to have the same user interact with the same application both by a command line interpreter and via a graphical user interface.
If you really want to do this, I would approach it by starting the JavaFX application in the usual way (calling launch()
once, from the main method, and using the start()
method as your entry point). Then start the CLI from the start()
method. Note that you still need to use a background thread, this time to run the CLI, because it is a blocking loop and running it on the FX Application Thread would prevent the UI from updating. Any GUI calls from the background thread have to be wrapped in Platform.runLater(...)
to ensure they are called on the FX Application Thread.
Also note that you almost certainly need to call Platform.setImplcitExit(false)
to prevent the FX runtime from closing when you close the first window.
Again, this doesn't really make any sense at all from a User Experience perspective, but here is a quick example implementing this:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
Platform.setImplicitExit(false);
Thread cliThread = new Thread(this::runCLI);
cliThread.start();
}
private void runCLI() {
try (Scanner scanner = new Scanner(System.in)) {
boolean exit = false ;
while (! exit) {
System.out.println("Enter option (GUI to show gui, Quit to exit):");
String option = scanner.nextLine();
switch(option.toLowerCase()) {
case "gui":
Platform.runLater(this::showGUI);
break;
case "quit":
exit = true;
break;
default:
System.out.println("Other action: "+option);
}
}
Platform.exit();
}
}
private void showGUI() {
Stage stage = new Stage();
Label label = new Label("Here is a GUI Window");
Button button = new Button("Close");
button.setOnAction(e -> stage.hide());
VBox root = new VBox(10, label, button);
root.setPadding(new Insets(40));
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
stage.toFront();
}
public static void main(String[] args) {
Application.launch();
}
}