Я много дней боролся за глупую проблему, и мне нужна ваша помощь. Я просто пытаюсь отобразить индикатор неопределенного процесса, как показано ниже, на отдельной стадии, в то время как мой основной код выполняет цикл. Если во время цикла выполняется определенное условие, этап выполнения должен быть закрыт, а основной код будет продолжен.Индикатор прогресса не будет отображаться до тех пор, пока главный код не остановится
Прямо сейчас я могу открыть новый этап перед основным кодом исходного цикла, но индикатор прогресса не будет отображаться на сцене еще. Но как только условие выполнено, индикатор внезапно появляется на сцене и вращается. НО, как только основной код начинает работать снова, индикатор замерзает, но остается видимым.
Я кратко объясню, что делает каждый код ниже. Как это сделать так, чтобы начался этап загрузки с видимым индикатором, а затем этот этап ЗАКРЫТСЯ, когда вызывается метод showMessage()
? В основном я хочу показать пользователю, что происходит цикл фонового цикла, до тех пор, пока основной код не достигнет showMessage()
.
Main.java Я не буду публиковать его, так как он создает только ПЕРВЫЙ GUI. Он использует menu.fxml
в качестве ресурса в FXMLLoader
... и menu.fxml
использует Controller.java
в качестве контроллера.
Controller.java Этот код изменяет сцену в главном графическом интерфейсе, чтобы новый макет, который предлагает пользователю нажать одну из видимых кнопок. Затем он проверяет, является ли кнопка источника Button1
... и если она затем создает/показывает новый этап, который использует sample.fxml
в качестве ресурса. Затем он запускает конечный файл, Loop.java
public class Controller implements Initializable {
public Stage loadingStage;
@FXML
ProgressIndicator progressIndicator;
public void handlerButtonClick() throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("field.fxml"));
Parent rootOne = loader.load();
((Controller) loader.getController()).setPrimaryStage(primaryStage);
((Controller) loader.getController()).setPrimaryScene(scene);
sceneField = new Scene(rootOne, 420, 510);
primaryStage.setScene(sceneField);
primaryStage.setTitle("Import Data");
primaryStage.show();
}
public void fieldOption(ActionEvent e) throws Exception {
source = e.getSource();
if (source == Button1) {
Loop loopObj = new Main();
String[] args = {};
//Create new stage to contain the Progress Indicator
FXMLLoader loader2 = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root2 = loader2.load();
Controller2 controller = loader2.getController();
loadingStage = new Stage();
loadingStage.setTitle("Loading Stage");
Scene scene = new Scene(root2, 200, 200);
loadingStage.setScene(scene);
loadingStage.show();
//Runs the looper
loopObj.start(stage);
}
}
Sample.fxml
Этот код создает индикатор хода и использует контроллер Controller2
<AnchorPane prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/2.2" fx:controller="Controller2">
<children>
<ProgressIndicator fx:id="progressIndicator" layoutX="78.0" layoutY="55.0" progress="-1.0"/>
</children>
</AnchorPane>
Controller2.java Этот код реализует Initializable
, чтобы индикатор хода был видимым:
public class Controller2 implements Initializable {
@Override
public void initialize(URL url, ResourceBundle rb) {
ProgressIndicator progressIndicator = new ProgressIndicator();
progressIndicator.setVisible(true);
}
}
Loop.java Это основной код, который выполняет цикл. На этапе загрузки должен отображаться индикатор хода доLoop.java
вызывает функцию showMessage()
, после чего стадия загрузки закрывается. Я знаю, что кажется, что один из этих методов не нужен, но только потому, что они лишены демо-целей.
public class Loop extends Application {
@Override
public void start(Stage ignored) throws Exception {
Platform.setImplicitExit(false);
for (int i = 0; i <= 100; i++) {
if (i == 75){
saveAttachment("Hello");
}
}
}
public static void saveAttachment(String subject) throws IOException, MessagingException {
showMessage(subject);
}
private static void showMessage(String subject) throws IOException, MessagingException {
// Close the loading stage here.
}
}
Обратите внимание, как он использует public void start(Stage ignored)
. Main.java использует public void start(Stage primaryStage)
. Возможно, это плохо. Я так расстроен, пожалуйста, помогите!
UPDATE
Я применил предложения Брайана, и в Controller.java
добавил новую задачу следующим образом:
Stage loadingStage = new Stage();
//create task object
Task<Void> task = new Task<Void>(){
@Override
protected Void call() throws Exception{
System.out.println("Background task started...");
FXMLLoader loader2 = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root2 = loader2.load();
Controller2 controller = loader2.getController();
loadingStage.setTitle("Hello World");
Scene scene = new Scene(root2, 450, 250);
System.out.println("HERE6");
loadingStage.setScene(scene);
System.out.println("HERE7");
loadingStage.show();
System.out.println("HERE8");
return null;
}
};
Thread th = new Thread(task);
th.setDaemon(true);
System.out.println("Starting background task...");
th.start();
Сейчас проблема заключается в том, что она не достигает распечатку линии говорит "HERE7". Он успешно входит в задачу и продолжает основной код, но задача не выходит за пределы, где печатается «ЗДЕСЬ», поэтому новый этап не открывается. Что дает?
Вы не можете обновить пользовательский интерфейс в фоновом потоке, поэтому он генерирует исключение в 'loadStage.setScene (...)'. Но я не понимаю, почему вы так делаете эту часть в фоновом потоке. Наверняка это цикл 'for' со всеми вызовами' saveAttachment', который занимает много времени? Возможно, прочитайте мой ответ на http://stackoverflow.com/questions/30249493/using-threads-to-make-database-requests для получения некоторой исходной информации. Документы API '' Task' (http://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html) полны примеров. –
Спасибо, я сейчас занимаюсь ремеслом и чтением. Отчитается. –
Я дошел до того, что сцена открылась правильно, но я узнал, что для этой цели требуется «FutureTask». –