2016-07-21 5 views
-1

私はテキストファイルを読むプログラムを作っています。私がしたいのは、ファイルの読み込みの前または途中に別のスレッドで作成された任意のノード(アラートまたはその他のノード)を表示することです。私はこのようなTaskPlatform.runLater()を使用してみました:FXスレッド中にノードを表示することはできますか?

if (filetoopen != null) 
      { 
       Platform.runLater(new Runnable() { 
        @Override 
        void run() { 
          Alert alert=new Alert(Alert.AlertType.INFORMATION) 
          alert.setHeaderText('TEST')       
        } 
       }) 
       //method to read the file 
       Tools.convertFromFile(filetoopen,newredactor) 
       lastDirectory = filetoopen.getParentFile() 
      } 

私は、ファイルを読み込むのアラートやプログレスバーを表示したいのですが、読み取りが終了した後、コントロールが初期化されます。ですから、ファイルが読み込まれている間に進行状況バーを表示することは可能ですか?または私が作成したRunnableは常に最後に実行されますか?

編集:タスクとの試み:

class Alerter extends Task{ 
    Alerter(File f,Editor e) 
    { 
     file=f 
     editor=e 
    } 
    File file 
    Editor editor 
    @Override 
    protected Object call() throws Exception { 
     Dialog dialog=new Dialog() 
     DialogPane dp=dialog.getDialogPane() 
     dp.setHeaderText('TEST') 
     dp.getButtonTypes().add(new ButtonType('Cancel',ButtonBar.ButtonData.CANCEL_CLOSE)) 
     dialog.setOnCloseRequest(new javafx.event.EventHandler<DialogEvent>() { 
      @Override 
      void handle(DialogEvent event) { 
       dialog.close() 
      } 
     }) 
     dialog.show() 
     Tools.convertFromFile(file,editor) 
     return null 
    } 
} 

ダイアログがまだTools.convertFromFile後に初期化します。

+0

「私は、 ')' Task'と 'Platform.runLaterを(使用してみました」:それは正しいです方法はありますが、投稿されたコードには「タスク」はありません。 –

+0

OK、タスク – Alexiy

+0

で試行を追加しました。controlsFXとProgressDialogを見てください。タスクを送信してから開始すると、必要なものが表示されます。 –

答えて

1

:シーングラフに

  1. 変更は(すなわち、新しいシーンやウィンドウを作成、または既に表示されているノードの状態を変更) FXアプリケーションスレッドでを実行する必要があります。
  2. 長期実行プロセスは、バックグラウンドスレッド(FXアプリケーションスレッドではない)で実行する必要があります。そうしないと、UIが応答しなくなります。

最初のコードブロックは2番目のルールに違反しています(多分コンテキストが表示されていない可能性があります)。2番目のコードブロックが最初のルールに違反しています。

だから、基本的にあなたがする必要があります。

  1. は、FXのアプリケーションスレッド
  2. からダイアログがへの変更をスケジュールし、新しいスレッドからバックグラウンド
  3. でファイルを処理し、新しいスレッドを開始
  4. 表示ファイルの終了を処理する場合、FXのアプリケーションスレッド上でUIを更新
  5. FXのアプリケーションスレッドに新しいUI

Platform.runLater(...)を使用すると、FXアプリケーションスレッドで実行するコードをスケジュールできますが、Task classはこれらの更新でより便利なAPIを提供します。だから、

:それはなければならないUIを更新しないことに方法でUI(あるいは少なくともいずれかのコールを更新してはいけませんので、ごTools.convertFromFile(...)方法は、バックグラウンドスレッドから呼び出されたことをここ

// set up and show dialog: 
ProgressBar progressBar = new ProgressBar(); 
DialogPane dialogPane = new DialogPane(); 
dialogPane.getButtonTypes().setAll(ButtonType.OK); 
dialogPane.setHeaderText("Processing file"); 
dialogPane.setContent(progressBar); 
dialogPane.lookupButton(ButtonType.OK).setDisable(true); 
Dialog dialog = new Dialog(); 
dialog.setDialogPane(dialogPane); 
dialog.show(); 

// create task: 
Task<Void> task = new Task<Void>() { 
    @Override 
    public Void call() throws Exception { 
     Tools.convertFromFile(file, editor); 
     // can call updateProgress(...) here to update the progress periodically 
     return null ; 
    } 
}; 

// update progress bar with progress from task: 
progressBar.progressProperty().bind(task.progressProperty()); 

// when task completes, update dialog: 
task.setOnSucceeded(event -> { 
    dialogPane.lookupButton(ButtonType.OK).setDisable(false); 
    progressBar.progressProperty().unbind(); 
    progressBar.setProgress(1); 
    dialogPane.setHeaderText("Processing complete"); 
}); 

// handles errors: 
task.setOnFailed(event -> { 
    dialogPane.lookupButton(ButtonType.OK).setDisable(false); 
    progressBar.progressProperty().unbind(); 
    progressBar.setProgress(0); 
    dialogPane.setHeaderText("An error occurred"); 
}); 

// run task in background thread: 
Thread thread = new Thread(task); 
thread.start(); 

注意Platform.runLater(...)にラップしてください)。ここで

は(ちょうど長時間実行プロセスのデモとして眠る)完全SSCCEです:

import java.util.Random; 

import javafx.application.Application; 
import javafx.concurrent.Task; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.ButtonType; 
import javafx.scene.control.Dialog; 
import javafx.scene.control.DialogPane; 
import javafx.scene.control.ProgressBar; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class TaskWithProgressDemo extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     Button button = new Button("Start process"); 
     button.setOnAction(e -> { 

      button.setDisable(true); 

      // set up and show dialog: 
      ProgressBar progressBar = new ProgressBar(); 
      DialogPane dialogPane = new DialogPane(); 
      dialogPane.getButtonTypes().setAll(ButtonType.OK); 
      dialogPane.setHeaderText("Processing file in progress"); 
      dialogPane.setContent(progressBar); 
      dialogPane.lookupButton(ButtonType.OK).setDisable(true); 
      Dialog<Void> dialog = new Dialog<Void>(); 
      dialog.setDialogPane(dialogPane); 
      dialog.show(); 

      // create task: 
      Task<Void> task = new Task<Void>() { 
       @Override 
       public Void call() throws Exception { 

        Random rng = new Random(); 

        for (int i = 0 ; i <= 100 ; i++) { 
         Thread.sleep(rng.nextInt(40)); 
         updateProgress(i, 100); 
        } 

        if (rng.nextBoolean()) { 

         System.out.println("Simulated error"); 
         throw new Exception("An unknown error occurred"); 
        } 

        return null ; 
       } 
      }; 

      // update progress bar with progress from task: 
      progressBar.progressProperty().bind(task.progressProperty()); 

      // when task completes, update dialog: 
      task.setOnSucceeded(event -> { 
       dialogPane.lookupButton(ButtonType.OK).setDisable(false); 
       button.setDisable(false); 
       progressBar.progressProperty().unbind(); 
       progressBar.setProgress(1); 
       dialogPane.setHeaderText("Processing complete"); 
      }); 

      // handles errors: 
      task.setOnFailed(event -> { 
       dialogPane.lookupButton(ButtonType.OK).setDisable(false); 
       button.setDisable(false); 
       progressBar.progressProperty().unbind(); 
       progressBar.setProgress(0); 
       dialogPane.setHeaderText("An error occurred"); 
      }); 

      // run task in background thread: 
      Thread thread = new Thread(task); 
      thread.start(); 
     }); 

     StackPane root = new StackPane(button); 
     root.setPadding(new Insets(20)); 
     primaryStage.setScene(new Scene(root)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

あなたの例をありがとう。ユーザーが読み込み中にGUIを操作できるようにすることは可能ですか? – Alexiy

+0

あなたは何を意味するのかよく分かりません。この例でユーザーがUIとやり取りするのを妨げるのは、モーダルダイアログが表示されることだけです。 –

+0

そうです、私は、ユーザ入力をブロックしないためのダイアログではなく、新しいステージを作成する必要があると考えました。 – Alexiy

0

だから私はそれを最終的に理解しました。ファイルロードコードと進捗状況の両方をタスクに移動しなければならなかったので、FXスレッドをブロックしませんでした。インジケータは、ファイルのロードの進行状況を示します。

編集:別のノンブロッキングウィンドウで進行状況を表示するには、何かの代わりに新しいステージを使用する必要があります。 (ほぼすべての他のUIツールキットおよび中)JavaFXの2つのスレッドのルールがあります

+0

タスクを開始する前にダイアログを表示するだけですか? –

関連する問題