簡體   English   中英

Javafx如何實現忙和等待對話框例程

[英]Javafx how to implement a busy and wait dialog routine

我有一個問題,像在執行過程時JavaFX不確定進度條處暴露的問題,但是我使用javafx對話框Alert來顯示一個在進度條內部使用如下代碼的對話框:

Alert busyWaitAlert = new Alert(
Alert.AlertType.INFORMATION);
busyWaitAlert.setContentText("Operation in progress");                
ButtonType cancelButton = new ButtonType("Cancel", ButtonBar.ButtonData.FINISH);                    
busyWaitAlert.getButtonTypes().setAll(cancelButton);
busyWaitAlert.setTitle("Running Operation");
busyWaitAlert.setHeaderText("Please wait... ");
ProgressBar progressBar = new ProgressBar();                   
busyWaitAlert.setGraphic(progressBar);
progressBar.setProgress(ProgressBar.INDETERMINATE_PROGRESS);

Task<Boolean> task;
task = new Task<Boolean>() {
   @Override 
    public Boolean call() throws Exception {       
      Collections.sort(LnkListImportedToDb, new importDataToDb.DataItemImportedToDbTimeCmp1()); 
      return true;
    }
 };

   task.setOnSucceeded((e) -> {                        
        busyWaitAlert.close();                      
    });

    progressBar.progressProperty().bind(task.progressProperty());
    busyWaitAlert.contentTextProperty().bind(task.messageProperty());

    new Thread(task).start();      

問題是,在Task內,我調用了Collection.Sort,我不知道其持續時間,並且無法在“ Task call”方法內執行updateMessage,否則,Alert對話框不會凍結。 我想通過在第一個Task的調用中插入另一個管理Collection.sort的Task來解決該問題,是否有更好的解決方案?

Task或更一般地說是Worker的目的是在后台線程上運行長時間運行的進程,同時能夠向用戶更新其進度。 Task類為您提供了許多允許與JavaFX Application Thread安全通信的方法,例如updateProgressupdateMessagesetOnSucceeded 無需使用這些功能即可使用Task 並且不使用這些功能不會對Task任何形式的損害。

例如,您可能有一個非常簡單的Task ,如下所示:

public class TaskImpl<E> extends Task<Void> {
    private final List<E> list;

    public TaskImpl(List<E> list) { this.list = list; }

    @Override protected Void call() throws Exception {
        list.sort(null);
        return null;
    }
}

在這里,該代碼沒有利用Task優勢,只是用於對后台線程中的List進行排序。 外部代碼仍然可以觀察Task ,而不會產生不良影響。 例如,您的Alert不會凍結,因為未更新messageprogress屬性。

但是,如果您不打算使用Task的功能,則最好只使用普通的RunnableCallable 上面的功能等效於:

() -> list.sort(null);

RunnableTask (實現Runnable )都有一些共同點:沒有人願意為您在單獨的線程上運行自身。 您實際上必須將工作傳遞給另一個線程。 您可以通過直接創建一個Thread或使用java.util.concurrent包中提供的Executor框架(更好的選擇)來Executor此操作。

話雖如此,我不確定我是否理解您遇到的問題。 由於您不知道對List.sort的調用將占用Taskprogress屬性多長時間, List.sort應該保持不確定狀態。 如果要顯示一條消息,可以執行以下操作:

@Override protected Void call() {
    updateMessage("Sorting...");
    list.sort(null);
    updateMessage("Sorting complete.");
    updateProgress(1, 1); // jumps progress from indeterminate to 100%
    return null;
}

然后,將適當的控件綁定到適當的屬性,將這些控件添加到Alert ,然后顯示Alert 這是有關如何執行此操作的完整示例:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main extends Application {

    private List<Integer> integerList;

    @Override
    public void init() {
        /*
         * If there is at least one parameter attempt to parse the
         * first one as an Integer. This value will be used as the
         * size of the randomly generated "integerList".
         *
         * If there are no parameters then default to 10 million.
         */
        List<String> params = getParameters().getRaw();
        if (!params.isEmpty()) {
            generateRandomList(Integer.parseInt(params.get(0)));
        } else {
            generateRandomList(10_000_000);
        }
    }

    private void generateRandomList(int size) {
        System.out.printf("Generating random list of %,d integers...%n", size);
        Random r = new Random();
        integerList = Stream.generate(() -> r.nextInt(size))
                .limit(size)
                .collect(Collectors.toList());
        System.out.println("List generated.");
    }

    @Override
    public void start(Stage primaryStage) {
        System.out.println("Building scene graph...");
        ListView<Integer> listView = new ListView<>();
        listView.setPrefWidth(500);
        listView.getItems().addAll(integerList);

        Button btn = new Button("Sort List");
        btn.setOnAction(ae -> {
            ae.consume();
            btn.setDisable(true);

            /*
             * Here we create the task and configure it to set items of the listView
             * to the result. We do this because we are sorting "integerList" which
             * we had *copied* into the ListView. If  we sorted the items of the ListView
             * then we would be altering the UI from a background thread (big no-no!).
             * Therefore we need to re-copy the "integerList" into the ListView upon
             * completion of the task.
             */
            SortingTask<Integer> task = new SortingTask<>(integerList, null);
            task.setOnSucceeded(wse -> listView.getItems().setAll(task.getValue()));

            Alert alert = createProgressAlert(primaryStage, task);
            executeTask(task);
            alert.show();
        });

        VBox root = new VBox(btn, listView);
        root.setSpacing(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(20));
        VBox.setVgrow(listView, Priority.ALWAYS);

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Progress Alert Example");
        primaryStage.setResizable(false);
        primaryStage.show();
        System.out.println("Primary stage displayed.");
    }

    // executes task on a separate, daemon thread
    private void executeTask(Task<?> task) {
        Thread t = new Thread(task, "sorting-thread");
        t.setDaemon(true);
        t.start();
    }

    // creates the Alert and necessary controls to observe the task
    private Alert createProgressAlert(Stage owner, Task<?> task) {
        Alert alert = new Alert(Alert.AlertType.NONE);
        alert.initOwner(owner);
        alert.titleProperty().bind(task.titleProperty());
        alert.contentTextProperty().bind(task.messageProperty());

        ProgressIndicator pIndicator = new ProgressIndicator();
        pIndicator.progressProperty().bind(task.progressProperty());
        alert.setGraphic(pIndicator);

        alert.getDialogPane().getButtonTypes().add(ButtonType.OK);
        alert.getDialogPane().lookupButton(ButtonType.OK)
                .disableProperty().bind(task.runningProperty());

        alert.getDialogPane().cursorProperty().bind(
                Bindings.when(task.runningProperty())
                    .then(Cursor.WAIT)
                    .otherwise(Cursor.DEFAULT)
        );

        return alert;
    }

    // The Task implementation

    private static class SortingTask<E> extends Task<List<E>> {

        private final List<E> list;
        private final Comparator<? super E>  comparator;

        private SortingTask(List<E> list, Comparator<? super E> comparator) {
            this.list = Objects.requireNonNull(list);
            this.comparator = comparator; // if null then natural order is used by List.sort
            updateTitle("Sorting Task");
        }

        @Override
        protected List<E> call() throws Exception {
            updateMessage("Sorting list...");
            list.sort(comparator);
            updateMessage("Sorting complete.");
            updateProgress(1, 1);
            return list;
        }

        @Override
        protected void running() {
            System.out.println("Sorting task is running...");
        }

        @Override
        protected void succeeded() {
            System.out.println("Sorting task successful.");
        }

    }

}

如果要自定義隨機生成的列表的大小,可以將整數作為參數傳遞給該程序。 如果傳遞了多個參數,則除第一個以外的所有參數都將被忽略。 如果未提供任何參數,則大小默認為10,000,000(1000萬)。 根據您的計算機,您可能需要增加或減小列表的大小,以使Task不會太快(或花費太長時間)完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM