gpt4 book ai didi

java - 从线程多次更新 JavaFX ProgressIndicator

转载 作者:行者123 更新时间:2023-11-30 06:44:38 24 4
gpt4 key购买 nike

我正在 Javafx 中设计一个多线程应用程序,并且希望有一个 TableView,其中包含每个线程的名称和进度列。经过大量研究后,我发现了一个与我试图在这里完成的类似的例子:

JavaFX Update progressbar in tableview from Task

(指向此:“https://community.oracle.com/message/10999916 ”)

然而,我遇到的问题在这个例子中得到了很好的说明;如何多次调用“任务”对象来更新 ProgressIndicator?

我对 Oracle 文档的理解是,Task 对象“是一次性类,不能重用”。这样看来,一个任务对象的 call() 方法只能调用一次。我需要在任务通过 Thread 类进行时多次更新任务,而不是调用它一次并通过 For 循环任意递增。

我已经阅读了有关绑定(bind)到监听器和创建服务类的信息,但我不确定这些是否是此问题的实际解决方案。因此我想问这在 Javafx 中是否可能,或者我是否忽略了一些东西。如果过去有人已经完成了此任务,如果您能够通过前面提供的示例来说明如何实现,那将会非常有帮助。

对此的任何指导将不胜感激,谢谢。

-德鲁

编辑 1:我编辑了我的措辞,因为它不准确。

编辑2:这是一个带有一些伪代码的示例。假设我有一个包含以下代码的类(class):

public static class TaskEx extends Task<Void>{

@Override
protected Void call(){

updateProgress(.5, 1);

return null

}

public static void callThread() {
TableView<TaskEx> table = new TableView<TaskEx>();
//Some code for data in table.

TableColumn progressColumn = new TableColumn ("Progress");
progressColumn.setCellValueFactory(new PropertyValueFactor("progress");

table.setItems(<data>);
table.getColumns();addAll(progressColumn);

ExecutorService executor = Executors.newFixedThreadPool(<SomeNumber>);

for(TaskEx task : table.getItems(){
Threading.ThreadClass newThread = new Threading.ThreadClass(task);
executor.submit(newThread, <uniqueID>);
}
}

然后假设我有一个具有以下逻辑的线程第二类:

static class ThreadClass extends Thread{
Task progressTask;

public ThreadClass(Task task, Integer id){
progressTask = task;
}

public void run(){
ExecutorService executor = Executors.newFixedThreadPool(<someNumber>);

//This invokes the Task call for the correct progressIndicator in the Tableview.
//It will correctly set the progressIndicator to 50% done.
executor.submit(progressTask);

/* Main logic of the Threading class that involves the 'id' passed in. */

//This will do nothing because you cannot invoke the Task call more than once.
executor.submit(progressTask);
}
}

这就是我需要的工作流程,但我不确定如何实现这一点。

最佳答案

看来你没明白我们在说什么。您尝试在 Thread.run() 中执行逻辑,然后每个线程创建一个 Task 只是为了更新进度。

您真正需要的是将逻辑从Thread.run() 转移到Task.call()。您的线程实际上只是一个线程,它所做的只是运行一个 Runnable 对象(即任务)。

public class TaskEx extends Task<Void> {
@Override
protected Void call() {
// Do whatever you need this thread to do
updateProgress(0.5, 1);

// Do the rest
updateProgress(1, 1);
}
}


public static void callThread() {
TableView<TaskEx> table = new TableView<TaskEx>();
ObservableList<TaskEx> data = FXCollections.observableArrayList<>();
data.add(new TaskEx()); // Add the data you need

TableColumn progressColumn = new TableColumn("Progress");
progressColumn.setCellValueFactory(new PropertyValueFactory("progress"));
progressColumn.setCellFactory(column -> {
return new TableCell<TaskEx, Double> {
private final ProgressBar bp = new ProgressBar();

@Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);

if (empty || item == null) {
setText(null);
setGraphic(null);
}
else {
bp.setProgress(item.doubleValue());
setGraphic(bp);
}
}
}
});

table.setItems(data);
table.getColumns().add(progressColumn);

ExecutorService executor = Executors.newFixedThreadPool(data.size());

for (TaskEx task : table.getItems()) {
executor.submit(task);
}
}

此实现删除了ThreadClass,因为不应该有任何必须在线程子类中完成的逻辑。如果您确实需要访问线程对象作为逻辑的一部分,请从 TaskEx.call() 调用 Thread.getCurrentThread()

这个工具还打开多个线程做完全相同的事情(这是毫无意义的)。如果您需要执行一组不同的逻辑,您可以创建一组不同的 Task 子类,或者在 TaskEx< 中添加一个接受 Runnable 对象的构造函数.

例如

public class TaskEx extends Task<Void> {
private final Runnable[] logics;

public TaskEx(Runnable[] logics) {
this.logics = logics;
}

@Override
protected Void call() {
for (int i = 0; i < logics.length; i++) {
logics[i].run();
updateProgress(i, logics.length);
}
}
}

关于java - 从线程多次更新 JavaFX ProgressIndicator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43859153/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com