JavaFX UI冻结问题

Ash*_*oli 5 java concurrency multithreading javafx-2

我试图显示每项任务的进度和状态.每个任务代表一行TableView.每个任务在每个任务中并行执行Thread.请参考图片TableView.

在此输入图像描述

对于"Progress",TableColumn我已将Cell Factory设置为渲染"ProgressBar".

  public static class ProgressBarTableCell<S, T> extends TableCell<S, T> {

        private final ProgressBar progressBar;
        private ObservableValue<T> ov;

        public ProgressBarTableCell() {
            this.progressBar = new ProgressBar();
            progressBar.setPrefHeight(23);
            setAlignment(Pos.CENTER);
        }

        @Override
        public void updateItem(T item, boolean empty) {
            super.updateItem(item, empty);
            if (item == null) {
                setGraphic(null);
                setText(null);
            } else {
                if (item.toString().equalsIgnoreCase("Processing")) {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {

                            if (getGraphic() == null) {
                                setGraphic(progressBar);
                                progressBar.setProgress(-1);
                            } else {
                                ProgressBar objpProgressBar = (ProgressBar) getGraphic();
                                objpProgressBar.setProgress(-1);
                            }
                            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                        }
                    });
                } else {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            if (getGraphic() == null) {
                                setGraphic(progressBar);
                                progressBar.setProgress(0);
                            } else {
                                ProgressBar objpProgressBar = (ProgressBar) getGraphic();
                                objpProgressBar.setProgress(0);
                            }
                            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                        }
                    });
                }
            }
        }
    } 
Run Code Online (Sandbox Code Playgroud)

TableView未显示更新的状态和任务的进度,所以我正在定期后台线程,修改TableView当我打电话startUpdatingTableProgress()并停止当我打电话stopUpdatingTableProgress() .

 public void stopUpdatingTableProgress() {
    keepUpdating = false;
}

public void startUpdatingTableProgress() {
    keepUpdating = true;
    TableProgressBarUpdator tpu = new TableProgressBarUpdator(table);
    tpu.start();
}

class TableProgressBarUpdator implements Runnable {

    TableView table;

    public TableProgressBarUpdator(TableView fxtable) {
        table = fxtable;

    }

    public void start() {
        new Thread(this).start();
    }

    public void run() {

        while (keepUpdating) {
            try {
                updateProgressbar();
                Thread.sleep(1000);
            } catch (Exception e) {
                LogHandler.doErrorLogging("Error while updating tables cell", e);
            }
        }
        LogHandler.doDebugLogging("Table process repainting is completed.");
    }

    private void updateProgressbar() throws Exception {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                ((TableColumn) table.getColumns().get(0)).setVisible(false);
                ((TableColumn) table.getColumns().get(0)).setVisible(true);
            }
        });


    }
}
Run Code Online (Sandbox Code Playgroud)

但现在我的JavaFX应用程序的UI连续几次冻结.是否有任何替代方法可以在后台线程中调用updateProgressbar(),该后台线程在特定时间间隔后自动触发并且不冻结我的JavaFXApp的UI?

我不知道我是否正确地更新每个任务在一个单独的线程中运行的任务的状态.如果我想在这个帮助下实现这个,javafx.concurrent package那么任何人都可以向我展示一些指导或流程吗?什么将进入任务,什么将进入服务类?我如何安排它来更新进度条?仅供参考:一次只允许5个线程并行执行.

编辑 -

根据Andy Till先生的建议我更新了我的代码,但仍然没有运气 -

TableColumn tableColumn_Progress = new TableColumn("Progress");
        tableColumn_Progress.setCellValueFactory(new PropertyValueFactory<QueueData, Double>("progressBar"));
        tableColumn_Progress.setPrefWidth(100);

        Callback<TableColumn<QueueData, Double>, TableCell<QueueData, Double>> attachmentCellFactory = //
                new Callback<TableColumn<QueueData, Double>, TableCell<QueueData, Double>>() {
            @Override
            public TableCell call(final TableColumn param) {
                final ProgressBarTableCell cell = new ProgressBarTableCell() {
                    @Override
                    public void updateItem(Object item, boolean empty) {
                        super.updateItem(item, empty);
                    }
                };
                return cell;
            }
        };
        tableColumn_Progress.setCellFactory(attachmentCellFactory);
Run Code Online (Sandbox Code Playgroud)

在QueueData类中 -

DoubleProperty progressBar = null;

public DoubleProperty progressBarProperty() {
        return progressBar;
    }

    public Double getprogressBar() {
        return progressBar.get();
    }

    public void setprogressBar(Double sType) {
        this.progressBar = new SimpleDoubleProperty(sType);
    }
Run Code Online (Sandbox Code Playgroud)

而不是调用任何后台线程来更新UI但没有运气.

And*_*ill 5

据我了解您的代码,您正在翻转可见性以触发表格单元格上的updateItem方法?这意味着任何数量的线程都可能尝试每秒更改可见性并无休止地重新绘制.

我知道你已经对你的实现做了很多,但是JavaFX服务类已经实现了一个你可以更新的进度功能,这比现在你做的更简单.

拥有一个进程double属性会更加简单和有效,您可以从线程更新并将其绑定到ProgressBar.progressProperty(),以便一切都会自动更新.这是Service类的工作方式,但很容易实现.

还要确保你处理你的线程,这很容易检查.在eclipse中调试,在调试透视图中,它将显示线程列表,确保它不会无限增长.

为了安排Runnable checkout ScheduledExecutor类,您可以使用Executors.newScheduledThreadPool(numOfThreads)轻松创建它.


Nee*_*rma 5

你的'QueueData'类应该有设置现有进度的double属性的方法,似乎你每次都在setprogressBar(Double sType)方法中设置进度状态时创建新的SimpleDoubleProperty.

将此更新为 -

 public void setprogressBar(Double sType) {
        this.progressBar.set(sType);
    }
Run Code Online (Sandbox Code Playgroud)

只需在开始时创建progressBar对象,然后更新现有对象.