Hi I have application which runs both on GUI(Java FX) as well as command line.
When run as GUI, i show the status on text area. This works fine.
But the issue is when ever i try to show a error(via popup) from some different (non javafx) class, it shows me Java Fx - thread Exception not on FX thread.
Below is my code
This is my Java FX class where I wish to show popup.
public class DeploymentProcesController implements Initializable {
#FXML
private TextArea statusTextArea;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
public void updateGUIMessage(String message) {
if (Platform.isFxApplicationThread()) {
statusTextArea.appendText(message);
} else {
Platform.runLater(new Runnable() {
#Override
public void run() {
statusTextArea.appendText(message);
}
});
}
}
public void displayAlertMessages(final String message) {
Platform.setImplicitExit(false);
Task<Void> task = new Task<Void>() {
#Override public Void call() {
Platform.runLater(new Runnable() {
public void run() {
Alert alert = new Alert(AlertType.INFORMATION, message, ButtonType.OK);
alert.showAndWait();
}
});
return null;
}
};
new Thread(task).start();
}
}
I have a non FX class which is the entry point. So Based on type of run (command line / GUI ) I update the status.
Here is how I am calling to update the status.
public void promptUser(String message,boolean isCommandLineRun){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
if(isCommandLineRun) {
System.out.println(simpleDateFormat.format(new Date()) + " - " + message);
} else {
controller.displayAlertMessages(message);
}
}
I have no issues when i call the updateGUIMessage method from non fx class. This is because the statusArea element is on FX thread(member of this fx class).
Also I have no issues to generate a alert box on some button click,
but to display an Alert box from a different class- I am having issues since as soon as I try to generate a alert box , the application crashes, saying not on fx thread.
I understand that the Alert box is a popup and therefore may be unhandled. But can anyone help me, I want to show user a alert box, from different class.
Assuming that you want some long running code to run before the popup is called,
There are two steps that need to be done when dealing with the Fx Buttons. The first thread lets the code run as a thread when the button is pushed. The second is the Platform.runlater() which is telling the Fx Platform to execute the code in that thread from the Platform. Note that the popup will not get executed until the runlater is reached in the outer thread.
Otherwise you can call the popup directly.
public void MyExampleBtn() {
Thread t = new Thread() {
// long running work to be done, threaded so as not to hang the main controls.
// ....
// work is done do the success popup
#Override
public void run() {
Platform.runLater(new Runnable() {
#Override
public void run() {
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Success!");
alert.setHeaderText(null);
alert.setContentText("This is my popup");
alert.showAndWait();
}
});
}
};
}
Everything in the UI has to be executed from the UI application thread. That is exactly what the error message means.
Fortunately you can simply wrap your call so that it is executed in the UI thread:
if(isCommandLineRun) {
System.out.println(simpleDateFormat.format(new Date()) + " - " + message);
} else {
Platform.runLater(() -> controller.displayAlertMessages(message));
}
Finally found the solution to it,
Since Java fx runs on single thread, everything has to be on same thread. For every task (such as popup) where there needs background to pause, we need to use FutureTask.
I found this article, here :
JavaFX2: Can I pause a background Task / Service?
Related
I'm writing a Java program that acts as both a server and a client. Leaving out the irrelevant bits it has three classes: Main, Server and Client. Main just sets up a menu and contains the main method. Server and Client hold the algorithms for the server and the client respectively.
What I'm trying to do is to call the algorithm from the server and client classes and their GUIs depending on the button pressed. The code to call the server currently looks like this:
serverButton = new JButton();
serverButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
server.showGUI();
server.run();
}
});
The problem is that server.run() runs continuously for quite a long while and is a lot of heavy lifting. This bugs out the GUI, which from my understanding is because I'm calling the method from the EDT.
How can I call this method from the main thread? Do I need to create a SwingWorker and leave it there until the end of server.run()?
How can I call this method from the main thread?
This is how it is usually done in Swing.
public class WhatEverServer {
private UserInterface userInterface;
[...]
private static void createAndShowGUI() {
if( GraphicsEnvironment.isHeadless() )
logger.log( Level.FATAL, "This system seems to be 'headless'. Aborting now." );
else {
userInterface = UserInterface.getInstance();
userInterface.createAndShowUI();
}
}
public static void main( String[] args ) {
// schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater( new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
public class UserInterface {
...
public void createAndShowUI() {
// make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
// create and set up the window.
JFrame frame = new JFrame( "Whatever Server" );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set UI components, i.e
// set main menu bar
frame.setJMenuBar( this.mainMenuBar );
// set layout
frame.getContentPane().setLayout( new BorderLayout() );
// add UI components
// display the window.
frame.pack();
frame.setVisible(true);
}
}
This bugs out the GUI, which from my understanding is because I'm
calling the method from the EDT.
Yes, since the action is triggered by an event, the actionPerformed() is invoked by (or on) the EDT. I don't know what you are doing in server.run(), but I suppose this should not end up on the EDT.
Do I need to create a SwingWorker and leave it there until the end of
server.run()?
I would use SwingWorker or SwingUtilities in that case. You can write an ActionHandler in this way, using two threads, one for doing some of the 'heavy lifting', one for setting up the UI :
public void actionPerformed(ActionEvent e) {
new Thread(new Runnable {
public void run() {
...
// do some 'heavy lifting' here ...
SwingUtilities.invokeLater(new Runnable() {
public void run() {
server.setupUI();
}
)
...
// or do some 'heavy lifting' here
});
}
}
Make sure the server object reference is final and then invoke the method in a new thread in your actionPerformed method.
Runnable task = () -> {server.run();};
Thread thread = new Thread(task);
thread.start();
It depends on your requirement, if you want the user do not want anything to do until server returns, it is best to do it in a Busyindicator like :
public void actionPerformed( ActionEvent e )
{
BusyIndicator.showWhile(Display.getCurrent(), new Runnable()
{
#Override
public void run()
{
server.run();
}
});
}
This will show user a hour glass while the server run is going on and user is blocked from using UI.
Or
if you want the UI to be responsive, you need to call server.run() in a separate thread.
MyThread t = new MyThread()
{
public void run()
{
server.run();
}
}
t.start();
and it is good practice to add a listener to thread to notify completion of server response so UI can do its things.
t.addListener( new MyThreadListener()
{
public void serverDone()
{
Display.getDefault().asyncExec( new Runnable()
{
public void run()
{
}
});
}
});
Please note this is not complete code for thread listener, just for idea sake.
I'm trying to build a javafx app in which i need to respond to mouse movements and clicks together just like what happens in counter strike when you shoot. But the problem is when i press the mouse button it will not respond to mouse movements anymore until i release the mouse button. I want them both to work together in parallel. I tried to set my listeners in separate threads but it doesn't work.This is an image of a gun pointer.
Image image = new Image("/pointer.png"); // a 25*25 PNG icon
ImageView imageView = new ImageView(image);
scene.setCursor(Cursor.NONE);
and then :
scene.setOnMouseMoved(e -> {
imageView.setX(e.getX());
imageView.setY(e.getY());
});
scene.setOnMousePressed(e -> Toolkit.getDefaultToolkit().beep());
I also tried to put them in separate threads, it doesn't work either but if it does there is another problem, i cannot change the coordinates of a javafx component in another thread and i get this error -even if it doesn't cause an error it will not work:
java.lang.IllegalStateException: Not on FX application thread
scene.setOnMouseMoved(e -> {
Thread thread = new Thread() {
#Override
public void run() {
imageView.setX(e.getX()); // here i cannot do stuff related
imageView.setY(e.getY()); // to javafx components
}
};
thread.start();
});
scene.setOnMousePressed(e -> {
Thread thread = new Thread() {
#Override
public void run() {
Toolkit.getDefaultToolkit().beep());
}
};
thread.start();
});
I also tried this but it doesn't work either
scene.setOnMouseMoved(e -> {
imageView.setX(e.getX());
imageView.setY(e.getY());
scene.setOnMousePressed(event -> Toolkit.getDefaultToolkit().beep());
});
So how i can handle this problem, how i can respond to mouse clicks in parallel with mouse movements with no conflict.
When the mouse is clicked and held, instead of onMouseMoved use onMouseDragged with same method signature. I believe that should satisfy your requirements.
As for the exception, just for your information, in order to run code on JavaFX Application Thread simply call Platform.runLater(some Runnable code); So in your case
Thread thread = new Thread() {
#Override
public void run() {
Platform.runLater(() -> {
imageView.setX(e.getX()); // this will now run fine
imageView.setY(e.getY());
});
}
};
Nevertheless, there is absolutely no need for extra threads, since the capture of events will be propagated only to the JavaFX Application Thread. There are various ways of filtering or handling those events. More information about events can be found here
I have a GUI with a TextArea and a Save Button. When I press the latter the text is saved. This takes around 2 seconds. During the process of saving the buttons should get another caption than before and after saving.
Here is my code:
saveButton.setText("Saving...");
Util.print("Saving...");
Thread saveIt = new Thread(new Runnable() {
#Override public void run() {
Platform.runLater(() -> {
try {
Thread.sleep(2000);
} catch (Exception ex) {
Util.print(ex);
}
saveButton.setText("Saved!");
Util.print("Saved!");
});
}
});
saveIt.setDaemon(true);
saveIt.start();
What happens:
The following output is produced on the command line after pressing the button:
Saving...
Saved!
The command line prints "Saving..." directly after I click on saveButton. 2 seconds after pressing saveButton the command line prints "Saved!" and the button caption changes to "Saved!".
What I would expect:
The command line output and the button caption show "Saving..." directly after I click on the save button. After 2 seconds the caption changes to "Saved!".
How can I achieve the expected behaviour?
Thank you very much in advance for your help.
P.S.: I know so many people have had problems with changing GUI elements from Threads. I already read some articles on StackOverflow & the web about it, but this one's a too hard nut for me. Just for reference, here is some of the things I tried so far, among others Tasks:
Constantly Update UI in Java FX worker thread
Why am I getting java.lang.IllegalStateException "Not on FX application thread" on JavaFX?
javafx, update ui from another thread
http://blog.axxg.de/javafx-ui-thread-update/
I had to put the Thread.sleep() part out of the Platform.runLater() process. Seemingly runLater() must as few workload as possible.
Platform.runLater(() -> {
saveButton.setText("Saving...");
Util.print("Saving...");
});
Thread saveIt = new Thread(new Runnable() {
#Override public void run() {
try {
sleep(2000);
} catch (Exception ex) {
Util.print(ex);
}
Platform.runLater(() -> {
saveButton.setText("Saved!");
Util.print("Saved!");
});
}
});
saveIt.setDaemon(true);
saveIt.start();
try wrapping your first setText into a Platform.runLater like this:
Platform.runLater(() -> {
saveButton.setText("Saving...");
});
Every change made to a JavaFX UI component has to been called from the JavaFX thread using the Platform.runLater
I'm actually new to Java and SWT, so my question might sound dumb.
I've looked over the intrnet (and stackoverflow) but all the answers and examples are too complex for a noob like me.
I have a class, call it Admin. When I click a button, it launches a method in another class(Handler).
In Admin I have a progress bar, that should increase with the
operation in Handler.
I don't know how much time the operations in
Handler takes, but I know I have 9 of them.
I would like, somehow,
to inform Admin when each method has finished.
What I have so far: (non relevant parts omitted)
Admin.java:
ProgressBar bar = new ProgressBar(this, SWT.SMOOTH);
Button btn = new Button(this, SWT.NONE);
btn.setText("Update");
btn.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
btn.setEnabled(false);
thread.start();
}
});
Handler handler = new Handler();
final Thread thread = new Thread(){
public void run() {
handler.run();
for(int i=0; i<=10; i++) {
final int value = i;
try {
Thread.sleep(800);
} catch (Exception e) { }
display.asyncExec(new Runnable(){
public void run() {
bar.setSelection(value);
}
});
}
}
};
Handler.java:
public class Handler implements Runnable{
void m1() {...}
void m2() {...}
...
void m9() {...}
public void run()
{
m1();
m2();
...
m9();
}
With this implementation, the call to handler.run() works fine, and the progress bar is filling, but of course they are not "corelated" in any way.
I will appreciate your wisdom!
Thank you very much!
The highly coupled way of solving this, is to have the Handler take a ProgressBar as input in the constructor, and after m1() finishes, it updates the progress to 1/9 and so on. A better (more decoupled) way to do it, is that you can "listen" to Handler, and that Handler fires an event with its progress after each method finishes. Then you can update in the Admin.java.
I will ask you to consider using ProgressMonitorDialog from JFace if adding this library to your application is not much of a problem. Your code then would look something like below:
ProgressMonitorDialog dialog = new ProgressMonitorDialog(parent);
dialog.run(true, true, new IRunnableWithProgress() {
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
monitor.beginTask("my work", 9);
m1();
monitor.worked(1);
m2();
monitor.worked(1);
...
m9();
monitor.done;
}
});
You can also send the monitor instance into your m* methods for even detailed reporting. Have a look at SubProgressMonitor for dividing each one of your initial 9 ticks further before sending them into each m* method.
But this means that your progress bar is a new dialog which might not be acceptable to you so in that case the first answer suits your needs.
I am probably missing something here, but I'll try and explain what I want to achieve and then someone please tell me that I am doing it wrong(which I am :) ) and point me in the right direction?
I am using JavaFX 2.0, but I think this problem would lend itself to Swing, or any UI framework.
I want to develope a simple splash screen for my application, when the splash screen starts, I want to have a message label that will be used to update a user on whats happening, in regards to configuring up the back end of the application. My application start up has 2 steps, the first step uses Spring to initialise the Application Context, which in turn initialises the DB (JPA 2.0/Hibernate/etc). The second part of my application start up process will query the DB for the initial data which will be used to populate the UI. Both these steps need to be complete before I can close the splash screen, and between each step I want to update the label in the splash screen to let a user know which stage is being done at that time.
I have broken this down into the following simple program which uses JavaFX and a button, when the button is pressed a new thread is created, that starts another class, which just performs some count to an abitary value, and then another another thread is created to simlate the second step of the start up process, But my issue is here that the second thread attempts to run before the first thread has finished, and as a result runs into a NPE.
Below is a breakdown of some simple code that highlights this issue:
public class Test extends Application
{
private LongTester lt;
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage)
{
Button btn = new Button();
final Label lblText = new Label("Starting");
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
new Thread(new ConstructorRunnable()).start();
lblText.setText("More Loading?");
new Thread(new MethodRunnable()).start();
lblText.setText("Finished");
}
});
HBox root = new HBox();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private class ConstructorRunnable implements Runnable
{
#Override
public void run()
{
lt = new LongTester();
}
}
private class MethodRunnable implements Runnable
{
#Override
public void run()
{
lt.countAgain();
}
}
private class LongTester
{
public LongTester()
{
for (int idx = 0; idx < 1000000; idx++)
{
System.out.println("Constructor: " + idx);
}
}
public Boolean countAgain()
{
for (int idx = 0; idx < 1000000; idx++)
{
System.out.println("Method: " + idx);
}
return Boolean.TRUE;
}
}
}
Can anyone point out my mistake?
I'd advise using a Task to execute your startup tasks and message progress back to your splash screen (similar to the approach in this sample created for a prior stackoverflow question on splash screens). If you want stuff in your task to run sequentially, just use one thread for the task rather than two.
Sample code for your task might look something like:
final Task<Data> initTask = new Task() {
#Override protected Data call() throws InterruptedException {
updateMessage("Initializing Application");
MyApp.initializeAppContext();
updateMessage("Loading Data");
Data data = DB.loadData();
updateMessage("Data Loaded");
return data;
}
showSplash(initStage, initTask);
new Thread(initTask).start();
showMainStage(initTask.valueProperty());
To fix your problem, you can use a CountDownLatch
This can be used the following way:
private class ConstructorRunnable implements Runnable {
CountDownLatch gate_ = null;
public ConstructorRunnable(CountDownLatch gate){
gate_ = gate;
}
#Override
public void run() {
lt = new LongTester();
gate_.countDown(); // Signal the second thread to start
}
}
private class MethodRunnable implements Runnable{
CountDownLatch gate_ = null;
public MethodRunnable(CountDownLatch gate){
gate_ = gate;
}
#Override
public void run(){
CountDownLatch.await(); // Wait for the first thread to finish
lt.countAgain();
}
}
This can now be used like this:
CountDownLatch gate = new CountDownLatch(1);
new Thread(new ConstructorRunnable(gate)).start();
lblText.setText("More Loading?");
new Thread(new MethodRunnable(gate)).start();
lblText.setText("Finished");
On a side note: as your tasks are sequential, why is there a need for having several threads? Threads are made to run multiple tasks running in parallel and your case does not make a use case for threads as these operations are sequential