1

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/

Community
  • 1
  • 1
Johann Hagerer
  • 1,048
  • 2
  • 10
  • 28

2 Answers2

2

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

Hamza Anis
  • 2,475
  • 1
  • 26
  • 36
Jonathan Fortin
  • 342
  • 3
  • 14
  • It works in about 1 out of 10 cases. I've tried wrapping in a seperate Thread like in example code, doesn't work either. Also not if I utilize Thread.join(). – Johann Hagerer Jun 11 '15 at 15:49
2

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();
Johann Hagerer
  • 1,048
  • 2
  • 10
  • 28