我正在设计Javafx中的多线程应用程序,并希望有一个TableView,其中包含每个Thread的Name和Progress的列。经过大量的研究后,我发现了一个类似的例子,说明了我在这里要完成的任务:
JavaFX Update progressbar in tableview from Task
(指出这一点:'https://community.oracle.com/message/10999916')
然而,我遇到的问题在这个例子中很好地说明了;如何多次调用'Task'对象来更新ProgressIndicator?
我从Oracle的文档中了解到,Task对象“是一次性的类,无法重用”。那么似乎只能调用Task对象的call()方法一次。我需要多次更新Task,因为它通过Thread类进行,而不是调用它一次,并通过For循环任意增加。
我已阅读有关绑定到Listeners和创建Service类的内容,但我不确定这些是否是对此问题的实际解决方案。因此,我想问一下,在Javafx中是否甚至可能这样,或者我是否忽略了某些东西。如果有人在过去完成了这项工作,那么如果您能够通过之前提供的示例说明如何,将会非常有用。
对此的任何指示都表示赞赏,谢谢。
-DREW
编辑1:我编辑了我的措辞,因为它不准确。
编辑2:这是一个带有一些伪代码的例子。假设我有一个包含以下代码的类:
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);
}
}
这就是我需要的那种工作流程,但我不确定如何实现这一目标。
答案 0 :(得分:1)
好像你没有得到我们所说的。您正在尝试在Thread.run()
中执行逻辑,然后每个线程都创建一个Task
,只是为了更新进度。
您需要的是将您的逻辑从Thread.run()
转移到Task.call()
。你的线程实际上只是一个线程,它只是运行一个Runnable
对象(Task
)。
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
,因为不应该有任何必须在线程子类中完成的逻辑。如果您确实需要在逻辑中访问线程对象,请从Thread.getCurrentThread()
致电TaskEx.call()
。
这个工具也会打开多个线程做同样的事情(这是毫无意义的)。如果您需要执行一组不同的逻辑,则可以创建一组不同的Task
子类,或者添加一个构造函数来接收Runnable
中的TaskEx
个对象。
E.g。
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);
}
}
}