好几天我现在正在尝试更新Javafx用户界面,同时自动发送2个或更多电子邮件。用户界面应使用"连接","发送"更新标签。并且"发送"。我已经阅读过关于Runnables,Tasks,TimeLine但我真的不明白我应该使用哪种方法以及它是如何工作的。
我读到有关Platform.runLater()的所有内容,我都使用过它,但是当所有的电子邮件都被发送时,我的JavaFX Gui中的动画会冻结,而Label只会发生变化。
我会很快用我的代码更新这篇文章,但有人可以告诉我应该使用哪种线程以及如何轻松更新ui?
//修改
感谢你的帮助,Branislav但现在我得到了#34; Not on FX应用程序线程" -Error。以下代码不是我的"扩展Application" -class,请看一下。
public class ControllerOCM implements Initializable{
@FXML
private ComboBox<String> comboEmpf;
@FXML
private Label lblStatus;
@FXML
private Label lblStatus1;
@Override
public void initialize(URL location, ResourceBundle resources) {
hint.setText("some hint");
}
public void sende(ActionEvent event) throws Exception {
switch (comboEmpf.getValue()) {
case "A": System.out.println("A");break;
case "B":
File fTEST = new File("C:\\B\\");
File[] fpathTEST = fTEST.listFiles();
String[] fnameTEST = fTEST.list();
for (int i=0; i<fpathTEST.length; i++) {
SendenTask sendTEST = new SendenTask(mail@address.com,
"bodycontent",
"subject",
fpathTEST[i].toString(),
fnameTEST[i],
i, //count
fpathTEST.length); //max
new Thread(sendTEST).start();
}
break;
}
}
public class SendenTask extends Task<Void> {
private String adr;
private String body;
private String subj;
private String fp;
private String fn;
private int count;
private int max;
public SendenTask(String adr, String body, String subj, String fp, String fn, int count, int max) {
this.adr = adr;
this.body = body;
this.subj = subj;
this.fp = fp;
this.fn = fn;
this.count = count;
this.max = max;
}
@Override
protected Void call() throws Exception {
lblStatus1.setText("connecting");
//doing connectionAction
lblStatus1.setText("sending");
updateMessage("sending");
//doing sendingthingys
//sending complete
lblStatus1.setText("sent");
System.out.println("done");
updateMessage("done");
return null;
}
}
}
// EDIT2
现在,程序正在逐个发送电子邮件,但textproperty无法正常工作。它没有刷新文本,它只是清空标签。如果我删除unbind-line(成功)它只运行一次我发送任务。之后,对于所有其他发送任务,它再次为空。
public class ControllerOCM implements Initializable{
@FXML
private ComboBox<String> comboEmpf;
@FXML
private Label lblStatus;
@FXML
private Label lblStatus1;
@Override
public void initialize(URL location, ResourceBundle resources) {
hint.setText("some hint");
}
public void sende(ActionEvent event) throws Exception {
switch (comboEmpf.getValue()) {
case "A": System.out.println("A");break;
case "B":
File fTEST = new File("C:\\B\\");
File[] fpathTEST = fTEST.listFiles();
String[] fnameTEST = fTEST.list();
for (int i=0; i<fpathTEST.length; i++) {
SendenTask sendTEST = new SendenTask(mail@address.com,
"bodycontent",
"subject",
fpathTEST[i].toString(),
fnameTEST[i],
i, //count
fpathTEST.length); //max
lblStatus1.textProperty().bind(sendTEST.messageProperty());
thread = new Thread(sendTEST);
thread.start();
}
break;
}
}
public class SendenTask extends Task<Void> {
private String adr;
private String body;
private String subj;
private String fp;
private String fn;
private int count;
private int max;
public SendenTask(String adr, String body, String subj, String fp, String fn, int count, int max) {
this.adr = adr;
this.body = body;
this.subj = subj;
this.fp = fp;
this.fn = fn;
this.count = count;
this.max = max;
}
@Override
protected Void call() throws Exception {
while(!sending) {
sending = true
updateMessage("connecting");
//doing connectionAction
updateMessage("sending");
//doing sendingthingys
//sending complete
updateMessage("done");
}
return null;
}
@Override
protected void succeeded() {
super.succeeded();
lblStatus1.textProperty().unbind();
sending = false;
}
}
}
// EDIT3 最大的问题是,我把它放在哪里 。lblStatus1.textProperty()结合(sendTEST.messageProperty()); 和哪里 lblStatus1.textProperty()解除绑定(); 吗
答案 0 :(得分:3)
你必须使用Task
类。
这是一个小型演示。让我们通过for
循环来模拟耗时的任务:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class TaskDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
final Label label = new Label();
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
boolean fxApplicationThread = Platform.isFxApplicationThread();
System.out.println("Is call on FXApplicationThread: " + fxApplicationThread);
// Run your time consuming task here!
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
updateMessage("Time elapsed: " + i);
}
return null;
}
@Override
protected void succeeded() {
boolean fxApplicationThread = Platform.isFxApplicationThread();
System.out.println("Is call on FXApplicationThread: " + fxApplicationThread);
super.succeeded();
label.textProperty().unbind();
label.setText("Task done");
}
};
// Bind messageProperty of task for textProperty of Label
label.textProperty().bind(task.messageProperty());
stage.setScene(new Scene(label, 300, 200));
stage.show();
new Thread(task).start();
}
}
事情很简单。您耗费时间的任务将冻结UI,直到完成为止。通过使用Task
类,您的耗时任务在后台线程上运行,从而使JavaFX线程响应。偶尔,您可以发布&#34;来自call
方法的任务结果。 不要在后台线程上更新您的JavaFX UI(在call
方法中)。通过致电Platform.isFxApplicationThread()
,您可以检查您的代码是否在FXApplicationThread
上运行。如果您的代码没有在该线程上运行,请不要从那里更新JavaFX UI!