用VBox JavaFX中的ProgressIndicator替换TableView

时间:2014-10-01 15:09:25

标签: multithreading javafx tableview progress-indicator

我有一个与某些数据关联的TableView,一旦我点击了一个运行按钮,我就对该数据执行了一些处理。每行数据都是在一个单独的线程中处理的,当这些线程正在运行时,我想要一个ProgressInducator来替换它的vbox中的表。

附带的代码:

如果我停在哪里说“停止在这里工作” - 表格被替换为pi。 如果我继续等待线程加入 - 没有替换。 我错过了什么?

    runButton.setOnAction(
                new EventHandler<ActionEvent>() {
                    @Override
                    public void handle(final ActionEvent e) {
                        List<Thread> threadList = new ArrayList<Thread>();

                        int threadCounter = 0;
                        final ProgressIndicator pi = new ProgressIndicator(threadCounter);

                        vbox.getChildren().clear();
                        vbox.getChildren().addAll(pi);
                        for (ProductInTable product : data) {
                            Thread thread = new Thread(new Runnable() {
                                @Override
                                public void run() {
                                    try
                                    {
                                        product.calculate();
                                    } catch (IOException ioe) {
                                        ioe.printStackTrace();
                                    }
                                }
                            });
                            threadList.add(thread);
                            thread.start();
                        }

                        int x = threadList.size();

                        /** WORKS IF STOP HERE **/

                        // wait for all threads to end
                        for (Thread t : threadList) {
                            try {
                                t.join();
                                threadCounter++;
                                pi.setProgress(threadCounter / x);
                            } catch (InterruptedException interE) {
                                interE.printStackTrace();
                            }
                        }

                        /** DOESNT WORKS IF STOP HERE **/

1 个答案:

答案 0 :(得分:0)

Thread.join()阻止执行,直到线程完成。由于您在FX应用程序线程上调用此方法,因此您将阻止该线程直到所有工作线程完成。这意味着在这些线程完成之前,UI无法更新。

更好的方法可能是用任务表示每个计算,并使用setOnSucceeded在FX应用程序线程上更新完整任务的计数器。类似的东西:

runButton.setOnAction(
            new EventHandler<ActionEvent>() {
                @Override
                public void handle(final ActionEvent e) {

                    final ProgressIndicator pi = new ProgressIndicator(threadCounter);

                    vbox.getChildren().clear();
                    vbox.getChildren().addAll(pi);

                    final int numTasks = data.size();

                    // only access from FX Application thread:
                    final IntegerProperty completedTaskCount = new SimpleIntegerProperty(0);

                    pi.progressProperty().bind(completedTaskCount.divide(1.0*numTasks));

                    completedTaskCount.addListener(new ChangeListener<Number>() {
                        @Override
                        public void changed(ObservableValue<? extends Number> obs, Number oldValue, Number newValue) { 
                            if (newValue.intValue() >= numTasks) {
                                // hide progress indicator and show table..
                            }
                        }
                    });

                    for (final ProductInTable product : data) {
                        Task<Void> task = new Task<Void>() {
                            @Override
                            public Void call() {
                                try
                                {
                                    product.calculate();
                                } catch (IOException ioe) {
                                    ioe.printStackTrace();
                                }
                                return null ;
                            }
                        });
                        task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
                            @Override
                            public void handle(WorkerStateEvent event) {
                                completedTaskCount.set(completedTaskCount.get()+1);
                            }
                        });
                        new Thread(task).start();
                    }

                }
});

如果您可能在此处拥有大量项目,则应使用某种ExecutorService来避免创建太多线程:

ExecutorService exec = Executors.newFixedThreadPool(
    Runtime.getRuntime().availableProcessors()); // for example...

然后替换

new Thread(task).start();

exec.submit(task);
相关问题