0

I'm using a TableView backed by an ObservableList of Renderer objects which is set up like this:

private ObservableList<Renderer> renderers = FXCollections.observableArrayList();

@FXML
private TableView<Renderer> renderersTable;
@FXML
private TableColumn<Renderer, String> nameColumn;
@FXML
private TableColumn<Renderer, Boolean> approvedColumn;

@FXML
private void initialize() {
    nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
    approvedColumn.setCellValueFactory(new PropertyValueFactory<>("approved"));
    renderersTable.setItems(renderers);
}

The Renderer objects are very simple and look like this:

@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class Renderer extends Model {
    private String name;
    private boolean approved;
    // ...
}

I have a function that gets called from the UI, by pressing a button and contains something like:

@FXML
private void approveSelectedRenderers() {
    List<Renderer> selectedRenderers = new ArrayList<>();
    selectedRenderers.addAll(renderersTable.getSelectionModel().getSelectedItems());

    for (Renderer renderer : selectedRenderers) {
        renderer.setApproved(true);
        renderers.set(renderers.indexOf(renderer), renderer);
        Thread.sleep(3000); // Simulate slowly talking to the network.
    }
}

I was expecting to see the change to approved on each row once every 3 seconds, but instead, it does all the rows, and only after that it updates the UI. Why is that? How do I make the UI update?

Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622

1 Answers1

1

It appears all your rendering is happening on the FX Thread. This will block your UI until all processing has completed and then will update.

To look at long running processes - use a Task or a Service and in their update call backs you can update the UI.

You can also use Platform.runLater() to post back to the UI thread from a thread that is running in the background.

purring pigeon
  • 4,141
  • 5
  • 35
  • 68
  • All the rendering should happen in the FX thread, shouldn't it? – Pablo Fernandez Oct 23 '17 at 21:10
  • 2
    Yes it should - but you thread.sleep() is pausing the FX thread. So you can update your model in the background and use Platform.runLater() to push those updates to the thread at which point they will render on the next pulse. – purring pigeon Oct 23 '17 at 21:16