2013-02-03 6 views
20

Ich habe eine einfache JavaFX 2 App, mit 2 Tasten, sagen Start und Stop. Wenn der Startknopf angeklickt wird, möchte ich einen Hintergrundthread erstellen, der einige Verarbeitungsschritte ausführt und die Benutzeroberfläche (z. B. einen Fortschrittsbalken) aktualisiert, während sie weiterläuft. Wenn der Stop-Button angeklickt wird, möchte ich den Thread beenden.Multithreading in JavaFX hängt die UI

Ich habe versucht, dies zu tun mit der javafx.concurrent.Task Klasse, die ich aus der Dokumentation gesammelt würde funktionieren gut für diese. Aber immer, wenn ich auf Start klicke, bleibt die Benutzeroberfläche hängen, anstatt normal zu bleiben.

ist ihr der Code von der Haupt Myprogram extends Application Klasse für die Tasten zeigt:

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. 
} 

Hier ist der Code von MyProcessor Klasse:

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; 
    } 
} 

Ziemlich einfach, aber die UI hängt, wenn ich den Start klicken Taste, obwohl die Konsolenmeldungen weiterhin angezeigt werden (Logger.log tut einfach System.out.println)

Was mache ich falsch?

Antwort

22

Task implementiert Runnable, so, wenn Sie anrufen handler.run(); Sie tatsächlich die call Methode in dem UI-Thread ausgeführt werden. Das wird die Benutzeroberfläche hängen.

Sie sollten die Aufgabe in einem Hintergrundthread starten, entweder über einen Executor oder einfach durch den Aufruf new Thread(handler).start();.

Dies wird (möglicherweise nicht sehr deutlich) in the javadoc oder in der JavaFX concurrency tutorial erklärt.

+3

Ich kann dir nicht genug Kumpel danken. –

+0

Ich habe noch eine Frage. Ich möchte ein Label in der Hauptbenutzeroberfläche mit dem Fortschritt des Task-Threads aktualisieren. Dazu würde ich diesen Code in der Task 'mainProg.updateStatus (i);' verwenden und im Hauptprogramm 'public void updateStatus (int i) {this.label.setText (i)); } '. Würde das funktionieren, oder sollte ich 'platform.runLater()' von 'MainProg.updateStatus()' zum Aktualisieren der UI verwenden? –

+1

Ja, Sie müssten es im UI-Thread mit runLater ausführen - Alternativ können Sie die updateProgress-Methode verwenden (siehe Beispiel 3 im Lernprogramm), die im UI-Thread ausgeführt wird. – assylias