Good time of day.

I have a small issue related to multithreading in JavaFX . To be more precise, I have some table that is formed by getting the state of an object from the server. If some field has changed, you need to update it in this table, change the display (color, text size, etc.) and, possibly, throw out the informative dialog. Since there may be several such objects, I used TabPane, and on each tab of the GridPane (actually, the table itself), there is a thread for each tab, which polls the server and compares the obtained values ​​with the existing ones. GridPane consists of objects of type Label , in which I try to change the state.

Not on FX application thread

I was looking for solutions, but I did not find anything worthwhile, because I need to poll the server every n seconds. Using Platform.runLater(Thread) doesn't work, since I need to poll the server, fall asleep for n seconds, and poll again, and if I try to fall asleep, my application also falls asleep with this stream.

Here is the thread that I run on each tab:

 public class Seeker extends Thread { private User userBefore; private Label[] labelsBefore; private Label[] labelsNow; public Seeker(User userToSeek, Label[] labelsBefore, Label[] labelsNow) { userBefore = userToSeek; this.labelsBefore = labelsBefore; this.labelsNow = labelsNow; } @Override public void run() { while (true) { TimeHelper.sleep(1000); User userNow = APIHolder.getUserAPI().getInfo(userBefore.getHandle()).getResult().get(0); if (!userBefore.equalsAllFields(userNow)) { List<String> fieldNames = ReflectionHelper.getFieldNames(User.class); List<String> userFieldValuesBefore = ReflectionHelper.getFieldValues(fieldNames, userBefore); List<String> userFieldValuesNow = ReflectionHelper.getFieldValues(fieldNames, userNow); for (int i = 0; i < fieldNames.size(); i++) { String valueBefore = userFieldValuesBefore.get(i); String valueNow = userFieldValuesNow.get(i); if (!valueBefore.equals(valueNow)) { if (isTime(fieldNames.get(i))) { labelsNow[i].setText(getTimeFromMillis(valueNow)); } else { labelsNow[i].setText(valueNow); } labelsBefore[i].setTextFill(Color.DARKRED); labelsBefore[i].setFont(Font.font("System", FontWeight.BOLD, 15)); labelsNow[i].setTextFill(Color.DARKGREEN); labelsNow[i].setFont(Font.font("System", FontWeight.BOLD, 15)); } } userBefore = userNow; } } } 

Tell me how you can implement it.

  • As usual. Calculate everything in the background thread, and update the UI in the UI stream. How exactly to transfer the task to the UI-stream is probably in the documentation. - VladD
  • And can you detail, please? And then I can not imagine how to do it - PloadyFree
  • one
    If you believe Google, you need Platform.runLater . - VladD
  • And what am I going to throw in runLater? My Seeker? So then I will fall asleep my application forevermore. - PloadyFree
  • In runLater you runLater only the part that updates the UI. All calculations remain in the background thread. In this case, of course, you will have to divide the code into parts: the first part collects the necessary data, the second updates the UI (for some reason you have everything mixed up). - VladD

1 answer 1

In JavaFX, you cannot change the state of a UI object that is not in a UI stream. Use the Observer pattern to notify the UI of a model change.