This question already has an answer here:
Unable to construct javafx.application.Application instance
(1 answer)
Closed 4 years ago.
I am trying to launch in my public class an application defined in another class, earning the "Unable to construct Application instance"-Exception.The example (below) is quite minimalistic. What am I missing?---Clues would be very much appreciated.
This question is different from the question
Unable to construct javafx.application.Application instance
as I would like to have the definition of an application and its launch in separate classes.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class Main {
public static void main(String[] args) {
Application.launch(OKButton.class, args);
}
}
class OKButton extends Application {
#Override
public void start(Stage stage) {
Button btn = new Button("OK");
Scene scene = new Scene(btn, 200, 250);
stage.setScene(scene);
stage.show();
}
}
The problem is, that the constructor of your OKButton class is not accessible for JavaFX. You have to either put your OKButton class in a separate file or use it this way:
public class Main {
public static void main(String[] args) {
Application.launch(OKButton.class, args);
}
public static class OKButton extends Application {
#Override
public void start(Stage stage) {
Button btn = new Button("OK");
Scene scene = new Scene(btn, 200, 250);
stage.setScene(scene);
stage.show();
}
}
}
Related
This question already has an answer here:
JavaFX Single Instance Application
(1 answer)
Closed 3 years ago.
inside controller there is a TextArea
the application to check if it is already running just exits without letting another instance start
public class Main extends Application {
private static Controller controller;
#Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader fxmlLoader = new FXMLLoader();
AnchorPane anchorPane = fxmlLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setScene(new Scene(anchorPane));
primaryStage.setTitle("Hello World");
primaryStage.show();
}
public static void main(final String[] args) throws IOException {
if (Application Launch)) {
//how to access the open application
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sample.fxml"));
controller = fxmlLoader.getController();
controller.doSomeThing("myText");
System.exit(0);
}else {
launch(args);
}
that is a controller
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
public class Controller {
#FXML
private TextArea textArea;
public void doSomeThing(String myText) {
textArea.setText(myText);
}
}
So a small example for you:
private static Controller controller;
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent anchorPane = fxmlLoader.load();
controller = fxmlLoader.getController();
controller.doSomeThing("myText");
...
And in the Controller define a public function.
MyController :
public void doSomeThing(String myText) {
myTextField.setText(myText);
}
When I am running the below mentioned code it is working
import javafx.application.Application;
public class Client {
public static void main(String[] args){
Test t2 = new Test();
Application.launch(t2.getClass(),args);
}
}
where the test class is
package com.temp.com.serverclient;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Test extends Application {
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("No Main");
StackPane root = new StackPane();
root.getChildren().add(new Label("It worked!"));
primaryStage.setScene(new Scene(root, 300, 120));
primaryStage.show();
}
}
But if I am trying to add constructor,it is getting Exception in Application constructor,Error.
The code is
package com.temp.com.serverclient;
import javafx.application.Application;
public class Client {
public static void main(String[] args){
Test t1 = new Test("Pass this String to Constructor");
Application.launch(t1.getClass(),args);
}
}
Test class
package com.temp.com.serverclient;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Test extends Application {
String str;
public Test(String str) {
this.str = str;
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("No Main");
StackPane root = new StackPane();
root.getChildren().add(new Label("It worked!"));
primaryStage.setScene(new Scene(root, 300, 120));
primaryStage.show();
}
}
How Can I sovle the problem? I need to pass the String to collect information from previous class.
Application.launch always uses a public parameterless constructor to create a instance of the application class to launch. (It does not provide any benefit to create a instance in the main method BTW. Simply pass the class without creating a instance, i.e. Application.launch(Test.class, args);.)
In fact you can only pass String parameters to the new instance of your application class without using static members and it's done via the args parameter of Application.launch:
public class Client {
public static void main(String[] args) {
Application.launch(Test.class, "Pass this String to Constructor");
}
}
public class Test extends Application {
String str;
#Override
public init() {
this.str = getParameters().getRaw().get(0);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("No Main");
StackPane root = new StackPane();
root.getChildren().add(new Label("It worked!"));
primaryStage.setScene(new Scene(root, 300, 120));
primaryStage.show();
}
}
Note that accessing the parameters property is also possible for the start method.
JavaFX 9 introduced a new possiblility: using Platform.startup but you need to handle the lifecycle of the application class yourself:
Application app = new Test("Pass this String to Constructor");
app.init();
Platform.startup(() -> {
Stage stage = new Stage();
try {
app.start(stage);
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
});
This does not properly call the Application.stop method though. Also the parameters are not assigned.
AFAIK, Application.launch creates a new instance of Test. Therefore, you need another way to get the value to the instance, e. g. using a static getter method in your Client class which is called from Test
I'm building a JavaFX application with multiple Scenes. I have a problem with scope of variable when changing scenes within setOnAction event. This is my code:
Stage myStage;
public Scene logInScene(){
... all the buttons / textFields
createAccountButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent t){
**this.getStage().allScene(createAccountPane1);**
}
}
}
public Stage getStage(){
return this.myStage;
}
public void allScene(Pane p){
this.myStage.setScene(p);
}
I'm getting an error within the setOnAction function. "Cannot Find Symbol" getStage(). I know this must be a scope problem and it doesn't recognize any variables / functions outside of that scope. How do I make it so that I can change within? I've tried passing through the variable but that will just make my code messy and I wish there was a simpler way. Thanks guys!
Your code works as long as you keep consistency:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Test extends Application{
private Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
Scene scene = logInScene();
primaryStage.setScene(scene);
primaryStage.show();
}
public Scene logInScene(){
Pane root = new Pane();
Button createAccountButton = new Button("create account");
createAccountButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent t){
stage.setScene(CreateAccountScene());
}
});
root.getChildren().add(createAccountButton);
return new Scene(root);
}
protected Scene CreateAccountScene() {
VBox root = new VBox();
Label userLabel = new Label("Insert the username:");
final TextField userField = new TextField();
Button createAccountButton = new Button("create account");
createAccountButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent t){
System.out.println("Account for user " + userField.getText() + " was created succesfully");
}
});
root.getChildren().addAll(userLabel,userField,createAccountButton);
return new Scene(root);
}
public static void main(String[] args) {
launch(args);
}
}
This question has already been solved, but I think it's worth clarifying that your line fails because the this keyword refers to the anonymous EventHandler you are implementing. In Java, you reference the outer class instance with OuterClass.this. So OuterClass.this.getStage().allScene(createAccountPane1); will work.
If you are looking for a prettier solution, some coders like to define a local variable that points to the outer class instance:
final OuterClass self = this;
createAccountButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent t){
self.getStage().allScene(createAccountPane1);
}
}
I'm building a JavaFX application with multiple Scenes. I have a problem with scope of variable when changing scenes within setOnAction event. This is my code:
Stage myStage;
public Scene logInScene(){
... all the buttons / textFields
createAccountButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent t){
**this.getStage().allScene(createAccountPane1);**
}
}
}
public Stage getStage(){
return this.myStage;
}
public void allScene(Pane p){
this.myStage.setScene(p);
}
I'm getting an error within the setOnAction function. "Cannot Find Symbol" getStage(). I know this must be a scope problem and it doesn't recognize any variables / functions outside of that scope. How do I make it so that I can change within? I've tried passing through the variable but that will just make my code messy and I wish there was a simpler way. Thanks guys!
Your code works as long as you keep consistency:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Test extends Application{
private Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
Scene scene = logInScene();
primaryStage.setScene(scene);
primaryStage.show();
}
public Scene logInScene(){
Pane root = new Pane();
Button createAccountButton = new Button("create account");
createAccountButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent t){
stage.setScene(CreateAccountScene());
}
});
root.getChildren().add(createAccountButton);
return new Scene(root);
}
protected Scene CreateAccountScene() {
VBox root = new VBox();
Label userLabel = new Label("Insert the username:");
final TextField userField = new TextField();
Button createAccountButton = new Button("create account");
createAccountButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent t){
System.out.println("Account for user " + userField.getText() + " was created succesfully");
}
});
root.getChildren().addAll(userLabel,userField,createAccountButton);
return new Scene(root);
}
public static void main(String[] args) {
launch(args);
}
}
This question has already been solved, but I think it's worth clarifying that your line fails because the this keyword refers to the anonymous EventHandler you are implementing. In Java, you reference the outer class instance with OuterClass.this. So OuterClass.this.getStage().allScene(createAccountPane1); will work.
If you are looking for a prettier solution, some coders like to define a local variable that points to the outer class instance:
final OuterClass self = this;
createAccountButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent t){
self.getStage().allScene(createAccountPane1);
}
}
I have a MainWindowFx class like below. It basically creates a simple JavaFX GUI.
package drawappfx;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.control.TextAreaBuilder;
/**
*
* #author Hieu
*/
public class MainWindowFX extends Application{
public static final int DEFAULT_WIDTH = 600;
public static final int DEFAULT_HEIGHT = 600;
private int width;
private int height;
private Scene scene;
private TextArea messageView;
private Button quitButton;
private BorderPane layout;
private Stage primaryStage;
#Override
public void start(Stage primaryStage) {
System.out.println("Started building GUI....");
this.buildGUI();
System.out.println("Finished building GUI");
this.primaryStage = primaryStage;
primaryStage.setTitle("Hello World!");
primaryStage.setScene(this.scene);
primaryStage.show();
System.out.println("Where the hell are you?");
}
public Scene getScene() {
return this.scene;
}
public BorderPane getBorderPane() {
return this.layout;
}
public Stage getPrimaryStage() {
return this.primaryStage;
}
public void buildGUI() {
System.out.println("Before layout");
this.layout = new BorderPane();
System.out.println("Before vbox");
this.layout.setBottom(this.addVBox());
System.out.println("before new scene");
this.scene = new Scene(this.layout, DEFAULT_WIDTH, DEFAULT_HEIGHT);
System.out.println("after new scene");
}
public VBox addVBox() {
VBox vbox = new VBox();
vbox.setPadding(new Insets(15, 12, 15, 12));
// message box
this.messageView = TextAreaBuilder.create()
.prefRowCount(5)
.editable(false)
.build();
// quit button
this.quitButton = new Button("Quit");
this.quitButton.setPrefSize(100, 20);
System.out.println("think of a good message?");
vbox.getChildren().addAll(this.messageView, this.quitButton);
System.out.println("before returning vbox");
return vbox;
}
public void postMessage(final String s) {
this.messageView.appendText(s);
}
}
Now I want to use an instance of this object in another class:
package drawappfx;
import java.io.InputStreamReader;
import java.io.Reader;
import javafx.scene.layout.BorderPane;
public class DrawAppFx
{
public static void main(String[] args)
{
final MainWindowFX main = new MainWindowFX();
BorderPane layout = main.getBorderPane();
Reader reader = new InputStreamReader(System.in);
Parser parser = new Parser(reader,layout,main);
main.start(main.getPrimaryStage());
parser.parse();
}
}
But when I run this I ran into this error:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.javafx.main.Main.launchApp(Main.java:658)
at com.javafx.main.Main.main(Main.java:805)
Caused by: java.lang.IllegalStateException: Not on FX application thread; currentThread = main
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:397)
at javafx.scene.Scene.<init>(Scene.java:287)
at javafx.scene.Scene.<init>(Scene.java:226)
at drawappfx.MainWindowFX.buildGUI(MainWindowFX.java:74)
at drawappfx.MainWindowFX.start(MainWindowFX.java:47)
at drawappfx.DrawAppFx.main(DrawAppFx.java:39)
... 6 more
Java Result: 1
I've done some searches on this and guessed that it has something to do with threading... but I still have no idea. Any suggestions?
I've had this problem several times and there is a fairly easy way to resolve it.
First of all let me introduce you to the Mediator pattern, basically you want to create a class that has the relationship with all your GUI classes
(I.e the different GUI classes do not have their own instance of each other instead all of them has the same reference to the Mediator).
That was a sidetrack now to your question.
In order to change window you need to pass the Stage of which the new window should be placed upon because of this your code needs only a minor change:
Now I do not often do this but in your case, I will make an exception the following code consists of a class that you can "Copy Paste" into your program and use that will fix the problem after the code I will explain exactly what I did:
Mediator
public class Mediator extends Application {
private DrawAppFx daf;
private MainWindowFX mainWindow;
private Stage primaryStage;
public Mediator(){
daf = new DrawAppFx(this);
mainWindow = new MainWindowFx(this);
}
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
primaryStage = stage;
mainWindow.start(primaryStage);
}
public void changeToDaf(){
daf.start(primaryStage);
}
}
Now each of the DrawAppFx and MainWindowFx must have a constructor that passes a Mediator object and therefore have a "Has-a" relationship with the mediator
The reason behind this is that the mediator pattern is now in control and should you create more windows it is easy to implement just add them to the mediator and add a method for which the mediator can change to that window.