2017-05-09 6 views
1

私はJavafxでマルチスレッドアプリケーションの設計に取り組んでおり、各スレッドのNameとProgressの列を持つTableViewを使用したいと考えています。多くの研究を行った後、私は私がここで達成しようとしています何の同様の例が見つかりました:スレッドからJavaFX ProgressIndicatorを複数回更新する

JavaFX Update progressbar in tableview from Task

(これを指して:「https://community.oracle.com/message/10999916」)

私はしかし、に実行しています問題は、この例ではよく説明されています。どのようにProgressIndicatorを更新するために 'Task'オブジェクトを何度も呼び出すことができますか?

オラクルのドキュメントから、私の理解では、タスクオブジェクトは「ワンショットクラスであり、再利用できません」ということです。そのため、Taskオブジェクトのcall()メソッドを1回だけ呼び出すことができるように見えます。私は、タスクを複数回更新する必要があります。これは、Threadクラスを介して進行し、一度呼び出さずに、任意にForループを通してインクリメントします。

私はリスナーへのバインディングとサービスクラスの作成について読んだことがありますが、それらがこの問題の実際の解決方法であるかどうかはわかりません。したがって、私はこれがJavafxでも可能かどうか、もしかすると何かを見落としているかどうか尋ねたいと思います。過去にこれを達成したことがあった場合、以前に提供された例をどのように説明できるかが大いに役立ちます。

これについてのご質問はありがとうございます、ありがとうございます。

-Drew

EDIT 1:それは不正確であったように私は私の言葉遣いを編集しました。

EDIT 2:いくつかの擬似コードを使用した例です。

public static class TaskEx extends Task<Void>{ 

    @Override 
    protected Void call(){ 

    updateProgress(.5, 1); 

    return null 

} 

public static void callThread() { 
    TableView<TaskEx> table = new TableView<TaskEx>(); 
    //Some code for data in table. 

    TableColumn progressColumn = new TableColumn ("Progress"); 
    progressColumn.setCellValueFactory(new PropertyValueFactor("progress"); 

    table.setItems(<data>); 
    table.getColumns();addAll(progressColumn); 

    ExecutorService executor = Executors.newFixedThreadPool(<SomeNumber>); 

    for(TaskEx task : table.getItems(){ 
    Threading.ThreadClass newThread = new Threading.ThreadClass(task); 
    executor.submit(newThread, <uniqueID>); 
    } 
} 

は、その後、私はこのロジックでスレッドのための第二のクラスを持っていたと言う:私は次のコードを持つクラスを持っていたと言う、私は必要なワークフローの一種であるが、私は

static class ThreadClass extends Thread{ 
    Task progressTask; 

    public ThreadClass(Task task, Integer id){ 
    progressTask = task; 
    } 

public void run(){ 
    ExecutorService executor = Executors.newFixedThreadPool(<someNumber>); 

    //This invokes the Task call for the correct progressIndicator in the Tableview. 
    //It will correctly set the progressIndicator to 50% done. 
    executor.submit(progressTask); 

    /* Main logic of the Threading class that involves the 'id' passed in. */ 

    //This will do nothing because you cannot invoke the Task call more than once. 
    executor.submit(progressTask); 
    } 
} 

これを達成する方法が不明です。

+2

*「一つだけ呼び出すことができ、その後思える 『のUpdateProgress』 Taskオブジェクトに一度。」*これは明らかに真実ではありません:あなたは、ループ内のコール 'のUpdateProgress(...を)'リンクされている例ので、各タスクは複数回それを呼び出します。すべてのドキュメントの意味は 'Task'の' call() 'メソッドを1回だけ呼び出すことができるということです。あなたは 'call()'メソッドの中から好きなだけ 'updateProgress'を何度も呼び出すことができます。リンクした例は、あなたが何をしたいのかを完全に実装しているようです。あなたの質問について何が違うか説明できますか? –

+2

ヘイ・ジェームス。私はそれが貧弱だと確信しています。つまり、Taskの進捗を適切に増やすには、Taskのcall()メソッドを複数回呼び出す必要があります。私はループを通って、呼び出し(update)メソッドを呼び出した後もupdateProgressを呼び出すことができますが、呼び出すときにスレッドがどれくらいの期間終了するかはわかりません。タスクのcall()メソッドをスレッドロジックの特定のポイントに置いた後に呼び出すよう計画していました。それから、それがさらにダウンしたときなどにもう一度呼び出します。 –

+1

「仕事」の目的を誤解しているに違いないと思いますか?タスクは "あなたがやっていること"を表します - それはあなたが興味を持っているタスクの進歩でなければなりません。そうでない場合、あなたは 'Task'を何に使っていますか?問題を説明するコードを投稿できますか? –

答えて

1

私たちが話していたことが分からないようです。 Thread.run()でロジックを実行しようとしていて、各スレッドは進行状況の更新を行うためにTaskを作成しています。

本当にロジックをThread.run()からTask.call()に変更する必要があります。スレッドは実際には単なるスレッドで、Runnableオブジェクト(Task)を実行するだけです。

public class TaskEx extends Task<Void> { 
    @Override 
    protected Void call() { 
     // Do whatever you need this thread to do 
     updateProgress(0.5, 1); 

     // Do the rest 
     updateProgress(1, 1); 
    } 
} 


public static void callThread() { 
    TableView<TaskEx> table = new TableView<TaskEx>(); 
    ObservableList<TaskEx> data = FXCollections.observableArrayList<>(); 
    data.add(new TaskEx()); // Add the data you need 

    TableColumn progressColumn = new TableColumn("Progress"); 
    progressColumn.setCellValueFactory(new PropertyValueFactory("progress")); 
    progressColumn.setCellFactory(column -> { 
     return new TableCell<TaskEx, Double> { 
      private final ProgressBar bp = new ProgressBar(); 

      @Override 
      public void updateItem(Double item, boolean empty) { 
       super.updateItem(item, empty); 

       if (empty || item == null) { 
        setText(null); 
        setGraphic(null); 
       } 
       else { 
        bp.setProgress(item.doubleValue()); 
        setGraphic(bp); 
       } 
      } 
     } 
    }); 

    table.setItems(data); 
    table.getColumns().add(progressColumn); 

    ExecutorService executor = Executors.newFixedThreadPool(data.size()); 

    for (TaskEx task : table.getItems()) { 
     executor.submit(task); 
    } 
} 

スレッドサブクラスで行わなければなりません任意のロジックがあってはならないので、このThreadClass削除しを実装します。ロジックの一部としてスレッドオブジェクトに実際にアクセスする必要がある場合は、TaskEx.call()からThread.getCurrentThread()に電話してください。

この実装では、まったく同じことを行う複数のスレッドも開きます(これは全く意味がありません)。異なるロジックのセットを行う必要がある場合は、別のTaskサブクラスのセットを作成するか、またはRunnableのオブジェクトを取り込むコンストラクタをTaskExに追加します。

など。

public class TaskEx extends Task<Void> { 
    private final Runnable[] logics; 

    public TaskEx(Runnable[] logics) { 
     this.logics = logics; 
    } 

    @Override 
    protected Void call() { 
     for (int i = 0; i < logics.length; i++) { 
      logics[i].run(); 
      updateProgress(i, logics.length); 
     } 
    } 
} 
+0

ありがとうジャイ!あなたとJames_Dは私が「仕事」とその目的をよりよく理解するのを助けましたが、私は確かに道のりがあります:) –

+0

@DrewB Learningは進行中のプロセスです。私はJames_D、jewelsea、DVargaのような専門家から(直接的かつ間接的に)多くの指導を受けました:) – Jai

関連する問題