2

I have a "little" issue with Service usage. The code below doesn't work: text value isn't updated in HMI but its value is correct !!?

public class FilterController
{
    @FXML
    private TextField       totalItemCount;

    private final Service service = new Service() {
        @Override
        protected Task createTask() 
        {
            return new Task<Void>() {
                @Override protected Void call() throws Exception {

                    int  x = (int) (Math.random() * 10000);
                    System.out.println("x = " + x);

                    try {
                        totalItemCount.setText(Integer.toString(x));
                        System.out.println("totalItemCount = " + totalItemCount.getText());
                    }
                    catch (Throwable ex)
                    {
                        System.err.println("Fail");
                        ex.printStackTrace();
                    }
                    return null;
                }
            };
        }

        @Override
        protected void failed()
        {
            super.failed();
            System.err.println("FAILED");
        }
    };

    @FXML
    public void handleFindProblemsEvent()
    {
        System.out.println("Handle Find Problems");
        service.restart();
    }
}

I don't have any error. Fail message isn't displayed, so I can think that job has been done but it's not the case. Is it a bug or a bad usage ? Thanks for your help.

Note: I use jre1.8.0_25

Linuski
  • 63
  • 1
  • 8

3 Answers3

0

You have not called the failed() method anywhere.

question
  • 392
  • 1
  • 4
  • 15
  • Sorry, my description isn't complete. For this test case, I have a button in my HMI and a textfield. The button's action execute handleFindProblemsEvent() method which start the thread (service.restart()) The method failed() is provided in case of service's error. I don't have to call this method. – Linuski Dec 25 '14 at 18:56
0

I assume you Task is executed in its own thread so you need to sync calls to fx APIs with Platform.runLater

tomsontom
  • 5,856
  • 2
  • 23
  • 21
  • Can you explain more. I not sure to understand exactly why I need to use runLater in this case. In fact, in my real application, the textField totalItemCount is binded with a property (not seen here), but to reduce the problem, I used setText in place of bind mechanism. Did you said I must use runLater for setText only ? – Linuski Dec 26 '14 at 16:59
0

JavaFX is a single thread GUI toolkit, so every update of a GUI component has to be done on the main application (JavaFX) thread.

What you are doing there, is trying to update a TextField from a background thread and an IllegalStateException will get thrown.

The Task and Service classes are meant to compute something in the background and do a GUI update afterwards.

Like explained over here and over here, you should create a Task<Integer> and return the computed value. If this succeeds, you can retrieve the value in the succeeded() method with getValue() and set the value to the TextField. The succeeded() method is getting called from the GUI Thread, so its safe to update the TextField here.

Community
  • 1
  • 1
eckig
  • 10,964
  • 4
  • 38
  • 52
  • Sorry but I didn't see any exception but your answer is interesting in this case because I must change the textfield at the end of this process. So in this case it's a good solution. So ok, thread cannot do GUI so how can we do if I need to update periodically a GUI component ? – Linuski Dec 28 '14 at 19:21
  • For periodic updates with a fixed interval, use a TimeLine: http://stackoverflow.com/questions/26916640/javafx-not-on-fx-application-thread-when-using-timer/26916766#26916766 – eckig Dec 29 '14 at 08:30
  • Thanks a lot for all these explanations. – Linuski Dec 29 '14 at 09:42