Reputation: 2411
When reading javafx 8 tutorials, this seems to be the main work flow:
public class Test extends Application{
public static void main(String[] args){
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
primaryStage.setScene(scene);
primaryStage.show();
TestFXController controller = fxmlLoader.getController();
controller.plotSomething();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Let's say that I have an Algorithm which I want to run. After starting the above application I may end up with an interface containing a "run algorithm" button. After pressing the button, an action handler invokes the algorithm. I then have: start java application -> build interface -> press button to solve Algorithm -> display solution. All that separates the graphical stuff from the algorithm is a button. In fact, the graphical interface 'drives' the application in the sense that it is responsible for launching the algorithm. What I would prefer however is something like this:
public class Test2{
public void main(String[] args){
Algorithm alg=new Algorithm();
alg.solve();
GUI gui =new GUI(); //Spawns a Javafx 8 Graphical User Interface
gui.displaySolution(alg.getSolution());
}
}
To me, this seems a lot cleaner? I'm however not sure how to do this with javafx 8, or whether this is even possible? Any examples or references are highly appreciated. What should I put in the GUI class such that it launches a javafx 8 interface? The example in Test2 would also open up possibilities to use a clean Observer Design Pattern like this:
public class Test3{
public void main(String[] args){
Algorithm alg=new Algorithm();
alg.addListener(new GUI()); //Add a Javafx 8 GUI as a listener.
alg.addListener(new TextualLogger());
alg.solve();
}
}
Notice that in the classes Test2 and Test3, the GUI no longer drives the application.
To clarify, my main question would be: what should be the implementation of the GUI class if I would run the code in Test2? Something like this:
public class GUI extends Application{
public GUI(){
//What should I put here? Perhaps launch(new String[]); ?
}
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void displaySolution(Solution sol){
...
}
}
Upvotes: 2
Views: 781
Reputation: 609
If you really want to open second JavaFX window from one already running. You can visit.
Launch JavaFX application from another class
It will solve your issue.
below is the code how to run new JavaFx Application
Platform.runLater(new Runnable(){
@Override
public void run(){
new MainApp().start(new Stage()); // MainApp is the class name of your second Application
}
});
Make your class extend Application and Implement Runnable and add below mention code in that class
@Override
public void run(){
launch();
}
launch() method will be called from run() method. Do not use Main() method in the second class, else it with throw exception.
Upvotes: 0
Reputation: 209494
In a JavaFX application, you should think of the start(...)
method essentially as the equivalent of the main(...)
method in a "regular" Java application. (In fact, in Java 8, a JavaFX application does not need a main(...)
method at all.) This mechanism for launching a JavaFX application was introduced in order to force the programmer, as much as possible, to initialize the UI on the correct thread (in comparison to Swing, where there is a large amount of code published which launches the GUI incorrectly). For convenience, the start(...)
method is passed an initial stage, but there is no requirement for you to use it if you prefer to use a different one.
So you can just do
public class Test2 extends Application {
@Override
public void start(Stage primaryStage) {
Algorithm alg = new Algorithm();
alg.solve();
GUI gui = new GUI();
gui.displaySolution(alg.getSolution());
}
// included for the benefit of IDEs that do not support
// launching an Application without a main method:
public static void main(String[] args) { launch(args); }
}
and now GUI
is not an Application
subclass (which makes sense, because it represents the GUI, not an application):
public class GUI {
public GUI(){
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void displaySolution(Solution sol){
...
}
}
One thing to bear in mind here is that start(...)
is executed on the FX Application Thread. Consequently, once you have shown the UI, any further long-running processes that need to be performed should be executed on background threads. In the use-case you've described, all the heavy lifting is done before you show the UI, so this is not an issue, but you may need to consider this if you try to extend this pattern at all.
Upvotes: 3
Reputation: 4209
I am not sure I follow exactly what you are attempting to do - are you trying to open a second JavaFX Window?
Would something like this work?
Scene resultScene = algorithm.getSolution();
Stage resultStage = new Stage();
resultStage.setScene(resultScene);
resultStage.addEventHandler() or addEventFilter()
resultStage.show();
This stage can be it's own window or a child of the primaryStage so that if you close the parent, it will also close.
Upvotes: 0