2013-05-23 31 views
5

タスクにはupdateProgressというメソッドがありますが、プログレスバーをタスクにバインドする必要がありますが、オブジェクトとしてプログレスバーを持たないため、これを行うことはできません。タスクからのtableviewのJavaFX Updateプログレスバー

私のプログラムにはTableViewがあります。ユーザーがダウンロードURLを入力し、TableViewで作成された新しい行をダウンロードするをクリックします。行には情報とプログレスバーの列があります。私は新しいスレッドタスクを開始します。すべてのダウンロードが完了しているところで、何とかその行のプログレスバーを更新する必要があります。

私はタスクにSimpleDoublePropertyを結合しようとしたが、それは、プログレスバーを更新しません...

答えて

20

ジェームズ・Dは、OracleのJavaFXフォーラムのスレッドでこれを解決:Table cell progress indicatorを。私はちょうどこの答えにその解決策をコピーしました。

解決策は、複数のタスクを作成し、進捗バーのセットを使用して進行状況を監視します(TableView)。

オリジナルのスレッドにはProgressIndicatorsを使用するソリューションが含まれています。その場合は、ProgressBarsを使用することをお勧めします。

progress

import java.util.Random; 
import java.util.concurrent.Executor; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ThreadFactory; 

import javafx.application.Application; 
import javafx.concurrent.Task; 
import javafx.scene.Scene; 
import javafx.scene.control.ProgressIndicator ; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.ProgressBarTableCell; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class ProgressBarTableCellTest extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
    TableView<TestTask> table = new TableView<TestTask>(); 
    Random rng = new Random(); 
    for (int i = 0; i < 20; i++) { 
     table.getItems().add(
      new TestTask(rng.nextInt(3000) + 2000, rng.nextInt(30) + 20)); 
    } 

    TableColumn<TestTask, String> statusCol = new TableColumn("Status"); 
    statusCol.setCellValueFactory(new PropertyValueFactory<TestTask, String>(
     "message")); 
    statusCol.setPrefWidth(75); 

    TableColumn<TestTask, Double> progressCol = new TableColumn("Progress"); 
    progressCol.setCellValueFactory(new PropertyValueFactory<TestTask, Double>(
     "progress")); 
    progressCol 
     .setCellFactory(ProgressBarTableCell.<TestTask> forTableColumn()); 

    table.getColumns().addAll(statusCol, progressCol); 

    BorderPane root = new BorderPane(); 
    root.setCenter(table); 
    primaryStage.setScene(new Scene(root)); 
    primaryStage.show(); 

    ExecutorService executor = Executors.newFixedThreadPool(table.getItems().size(), new ThreadFactory() { 
     @Override 
     public Thread newThread(Runnable r) { 
     Thread t = new Thread(r); 
     t.setDaemon(true); 
     return t; 
     } 
    }); 


    for (TestTask task : table.getItems()) { 
     executor.execute(task); 
    } 
    } 

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

    static class TestTask extends Task<Void> { 

    private final int waitTime; // milliseconds 
    private final int pauseTime; // milliseconds 

    public static final int NUM_ITERATIONS = 100; 

    TestTask(int waitTime, int pauseTime) { 
     this.waitTime = waitTime; 
     this.pauseTime = pauseTime; 
    } 

    @Override 
    protected Void call() throws Exception { 
     this.updateProgress(ProgressIndicator.INDETERMINATE_PROGRESS, 1); 
     this.updateMessage("Waiting..."); 
     Thread.sleep(waitTime); 
     this.updateMessage("Running..."); 
     for (int i = 0; i < NUM_ITERATIONS; i++) { 
     updateProgress((1.0 * i)/NUM_ITERATIONS, 1); 
     Thread.sleep(pauseTime); 
     } 
     this.updateMessage("Done"); 
     this.updateProgress(1, 1); 
     return null; 
    } 

    } 
} 

あなたは上記のコードがどのように機能するかを理解する難しさを持つとのより深い理解を得るために必要されている場合にのみ、このセクションを読む必要はコメントの質問

に基づき説明文セル値とプロパティの接続。

ここではバインディングはありません(少なくとも私は見ていません)。

結合(または同じことになるのChangeListenerは、)PropertyValueFactoryProgressBarTableCellの実装の背後に隠されています。のは、関連するコードを見てみましょう:

TableColumn<TestTask, Double> progressCol = new TableColumn("Progress"); 
progressCol.setCellValueFactory(
    new PropertyValueFactory<TestTask, Double>("progress") 
); 
progressCol.setCellFactory(
    ProgressBarTableCell.<TestTask> forTableColumn() 
); 

progressColは、データ行としてTestTaskを取り、テストタスクのプロパティのうち、double値を抽出するために定義されています。

セル値ファクトリは、列のdouble値がどのように設定されるかを定義します。これは、パラメータ "progress"を取るPropertyValueFactoryに基づいて定義されます。これはプロパティ値ファクトリに、JavaFX命名規則とJavaリフレクションAPIを使用して関連するメソッドをルックアップし、TestTaskインスタンスからデータを取得するように指示します。この場合、TestTaskインスタンス上でprogressProperty()というメソッドが呼び出され、タスクの進行状況を反映するReadOnlyDoublePropertyが取得されます。

ドキュメントに記載されているように、PropertyValueFactoryは、以下のコードの混乱の手掛かりにすぎませんが、実際には、ObservableValueが返されているため、テーブル実装はセルの値を細胞の変化。

TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name"); 
firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() { 
    public ObservableValue<String> call(CellDataFeatures<Person, String> p) { 
    // p.getValue() returns the Person instance for a particular TableView row 
    return p.getValue().firstNameProperty(); 
    } 
}); 

OK、タスクは任意の進捗状況を作る時はいつでも今、我々は、セルの値は、タスクの進行状況のdouble値に反映されています。しかし、我々はまだその二倍の値を何とかグラフィカルに表現する必要があります。これはProgressBarTableCellの機能です。プログレスバーを含むテーブルセルです。forTableColumnメソッドは、列内の空でない行ごとにProgressBarTableCellsを生成するファクトリを作成し、PropertyValueFactoryによってタスクのprogressプロパティにリンクされたセルの値に一致するようにプログレスバーの進行を設定します。

詳細な実装の理解に混乱があります。 。 。確かに。しかし、これらの高レベルのヘルパーファクトリとセルは、あなたのための低レベルのリンケージの詳細を大事に扱うので、プレーンなAPIの使用の観点から何度もコードを書く必要はありません。論理的。

また、(SimpleStringPropertyなどの)プロパティがないので、SimpleStringPropertyで2つ以上の列が必要な場合はどうすればこの種類のTableViewに追加できますか?

もう一度PropertyValueFactoryを使用してください。さんにイメージをしてみましょうあなたはURLと呼ばれる文字列プロパティを持っている、あなたは、このような列を追加することができます:我々は唯一のセル値の工場を設定するために必要な

TableColumn<TestTask, Double> urlCol = new TableColumn("URL"); 
urlCol.setCellValueFactory(
    new PropertyValueFactory<TestTask, Double>("url") 
); 

注意、列のデフォルトのセル工場が返されますので、これはセルの文字列値を直接表示するラベルを含むセル。上記が正しく動作するために

は、今、私たちは、たとえば、タスクのURLを提供TestTaskのメソッドを必要とする:命名規則は、ここで本当に重要であることを

final ReadOnlyStringWrapper url = new ReadOnlyStringWrapper(); 

public TestTask(String url) { 
    this.url.set(url); 
} 

public ReadOnlyStringProperty urlProperty() { 
    return url.getReadOnlyProperty() 
} 

注意を、それがurlProperty(なければなりません)それは他のものであってはならないか、PropertyValueFactoryはプロパティ値アクセサを見つけられません。

これらの目的のために、getUrl()を使用した単純なString値は、PropertyValueFactoryがプロパティメソッドと同様にゲッターで動作するプロパティと同様に機能します。プロパティメソッドを使用する唯一の利点は、ストレートゲッターでは不可能なプロパティ変更イベントに基づいてテーブル値データを自動的に更新できることです。しかしここでは、URLが事実上最終的であり、与えられたタスクに対して変更されないため、タスクからこのファイルに対してゲッターメソッドまたはプロパティメソッドが提供されるかどうかは異なりません。

+0

このデモアプリケーションをテストしました。これは素晴らしい仕事です。しかし、私にとっては、このコードを理解するのは難しいです。ここには拘束力はありません(少なくとも私は見ません)。また、SimpleStringPropertyなどのプロパティがないので、SimpleStringPropertyを持つ2つの列が必要な場合はどうすればこの種類のTableViewに追加できますか?前もって感謝します。 – ksarunas

+0

Sarasのコメント – jewelsea

+0

の質問に基づいて余分な情報を提供するように更新されましたあなたの時間とそのような深い答えに感謝します。それは私をたくさん助けました。 – ksarunas

関連する問題