JavaFX更新进度栏,等待线程完成

时间:2019-04-25 13:29:04

标签: java multithreading user-interface javafx

我正在尝试更新Java FX中的进度条。我的第一个问题是窗口说“不响应”,而不是实际更新。它只是冻结,然后在完成任务后,进度条就满了。因此我发现我必须使用多线程并像这样实现它。

overallList.clear();
progressbar.setprogress(0);

for(Object obj : list) {
    class ThreadProgress implements Runnable { // inner class
        public void run() {
            thisList = scrape(obj);
            overallList.add(thisList);
            progressbar.setProgress(progressbar.getProgress() + (double)1/size);
        }
    }

    Thread current = new Thread(new ThreadProgress());
    current.start();
}

textAreaConsole.setText("Total number of things:" + overallList.size());

但是现在的问题是,最后一行打印“事物总数:0”,因为线程在机器运行最后一行之前并未真正完成执行。然后,我发现了多种解决方法,特别是使用join()或ExecutorService。我这样实现了join()。

overallList.clear();
progressbar.setprogress(0);
List<Thread> threads = new ArrayList<Thread>();

for(Object obj : list) {
    class ThreadProgress implements Runnable { // inner class
        public void run() {
            thisList = scrape(obj);
            overallList.add(thisList);
            progressbar.setProgress(progressbar.getProgress() + (double)1/size);
        }
    }

    Thread current = new Thread(new ThreadProgress());
    current.start();
    threads.add(current);
}

for(Thread thread : threads) thread.join(); // with a try-catch loop

textAreaConsole.setText("Total number of things:" + overallList.size());

但是,这使我回到了最初的问题,窗口再次显示“不响应”。 ExecutorService也发生了同样的事情。我不知道该怎么办。

1 个答案:

答案 0 :(得分:3)

请参阅下面的示例应用程序。它提供了一个简单的$(".mobile-toggle").click(function() { if ($(this).hasClass("inactive")) { $(this).removeClass("inactive"); $(this).addClass("active"); //find current toggle element parent, then find next element(wrapper of the images) and finally find children image. $(this).parent('.platform-toggle').next('.platform-images').children('.mobile-image').show(); $(this).siblings('.desktop-toggle').removeClass("active"); $(this).siblings('.desktop-toggle').addClass("inactive"); $(this).parent('.platform-toggle').next('.platform-images').children('.desktop-image').hide(); } }); 和一个ProgressBar来演示如何使用后台Label的进度更新UI。

代码也被注释。

Task
  

编辑:添加了import javafx.application.Application; import javafx.concurrent.Task; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ProgressBar; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class ProgressBarExample extends Application { // Create our ProgressBar private ProgressBar progressBar = new ProgressBar(0.0); // Create a label to show current progress % private Label lblProgress = new Label(); public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { // Simple interface VBox root = new VBox(5); root.setPadding(new Insets(10)); root.setAlignment(Pos.CENTER); // Button to start the background task Button button = new Button("Start"); button.setOnAction(event -> startProcess()); // Add our controls to the scene root.getChildren().addAll( progressBar, new HBox(5) {{ setAlignment(Pos.CENTER); getChildren().addAll( new Label("Current Step:"), lblProgress ); }}, button ); // Here we will // Show the Stage primaryStage.setWidth(300); primaryStage.setHeight(300); primaryStage.setScene(new Scene(root)); primaryStage.show(); } private void startProcess() { // Create a background Task Task<Void> task = new Task<Void>() { @Override protected Void call() throws Exception { // Set the total number of steps in our process int steps = 1000; // Simulate a long running task for (int i = 0; i < steps; i++) { Thread.sleep(10); // Pause briefly // Update our progress and message properties updateProgress(i, steps); updateMessage(String.valueOf(i)); } return null; } }; // This method allows us to handle any Exceptions thrown by the task task.setOnFailed(wse -> { wse.getSource().getException().printStackTrace(); }); // If the task completed successfully, perform other updates here task.setOnSucceeded(wse -> { System.out.println("Done!"); }); // Before starting our task, we need to bind our UI values to the properties on the task progressBar.progressProperty().bind(task.progressProperty()); lblProgress.textProperty().bind(task.messageProperty()); // Now, start the task on a background thread new Thread(task).start(); } } setOnFailed()方法。