javaFX Obfuscate error at java.lang.Thread.run(Unknown Source) - javafx

I'm new to JavaFX. I get this error when I try to run my JavaFX app
Exception in Application start method
java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$1(LauncherImpl.java:182)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.AbstractMethodError: javafx.application.Application.start(Ljavafx/stage/Stage;)V
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
... 1 more
My main class is main.mainpage
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.stage.WindowEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class mainpage extends Application {
public static Stage STAGE;
public static Scene SCENE;
#Override
public void start(Stage stage) throws Exception {
STAGE = stage;
Parent root = FXMLLoader.load(getClass().getResource("login.fxml"));
SCENE = new Scene(root);
STAGE.setScene(SCENE);
STAGE.show();
STAGE.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
Platform.exit();
System.exit(0);
}
});
}
public static void main(String args[]) {
launch(args);
}
}
Proguard config file:
-injars '************************************************************.jar'
-outjars '************************************************************-obf.jar'
-libraryjars 'C:\Program Files\Java\jre1.8.0_251\lib\rt.jar'
-dontshrink
-obfuscationdictionary OBF.txt
-classobfuscationdictionary OBF.txt
-packageobfuscationdictionary OBF.txt
-dontnote
-dontwarn
-ignorewarnings
# Keep - Applications. Keep all application classes, along with their 'main'
# methods.
-keepclasseswithmembers public class com.javafx.main.Main, main.mainpage {
public static void main(java.lang.String[]);
}
# Rename FXML files together with related views
-adaptresourcefilenames **.fxml,**.png,**.css
-adaptresourcefilecontents **.fxml
-adaptclassstrings
# Save meta-data for stack traces
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
# Keep all annotations and meta-data
-keepattributes *Annotation*,Signature,EnclosingMethod
# Keep names of fields marked with #FXML attribute
-keepclassmembers class * {
#javafx.fxml.FXML *;
}
# Also keep - Enumerations. Keep the special static methods that are required in
# enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Also keep - Database drivers. Keep all implementations of java.sql.Driver.
-keep class * extends java.sql.Driver
# Keep names - Native method names. Keep all native class/method names.
-keepclasseswithmembers,includedescriptorclasses,allowshrinking class * {
native <methods>;
}
I use exe4j to make exe file. When I run without obfuscating then the app is working. But it doesn't work after obfuscating.

Related

JavaFX multiple scene opening, duplicating of scene

I want to have a login page (which I have working), that then goes to a new scene (which I dont have working yet).
I then want this scene to have items that you can click on. And each item opens another scene/window. But you can open as many as you want. They contain different data, but same fxml/scene.
Is this possible?
Yes, it is possible. It would require you to create a controller for the scene, and then create a new instantiation of that controller object for each new instance of that scene. I think it will also require passing it a new stage each time.
EDIT: Failing to create a new controller instance for each new instance of a scene would mean it is possible to overwrite data in an open scene in one window from an open scene in another window.
In case you're newer to JavaFX, I'll provide some examples of creating new views. This question is mostly related to methods of going about doing so.
Assuming you're following MVC pattern, your project may be structured similar to this:
EDIT: Corrected improper usage of FXMLLoader
MainApp.java
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Modality;
import javafx.stage.Stage;
import Controller.LoginController;
public class Main
extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage stage) throws Exception
{
try {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("/View/Login.fxml"));
Parent root = loader.load();
stage.setScene(new Scene(root));
LoginController loginController = loader.getController();
// Pass this stage by calling the controller's stage setter.
// Conversely we could call a singleton class here to
// give us a stage object that we can re-use many times
loginController.setStage(stage);
stage.initStyle(StageStyle.UNIFIED);
stage.setResizable(false);
stage.getIcons().add(new Image("Resources/icon.png"));
stage.setTitle("");
stage.centerOnScreen();
stage.show();
} catch (IOException ex) {
// exception handling
}
}
}
LoginController.java
import java.net.URL;
import java.io.IOException;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.stage.Modality;
import javafx.stage.Stage;
import Controller.MainController;
public class LoginController implements Initializable
{
#FXML
private Button loginButton;
private Stage stage;
public LoginController() {}
#Override
public void initialize(URL url, ResourceBundle rb) {
loginButton.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
doLogin();
});
}
#FXML
private void doLogin() {
// handle login
showMainApplicationView();
}
#FXML
private void showMainApplicationView() {
try {
loader = new FXMLLoader(LoginController.class.getResource("View/mainView.fxml"));
Parent root = (Parent) loader.load();
MainController mainController = new MainController();
loader.setController(mainController);
mainController.setStage(new Stage());
stage.initModality(m);
stage.setResizable(isResizable);
stage.getIcons().add(new Image("Resources/icon.png"));
stage.setTitle(title);
stage.setScene(new Scene(root));
return stage;
} catch (IOException e) {
// exception handling
}
}
#FXML
public void setStage(Stage stage) {
this.stage = stage;
}
}
MainController.java
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.stage.Stage;
public class LoginController implements Initializable
{
public LoginController() {}
#Override
public void initialize(URL url, ResourceBundle rb) {}
#FXML
private void showSubview() {
/* Same code as the prior examples for launching a new view
* It will work for creating as many new "windows" of the same
* view as you desire. If you need to pass different types of
* data to each view you can use a DAO model, or some kind of
* "Instance" object that works for sending/receiving data to/from
* the subview from this class.
*/
}
#FXML
public void setStage(Stage stage) {
this.stage = stage;
}
}
If you want to reuse a stage more than once and at varying depths into subviews I would recommend using a Singleton class.
StageHolder.java
import javafx.stage.Stage;
public final StageHolder
{
private Stage stage;
private final static StageHolder INSTANCE = new StageHolder();
private StageHolder() {}
public static StageHolder getInstance() {
return INSTANCE;
}
public Stage getStage() {
return this.stage;
}
// you can omit this setter if you only want to re-use a single stage over and over.
public void setStage(Stage stage) {
this.stage = stage;
}
}

javafx.scene.Scene cannot be cast to javafx.scene.layout.Pane

Hi guys i'm new to javafx build and i'm trying to cast a Pane but can't seem to work and i don't know why, I hope you can help me, if so thanks!
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = (Pane)FXMLLoader.load(getClass().getResource("Interface.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
and the errors i get are
WARNING: Loading FXML document with JavaFX API of version 11.0.1 by JavaFX runtime of version 8.0.231
java.lang.ClassCastException: javafx.scene.Scene cannot be cast to javafx.scene.layout.Pane
at application.Main.start(Main.java:14)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
at java.lang.Thread.run(Unknown Source)
I used Scenebuilder to build the fxml file

Exception in Application start method java.lang.reflect.InvocationTargetException javafx

I write program with java8, JAVAFX, spring, hibernate, jpa, mysql.
I've to problem with connecting server part of program with javafx.
When I click on class with main→run as java aplication, this problems occurs:
log4j:WARN No appenders could be found for logger (org.jboss.resteasy.plugins.providers.DocumentProvider).
log4j:WARN Please initialize the log4j system properly.
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/Sylwia/.m2/repository/ch/qos/logback/logback-classic/1.0.13/logback-classic-1.0.13.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/Sylwia/.m2/repository/org/slf4j/slf4j-log4j12/1.7.5/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/Sylwia/.m2/repository/org/slf4j/slf4j-simple/1.5.8/slf4j-simple-1.5.8.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(Unknown Source)
at com.sun.javafx.application.LauncherImpl.launchApplication(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$147(Unknown Source)
at com.sun.javafx.application.LauncherImpl$$Lambda$48/1732398722.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: javafx.fxml.LoadException:
/C:/Users/Sylwia/git/Praca%20inzynierska%203/Praca%20inzynierska%202/target/classes/fxml/productComponent.fxml
at javafx.fxml.FXMLLoader.constructLoadException(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at pl.ftims.praca.restClientJavafx.RestClient.start(RestClient.java:17)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(Unknown Source)
at com.sun.javafx.application.LauncherImpl$$Lambda$51/1441419654.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(Unknown Source)
at com.sun.javafx.application.PlatformImpl$$Lambda$45/1051754451.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(Unknown Source)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/742445343.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(Unknown Source)
at com.sun.javafx.application.PlatformImpl$$Lambda$46/1775282465.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(Unknown Source)
at com.sun.glass.ui.win.WinApplication$$Lambda$37/1109371569.run(Unknown Source)
... 1 more
Caused by: java.lang.NullPointerException
at pl.ftims.praca.restClientJavafx.FXMLController.initialize(FXMLController.java:140)
... 23 more
Exception running application pl.ftims.praca.restClientJavafx.RestClient
//////////////////////////////////////////////////////////////////////
Should I first focus on problem:
at pl.ftims.praca.restClientJavafx.RestClient.start(RestClient.java:17)
or:
Caused by: java.lang.NullPointerException
at pl.ftims.praca.restClientJavafx.FXMLController.initialize(FXMLController.java:140)
... 23 more
my RestClient class:
package pl.ftims.praca.restClientJavafx;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class RestClient extends Application {
#Override
public void start(Stage stage) throws Exception {
//When using the Class.getResource method,
//you must provide a local path from the location of the class on which is called the method.
//Parent root = FXMLLoader.load(RestClient.class.getResource("/fxml/components.fxml"));
Parent root = FXMLLoader.load(RestClient.class.getResource("/fxml/productComponent.fxml"));
//I also had to use Parent root = FXMLLoader.load(getClass().getResource("/fxml/Scene.fxml"));
/*FXMLLoader loader = new FXMLLoadergetClass().getResource("main.fxml");
loader.setController(new MainController(path));
Pane mainPane = loader.load();*/
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
FXMLController class
package pl.ftims.praca.restClientJavafx;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import pl.ftims.praca.model.ProductWrapper;
import pl.ftims.praca.model.Products;
public class FXMLController implements Initializable {
#FXML
private TableView productTable;
#FXML
private TableColumn idColumn;
#FXML
private TableColumn nameColumn;
#FXML
private TableColumn sellingPriceColumn;
#FXML
private TableColumn purchasePriceColumn;
#FXML
private TextField idField;//tego nie bylo chyba, bo nie mozna przeciez zmieniac id
#FXML
private TextField nameField;
#FXML
private TextField sellingPriceField;
#FXML
private TextField purchasePriceField;
/*private Long id;
private String name;
private Double sellingPrice;
private Double purchasePrice; //cena zakupu
#ManyToOne
private Storages storage; */
private List<Products> listOfProducts = null;
private List<Fxproduct> listOfFxProducts = null;
private ObservableList<Fxproduct> listOfObservableList = null;
private final static String REST_ROOT_URL = "http://localhost:8080/rest/";
private final Client client = ClientBuilder.newClient();
#FXML
private void remove(ActionEvent event) { //ok rozumiem
Fxproduct fxproduct = (Fxproduct) productTable.getSelectionModel().getSelectedItem();
listOfObservableList.remove(fxproduct);
Response response = client.target(REST_ROOT_URL).
// path("publisher").
path("products").
path("deleteProductWithId").
path(String.valueOf(fxproduct.getId())).
request().delete();
}
#FXML
private void save(ActionEvent event) {
Products product = new Products();
product.setName(nameField.getText());
product.setPurchasePrice(Double.parseDouble(purchasePriceField.getText()));
product.setSellingPrice(Double.parseDouble(sellingPriceField.getText()));
Entity<Products> kitapEntity = Entity.entity(product, MediaType.APPLICATION_XML);
Response response = client.target(REST_ROOT_URL).
path("product").
path("createProductWithData").
request().
post(kitapEntity);
list(null);
nameField.setText("");
purchasePriceField.setText("");
sellingPriceField.setText("");
}
#FXML
private void list(ActionEvent event) { //NIE WIEM JAK TO ZROBIC
Response response = client.target("http://localhost:8080/rest/").
path("products").
path("products").
request(MediaType.APPLICATION_XML).
get();
ProductWrapper productWrapper = response.readEntity(ProductWrapper.class); //nie mam tego
listOfProducts = (productWrapper.getProductList()==null)?new ArrayList<Products>(): productWrapper.getProductList();
// listOfFxProducts = new ArrayList<>();
// listOfFxProducts = new ArrayList<>(); //tak bylo, ale to jest java 1.7 i sie nie kompilowalo
for (Products k : listOfProducts) {
listOfFxProducts.add(new Fxproduct(k));
}
listOfObservableList = FXCollections.observableList(listOfFxProducts);
System.out.println(listOfObservableList);
productTable.setItems(listOfObservableList);
System.out.println(productTable);
}
public void kitapDuzenle(Products product) {
Entity<Products> kitapEntity = Entity.entity(product, MediaType.APPLICATION_XML);
Response response = client.target(REST_ROOT_URL).
path("product").
path("saveProduct2").
request().
put(kitapEntity);
}
// #SuppressWarnings("restriction")
#Override
public void initialize(URL url, ResourceBundle rb) {
productTable.setEditable(true); //tu jest blad, nullpointer
//NAME
nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
nameColumn.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Fxproduct, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Fxproduct, String> t) {
ObservableList<Fxproduct> kitapListesi = t.getTableView().getItems();
Fxproduct kitap = kitapListesi.get(t.getTablePosition().getRow());
kitap.setName(t.getNewValue());
kitapDuzenle(kitap.getproduct());
}
}
);
//SELLINGPRICE
sellingPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(new DoubleToStringConverter()));//tu jest blad
sellingPriceColumn.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Fxproduct, Double>>() {
#Override
public void handle(TableColumn.CellEditEvent<Fxproduct, Double> t) {
ObservableList<Fxproduct> kitapListesi = t.getTableView().getItems();
Fxproduct kitap = kitapListesi.get(t.getTablePosition().getRow());
kitap.setSellingPrice(t.getNewValue()); //tu ejst problem z double i siple double
kitapDuzenle(kitap.getproduct());
}
}
);
//PURCHASEPRICE
purchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(new DoubleToStringConverter()));
purchasePriceColumn.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Fxproduct, Double>>() {
#Override
public void handle(TableColumn.CellEditEvent<Fxproduct, Double> t) {
ObservableList<Fxproduct> kitapListesi = t.getTableView().getItems();
Fxproduct kitap = kitapListesi.get(t.getTablePosition().getRow());
kitap.setPurchasePrice(t.getNewValue());//tu ejst problem z double i siple double
kitapDuzenle(kitap.getproduct());
}
}
);
idColumn.setCellValueFactory(
new PropertyValueFactory<Fxproduct, Long>("id"));
nameColumn.setCellValueFactory(
new PropertyValueFactory<Fxproduct, String>("name"));
purchasePriceColumn.setCellValueFactory(
new PropertyValueFactory<Fxproduct, Double>("price"));
sellingPriceColumn.setCellValueFactory(
new PropertyValueFactory<Fxproduct, Double>("price"));
list(null);
}
}
I thought that the problems is the path:
Parent root = FXMLLoader.load(RestClient.class.getResource("/fxml/productComponent.fxml"));
but I read this:
How to reference javafx fxml files in resource folder?
JavaFX "Location is required." even though it is in the same package
Referencing class resource in FXML
Error loading fxml files from a folder other than the bin folder
JavaFX: load resource from other package - NetBeans
How to reference javafx fxml files in resource folder?
https://stackexchange.com/search?q=How+to+reference+javafx+fxml+files+in+resource+folder%3F
JavaFX - Exception in Application start method?
and I didnt find the answer.
/////////////////////////////EDIT///////////////////
line 17 in RestClient:
Parent root = FXMLLoader.load(RestClient.class.getResource("/fxml/productComponent.fxml"));
line 139, 140 in FXMLController:
public void initialize(URL url, ResourceBundle rb) { productTable.setEditable(true); // nullpointer

Javafx service to update GUI objects status

I'm trying to update the GUI status based on a time consuming task. When I push on a button, I want the button to be inactive and the cursor to change until the job is completed. I've come up with this code that mostly works as needed.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class TestWait2 extends Application {
#Override
public void start(Stage primaryStage) {
FlowPane root = new FlowPane();
primaryStage.setScene(new Scene(root));
MyService myService = new MyService();
primaryStage.getScene().getRoot().cursorProperty()
.bind(Bindings.when(myService.runningProperty())
.then(Cursor.WAIT).otherwise(Cursor.DEFAULT));
Button startButton = new Button();
startButton.setText("Button");
startButton.disableProperty().bind(myService.runningProperty());
root.getChildren().add(startButton);
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
myService.start();
}
});
primaryStage.show();
}
private class MyService extends Service<Void> {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
Thread.sleep(5000);
return null;
}
};
}
}
public static void main(String[] args) {
launch(args);
}
}
When I launch it works great the first time. The problem is that if I click on the button a second time it get an error.
Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: Can only start a Service in the READY state. Was in state SUCCEEDED
Any thoughts on how to get around that issue?
I'm running on Java 8u5.
The problem with your code that you try to call myService.start(); when its on SUCCEEDED state(since you started it already once).
this is according to javadoc of Service start method
Starts this Service. The Service must be in the READY state to succeed in * *this call.
This method should only be called on the FX application thread.
to make your code work, you need to you call myService.restart().
since you are planning to use your service over and over you can do the following:
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//replace this line
// myService.start();
//with this
myService.restart();
}
});
Adding this to the program seemed to solve this.
myService.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent t) {
myService.reset();
}
});
I also found I can add the following directly to the MyService class.
#Override
protected void succeeded() {
reset();
}
There doesn't seem to be any other way to have it go to the ready state after completing it's work.

Using a JavaFx application instance from another class

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.

Resources