User interface 执行进程时更新TextArea
当我点击“开始”按钮,如“无响应”时,我发现我的GUI在3-4秒后开始冻结。当我继续单击应用程序时,它将被迫关闭。User interface 执行进程时更新TextArea,user-interface,javafx,concurrency,updates,fxml,User Interface,Javafx,Concurrency,Updates,Fxml,当我点击“开始”按钮,如“无响应”时,我发现我的GUI在3-4秒后开始冻结。当我继续单击应用程序时,它将被迫关闭。 现在我想阻止这一切,但我不知道怎么做。就我所知,JavaFX在一个线程中运行,因此,要在方法执行时更新我的TextArea,我需要在另一个线程中运行这些方法。 我希望有人能帮助我 我的项目看起来怎么样? public class Handler { public void handle(List<String> files) { for (String s :
现在我想阻止这一切,但我不知道怎么做。就我所知,JavaFX在一个线程中运行,因此,要在方法执行时更新我的TextArea,我需要在另一个线程中运行这些方法。
我希望有人能帮助我 我的项目看起来怎么样?
public class Handler {
public void handle(List<String> files) {
for (String s : files) {
List<String> ls = Reader.readFile(s);
Writer.writeFile(Transformer.transform(ls));
}
}
我得到了一个FXML、一个控制器、一个处理程序、一个转换器,还有一个Writer和一个Reader类(在处理程序类中使用)。当我单击绑定到控制器中某个方法的按钮时,会创建一个Handler实例,该实例调用读取器读取文本文件,并转换为字符串列表(逐行)。
此外,这些线条正在被操纵。在此之后,将使用Writer创建一个新文件,并将新的操作行写入该文件。
还允许用户引用多个文件。
我想要的是,每当读卡器开始读取文件时,文本区域就会显示,如“正在读取文件”。
然后在Transformer开始工作时附加“文件…正在被操作”,然后
当新行写入新文件时,“文件…正在写入” 这里有一些代码。
控制器:
public class FXMLDocumentController implements Initializable {
@FXML
private TextArea console;
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
Handler hand = new Handler();
hand.handle(files);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
处理程序:
public class Handler {
public void handle(List<String> files) {
for (String s : files) {
List<String> ls = Reader.readFile(s);
Writer.writeFile(Transformer.transform(ls));
}
}
公共类处理程序{
公共无效句柄(列表文件){
用于(字符串s:文件){
List ls=Reader.readFile;
writeFile(Transformer.transform(ls));
}
}
每当读取、操作或写入文件时,我应该如何更改代码以更新文本区域
Info:我知道类处理程序不会编译,因为我删除了包含文件路径字符串的列表“files”的初始化
如果我遗漏了相关信息,请随时询问。我提前感谢您!您应该在后台线程中执行
handle()
方法:
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
Thread thread = new Thread(() -> {
Handler hand = new Handler();
hand.handle(files);
});
// this line means the background thread will not prevent application exit:
thread.setDaemon(true);
thread.start();
}
如果要使用当前状态更新文本区域,则需要使用Platform.runLater()
将其重新安排到FX应用程序线程上。最干净的方法可能是在Handler
类中不使用Platform.runLater()
,而是在Handler
中定义一个用于“消费”的字段状态消息:
public class Handler {
private final Consumer<String> statusMessageProcessor ;
public Handler(Consumer<String> statusMessageProcessor) {
this.statusMessageProcessor = statusMessageProcessor ;
}
// default processor does nothing:
public Handler() {
this(s -> {});
}
public void handle(List<String> files) {
for (String s : files) {
// similarly for other status updates:
statusMessageProcessor.accept("The file "+s+" is being read");
List<String> ls = Reader.readFile(s);
Writer.writeFile(Transformer.transform(ls));
}
}
}
可以成为
Handler hand = new Handler(message ->
Platform.runLater(() -> console.appendText(message + "\n")));
在按钮处理程序方法中。您应该在后台线程中执行
handle()
方法:
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
Thread thread = new Thread(() -> {
Handler hand = new Handler();
hand.handle(files);
});
// this line means the background thread will not prevent application exit:
thread.setDaemon(true);
thread.start();
}
如果要使用当前状态更新文本区域,则需要使用Platform.runLater()
将其重新安排到FX应用程序线程上。最干净的方法可能是在Handler
类中不使用Platform.runLater()
,而是在Handler
中定义一个用于“消费”的字段状态消息:
public class Handler {
private final Consumer<String> statusMessageProcessor ;
public Handler(Consumer<String> statusMessageProcessor) {
this.statusMessageProcessor = statusMessageProcessor ;
}
// default processor does nothing:
public Handler() {
this(s -> {});
}
public void handle(List<String> files) {
for (String s : files) {
// similarly for other status updates:
statusMessageProcessor.accept("The file "+s+" is being read");
List<String> ls = Reader.readFile(s);
Writer.writeFile(Transformer.transform(ls));
}
}
}
可以成为
Handler hand = new Handler(message ->
Platform.runLater(() -> console.appendText(message + "\n")));
在按钮处理程序方法中。您应该查看并发程序包中的任务和服务:。和。您应该查看并发程序包中的任务和服务:。和。我更喜欢第二种方式,否?因为我可以看到文件读取、操作和写入时的状态,而在处理程序中的第一个变体中看不到hand=newhandler(s->Platform.runLater(()->console.appendText(s+“\n”));是我的初始化列表吗?你是什么意思?这里只有一个解决方案。为了更容易理解,我将其分为两部分:第一,如何在后台线程中运行处理程序,第二,如何提供更新。
s
调用处理程序
构造函数中的只是lambda的参数名称(这就是传递给statusMessageProcessor.accept(…)
)的状态消息。您可以随意调用它(显然,如果您更改它,也可以在控制台中更改它的使用。appendText(…)
)。谢谢!我删除了“Handler Handle=new Handler();”并复制了“Handler Handle=new Handler(s->Platform.runLater()->console.appendText(s+“\n”);“在线程声明之前,它现在可以正常工作了!并发是一个非常复杂的主题,我永远不知道应该使用什么实现(线程、任务、backgroundworker、使用者、服务等).你能给我一个链接或建议吗?有没有一种设计模式支持特殊情况下的线程实现?编辑:对不起,我缺少5个代表点,你能给我投票吗..请将答案标记为正确(你不需要声誉)如果它回答了问题。如果后台任务计算出您希望在UI中显示的结果(或者如果您希望在完成时更改UI),请使用任务。您可以使用任务
来完成此任务,但对于您描述的用法,简单的可运行没有什么好处。如果您希望能够多次重新启动任务,请使用服务
。我更喜欢第二种方式,不是吗?因为我可以看到在第一个v中看不到的文件读取、操作和写入时的状态Handler中的变量.s=新处理程序(s->Platform.runLater(()->console.appendText(s+“\n”));是我的初始化列表吗?你是什么意思?这里只有一个解决方案。为了更容易理解,我将其分为两部分:第一,如何在后台线程中运行处理程序,第二,如何提供更新。s
调用处理程序
构造函数中的只是lambda的参数名称(这就是传递给statusMessageProcessor.accept(…)
)的状态消息。您可以随意调用它(显然,如果您更改它,也可以在控制台中更改它的使用。appendText(…)
)。谢谢!我删除了“Handler Handle=new Handler();”并复制了“Handler Handle=new Handler(s->Platform.runLater()->console.appendText(s+“\n”));“在线程声明之前,它是w