Terminate JavaFX Application using Platform.exit() - java

I am using JavaFX 2.2 and I have a class which extends Application. Here is my code:
Class A extends Application {
public void Stage(final Stage primaryStage) { ... }
public void Start(){
launch();
}
btnLogin.setOnAction(new EventHandler<ActionEvent>() {
Platform.exit();
}
}
Class B{ }
Class C extends Application{
public void Stage(final Stage primaryStage) { ... }
public void Start(){
launch();
}
}
Actually, Class A is login screen; it will close when I successfully log in. Then the screen closed by platform.exit() function. After that I execute view button in Class B , Class C called but there are some problems.
java.lang.IllegalStateException: Application launch must not be called more than once
I just terminate the screen by using Platform.exit() function but I can't understand why it can't be closed.

Platform.exit() actually terminates whole jfx.
To keep things safe, just invoke launch() once and show/hide new windows.
Something like:
Platform.setImplicitExit(false);//make fx running in backgound.
Platform.runLater/AndWait {//make sure u create window in jfx thread
//window creation/show code here.
}

If Class B is the main screen and you need to Embed JavaFX in your application for Login Screen or any other screen, you don't need Class A and Class C to extend Application.
You can just create a new Window in Swing inside these classes (A and C) and use JFXPanel to embed JavaFX into your Swing Application. This way you can have full control on the application and you can easily open and close windows for Login or any other functionality that you want.
N.B. You should not have two class extending Application inside one app, as only one JavaFX thread is allowed per JVM.
Everytime you try to do this you will get this error
java.lang.IllegalStateException: Application launch must not be called more than once

Related

JavaFX Event handling from a different class

I looked at the stackoverflow questiions that seem similar to my problem, but none were of any help.
Here is my problem:
For a project, I am making a JavaFX app that is in pure Java without FXML. I have two classes, a controller Controller class and a class containing gui stuff GUI.
Controller has a member variable of type GUI and I am trying to assign an event handler to one of the buttons in GUI but it doesn't seem to work. It only works when I try implementing the handler inside the GUI class, but I need it to work in Comtroller.
In the constructor of Controller is as follows:
this.view = view;
view.addSimpleHandler(new SimpleHandler());
view is of type GUI and addSimpleHandler is a member function of view
SimpleHandler is an inner class of Controller that implements EventHandler and overrides the handle() function
public void addSimpleHandler(EventHandler<ActionEvent> e) {
simpleButton.setOnAction(e);
}
here is my main method and class signature for GUI
public class GUI extends Application {
//member variables for the GUI design including simpleButton
private Button simpleButton;
public static void main(String[] args) {
GUI view = new GUI();
Controller controller = new Controller(view);
Application.launch(view.getClass(), args);
}
public GUI() {
simpleButton = new Button("Simple button");
//rest of code is setting up GUI into my panes
}
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(mainPane, sceneWidth, sceneHeight);
//mainPane is a pane that contains simpleButton with a screenwidth and screenHeight
primaryStage.setTitle("Simple");
primaryStage.setScene(scene);
primaryStage.show();
}
Don't instantiate your application class manually. To understand why, see the documentation regarding the JavaFX life-cycle (emphasis mine):
The entry point for JavaFX applications is the Application class. The JavaFX runtime does the following, in order, whenever an application is launched:
Starts the JavaFX runtime, if not already started (see Platform.startup(Runnable) for more information)
Constructs an instance of the specified Application class
Calls the init() method
Calls the start(javafx.stage.Stage) method
Waits for the application to finish, which happens when either of the following occur:
the application calls Platform.exit()
the last window has been closed and the implicitExit attribute on Platform is true
Calls the stop() method
As you can see, JavaFX itself will instantiate the application class and it's that instance which has its life-cycle methods invoked—those methods being init(), start(Stage), and stop(). However, in your code you have the following:
public static void main(String[] args) {
GUI view = new GUI(); // created your own instance
Controller controller = new Controller(view); // gave controller that instance
// Launches JavaFX which starts the life-cycle documented above
Application.launch(view.getClass(), args);
}
You create your own instance of GUI. This instance is not managed by JavaFX which means its start(Stage) method is never invoked. When you create the Controller instance and pass it your instance of GUI you're adding the EventHandler to a node which is never displayed. The window you see displayed is from the GUI instance created as part of the call to Application#launch and that GUI instance is never associated with a Controller.
For JavaFX applications you should consider the init() and start(Stage) methods as the entry points1. In other words, create the Controller in one of those aforementioned life-cycle methods. Although I suppose you could do the same in the constructor instead2. Whichever you choose, take note of which thread invoke each method, which is documented in the same place as the life-cycle. Here are the essentials:
The application class is loaded, initialized, and constructed on the JavaFX Application Thread.
The init() method is invoked by the JavaFX-Launcher thread.
The start(Stage) and stop() methods are invoked by the JavaFX Application Thread.
Remember that certain actions can only be executed on the JavaFX Application Thread.
1. You can still execute code before the call to Application#launch within the main method if needed. The only constraint is that code should not be directly related to JavaFX.
2. Your constructor is currently public and has zero parameters—keep it that way. JavaFX requires the application class to have a public, no-argument constructor in order to construct an instance via reflection.

How to close the current window in JavaFX?

I'm using JavaFX to build an application. In some windows there's a button whose purpose is to close the current one. Currently I'm using this kind of approach, but I think it's not clean as I would like it to be.
public class AboutController {
#FXML
private Button aboutClose;
public void initialize() {
aboutClose.setOnAction(event ->
((Stage) (aboutClose.getScene().getWindow())).close());
}
}
Is there a better way to implement this task? How to get the stage I'm working on from the Controller without having to take it from the button itself?

Updating JFrame control with progress of call to another class

Using NetBeans 8, I have created a JavaFX in Swing Application. The application uses JFrame and JApplet.
The JFrame has a Label and a button that calls a processing class. The processing class calls 5 other subclasses.
I would like to have the processing class send status updates to the Label on the JFrame as the class is processing.
I have found that Sockets and ServerSockets can be used to send data from the processing class to the JFrame class but the Label only gets updated when the processing class completes.
There is too much default code to display.
Here is a summary:
The JFrame class has the typical main, init, createScene methods.
The createScene method creates a GridPane and adds the Label and Button to it, along with an EventHandler for the button.
The EventHandler calls the processing class.
The processing class simply calls 5 other methods.
I would like to do something like this:
public class processingClass {
public static void process(){
updateJFrameLabel("About to do something");
doSomething();
updateJFrameLabel("status: something Done");
doSomethingElse();
updateJFrameLabel("status: something Else Done");
doMore();
updateJFrameLabel("more done");
}
}
How can I update the JFrame label real-time as the process is running?
I understand how to use Sockets but I am not sure how to get the Label to update asynchronously.
Any help or a link to information would be helpful.

JavaFX: Updating UI elements in a Controller class from a Thread

In JavaFX, I have a Controller class that pulls control components from an FXML file and has methods that act on the component, shown with a Label here:
public class ViewController {
#FXML private Label labelStatus;
public void updateStatusLabel(String label) {
labelStatus.setText("Status: " + label);
}
}
I also have a Java Thread with a run() method, like this:
public class Server extends Thread {
public void run() {
super.run();
}
}
This Server thread handles some socket connections that I need for my particular application. After a connection has been established (in the run() method -- not shown), I need to update the Label in the FXML Controller. How would I do this?
Note: I've purposely made my code and question general so it may help others with the same problem.
You call Platform.runLater(runnable) off the JavaFX UI thread to execute a runnable that updates elements of the active JavaFX Scene Graph on the JavaFX UI thread.
Also review Concurrency in JavaFX, with the Task and Service classes and see if that is not a more appropriate solution to your particular task.
For more information, see:
Usage of JavaFX Platform.runLater and access to UI from a different thread.
Platform.runLater and Task in JavaFX
JavaFx response to SwingUtilities.invokeLater

How do I require login authentication before the main app loads with Netbeans Generated code?

Heads up I am very new to Java, 2 days experience so far. I am trying to require my program to show my login form, which is a separate class, and show my main application after authentication is validated. The login class has a isAuth() method that returns a boolean.
So, in netbeans the main app generates the application in 4 stages shown by the following.
#Override protected void startup() {
show(new login()); // loads frame only...
show(new Snap_multitabletestView(this));
}
/**
* This method is to initialize the specified window by injecting resources.
* Windows shown in our application come fully initialized from the GUI
* builder, so this additional configuration is not needed.
*/
#Override protected void configureWindow(java.awt.Window root) {
}
/**
* A convenient static getter for the application instance.
* #return the instance of Snap_multitabletestApp
*/
public static Snap_multitabletestApp getApplication() {
return Application.getInstance(Snap_multitabletestApp.class);
}
/**
* Main method launching the application.
*/
public static void main(String[] args) {
//my guess is login logic would go here?
launch(Snap_multitabletestApp.class, args);
}
So, essentially I am having a hard time figuring out the syntax for keeping the main app locked/hidden until the login has been verified.
Thank you for the assistance!
My suggestion would be to design the program such that your "main program" has no user interface at all.
When it launches the application launches a log on screen and waits until that screen returns. (Maybe look up threads and the join operation). Once the screen returns, if successful it launches your other GUI, otherwise it quits or re-opens the logon screen with an error.
A quick pseudocode walkthrough....
main launches -> Creates new thread that shows Logon GUI -> main thread joins the GUI thread -> GUI thread exits with return code set -> main thread checks return code for success/failure -> proceed to real GUI if successful -> re-open logon otherwise.
On startup do you have to show both the screens? You can show the login screen and on proper authentication you can enable/show the other screens.

Categories

Resources