#java #javafx
#java #javafx
Вопрос:
У меня есть кнопка подключения в приложении и две панели, размещенные на панели стека. Первая панель — chatPane, а вторая панель — загрузчик с .gif, установленным на его фоне.
Что я хочу сделать, так это после нажатия кнопки подключиться, я хочу отобразить загрузчик (с движущимся gif на его фоне), затем дождаться завершения метода delegate.ConnectToServer(..), а после этого выключить панель загрузчика и переключиться обратно на chatPane.
С текущим кодом кажется, что поток приложения JavaFX не визуализирует изменения, внесенные в графический интерфейс, пока не достигнет конца метода connectClicked(), что означает, что панель загрузчика не отображается.
Я попытался запустить содержимое метода setConnectionStatus в качестве задачи в потоке, но при этом я получил Not On fx application thread
исключение методом setText объекта Label, однако загрузчик gif отображался красиво.
Я также пытался использовать переход паузы следующим образом:
@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();
}
Это привело к тому, что панель загрузчика отображалась движущейся в течение 0,1 с, и после этого анимация остановилась (панель загрузчика осталась видимой, только gif остановился)
Я также попытался обернуть блок try catch с Platform.runLater()
помощью or Thread
, но это не имело никакого эффекта.
Я не могу использовать Platform.runLater
для отображения загрузчика, потому что я хочу, чтобы изменения в графическом интерфейсе выполнялись немедленно, а не «когда-нибудь в будущем»
Вот полный код:
@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);
}
Комментарии:
1. Поместите свою логику в поток, отличный от потока пользовательского интерфейса.
2. Обертывание блока try catch потоком не имело никаких эффектов, панель загрузчика по-прежнему не отображается
3. Google для «фоновой задачи JavaFX», и я уверен, что вы найдете много ресурсов. Логика, не связанная с пользовательским интерфейсом (например, установление соединения, что занимает много времени), должна выполняться вне потока пользовательского интерфейса. Логика пользовательского интерфейса (например, обновление метки) должна выполняться в потоке пользовательского интерфейса.
4. Включение логики в поток сработало, это была просто моя глупость, потому что я использовал thread.run() вместо thread.start()
Ответ №1:
Похоже, что обертывание блока try catch с помощью потока сработало, раньше это не работало, потому что я использовал thread.run() вместо thread.start() …
Также мне пришлось добавить Platform.runLater в setConnectionStatus
методы внутри тела потока.