2013-02-03 69 views
20

我有一个简单的JavaFX 2应用程序,带有2个按钮,表示启动和停止。当单击开始按钮时,我想要创建一个后台线程,它将执行一些处理并更新UI(例如进度条)。如果点击了停止按钮,我希望线程终止。JavaFX中的多线程挂起UI

我试图做到这一点,使用javafx.concurrent.Task类,我从文档中收集的工作将很好。但是,每当我点击开始,用户界面冻结/挂起,而不是保持正常。

她是从主Myprogram extends Application类的代码显示的按钮:

public void start(Stage primaryStage) 
{    
    final Button btn = new Button(); 
    btn.setText("Begin"); 

    //This is the thread, extending javafx.concurrent.Task : 
    final MyProcessor handler = new MyProcessor(); 
    btn.setOnAction(new EventHandler<ActionEvent>() 
    { 
     public void handle(ActionEvent event) 
     {     
      handler.run(); 
     } 
    }); 

    Button stop = new Button(); 
    stop.setText("Stop"); 
    stop.setOnAction(new EventHandler<ActionEvent>() 
     { 
      public void handle(ActionEvent event) 
      { 
       handler.cancel(); 
      } 
     } 

    ); 
    // Code for adding the UI controls to the stage here. 
} 

这里的MyProcessor类的代码:

import javafx.concurrent.Task; 
public class MyProcessor extends Task 
{ 
    @Override 
    protected Integer call() 
    { 
     int i = 0; 
     for (String symbol : feed.getSymbols()) 
     { 
      if (isCancelled()) 
      { 
       Logger.log("Stopping!"); 
       return i; 
      } 
      i++; 
      Logger.log("Doing # " + i); 
      //Processing code here which takes 2-3 seconds per iteration to execute 
      Logger.log("# " + i + ", DONE! ");    
     } 
     return i; 
    } 
} 

很简单,但每当我点击启动UI挂起按钮,尽管控制台消息继续显示(Logger.log只是做System.out.println

我在做什么错?

回答

22

Task implements Runnable,所以当你调用handler.run();你实际上在UI线程中运行call方法。这将挂起用户界面。

您应该在后台线程中启动任务,可以通过执行程序或仅需致电new Thread(handler).start();

这可以在the javadocJavaFX concurrency tutorial中解释(也许不是很清楚)。

+3

我不能感谢你足够的队友。 –

+0

我还有一个问题。我想用任务线程的进度更新主UI中的标签。为此,我将在任务中使用此代码:'mainProg.updateStatus(i);',并在主程序中:'public void updateStatus(int i){this.label.setText(i)); }'。这会工作吗,还是应该使用'MainProg.updateStatus()'中的'platform.runLater()'来更新UI? –

+1

是的,您需要在UI线程中使用runLater运行它 - 或者,您可以使用updateProgress方法(请参阅教程中的示例3),它将在UI线程中运行。 – assylias