KamilBuczko
KamilBuczko

Reputation: 37

Main application thread not updating GUI until it reaches end of the method

I am having a connect button in application, and two panes placed on a stack pane. First pane is chatPane and second Pane is a loader with .gif set on his background.

What I want to do is after clicking connect, I want to display loader (with moving gif on his background), then wait until delegate.connectToServer(..) method ends, and after that turn off the loader Pane and switch back to chatPane.

With current code it seems like javaFX application thread is not visualizing changes made to GUI, until it reaches end of connectClicked() method, that means loader Pane is not being displayed.

I tried running content of setConnectionStatus method as Task in a Thread, but while doing that i received Not On fx application thread exception by setText method of Label object, however loader gif was displayed nicely.

I also tried using pause transition like this:

@FXML
public void connectClicked() {
    setConnectionStatus(CONNECTING);
    PauseTransition pause = new PauseTransition(Duration.seconds(0.1));

    pause.setOnFinished(event -> {
        try {
            delegate.connectToServer(connectionConfig.getServerAddress().getIp(),
                        connectionConfig.getServerAddress().getPort(),
                        connectionConfig.getTimeout());
            setConnectionStatus(CONNECTED);
            } catch (ConnectionException e) {
                setConnectionStatus(DISCONNECTED);
                //todo reconnect dialog
            } catch (FatalException e) {
                handleFatalError("Connection error", e.getMessage());
            }
        });
        pause.play();
    }

It resulted in loader Pane being shown moving for 0.1s, and after that animation stopped (loader Pane remained visible, only gif stopped)

I also tried wrapping try catch block with Platform.runLater() or Thread, but it had no effect.

I can't use Platform.runLater for loader displaying because i want gui changes to be performed immediately, not "some time in the future"

Here is a full code:

@FXML public VBox loader;
@FXML public SplitPane chatPane;
@FXML public MenuItem connectMenuItem;
@FXML public MenuItem disconnectMenuItem;
@FXML public Label connectionStatus;

@FXML
public void connectClicked() {
       setConnectionStatus(CONNECTING);
        try {
            delegate.connectToServer(connectionConfig.getServerAddress().getIp(),
                    connectionConfig.getServerAddress().getPort(),
                    connectionConfig.getTimeout());
            setConnectionStatus(CONNECTED);

        } catch (ConnectionException e) {
            setConnectionStatus(DISCONNECTED);
            //todo reconnect dialog
        } catch (FatalException e) {
            handleFatalError("Connection error", e.getMessage());
        }
    }

     private void setConnectionStatus(ConnectionStatus status) {
        switch (status) {
            case CONNECTED:
                setStatusLabel("Connected", GREEN);
                setConnectionMenu(false, true);
                showChatPane();
                break;
            case DISCONNECTED:
                setStatusLabel("Not Connected", RED);
                setConnectionMenu(true, false);
                showChatPane();
                break;
            case CONNECTING:
                setStatusLabel("Connecting...", BLUE);
                setConnectionMenu(false, false);
                showLoader();
                break;
            case DISCONNECTING:
                setStatusLabel("Disconnecting...", BLUE);
                setConnectionMenu(false, false);
                showLoader();
                break;
        }
    }

    private void setStatusLabel(String text, Color color) {
        connectionStatus.setText(text);
        connectionStatus.setTextFill(color);
    }

    private void setConnectionMenu(boolean isConnectEnabled, boolean isDisconnectEnabled) {
        connectMenuItem.setDisable(!isConnectEnabled);
        disconnectMenuItem.setDisable(!isDisconnectEnabled);
    }

    private void showLoader() {
        chatPane.setVisible(false);
        loader.setVisible(true);
    }

    private void showChatPane() {
        chatPane.setVisible(true);
        loader.setVisible(false);
    }

Upvotes: 1

Views: 240

Answers (1)

KamilBuczko
KamilBuczko

Reputation: 37

Looks like wrapping try catch block with a thread worked, it did not work earlier because i was using thread.run() instead of thread.start() ...

Also i had to add Platform.runLater on setConnectionStatus methods inside thread body.

Upvotes: 1

Related Questions