2017-04-22 5 views
0

私の質問は、TextFieldだけでなく、この特定のタイプのノードのみを含む広い範囲のノードに適用されます。TextFieldバインディングを適切に処理し、ノード参照をタスクと分離して保持する方法

私のアプリケーションはChoiceBoxから作られた都市の選択に基づいて国の名前が表示されますテキストフィールドの内容を変更します。

My application changes the content of a TextField which displays the name of a country based on the selection of a city made from a ChoiceBox

私はcountryTextFieldのテキストを設定することでこれを実現それはうまく動作しますが、実際に私がやりたいことは完全に分離され

@FXML 
public void handleCityChoice() { 
    new Thread(new CityChoiceTask(cityChoiceBox.getValue())).start(); 
} 

class CityChoiceTask extends Task<Void> { 
    String selection; 
    CityChoiceTask(String selection) { 
     this.selection = selection; 
    } 
    @Override 
    public Void call() { 
     Platform.runLater(() -> countryTextField.setText(Datasource.getInstance(). 
       getCountryNameByCityName(selection))); 
     return null; 
    } 
} 

:選択ボックスのonActionイベントハンドラを使用してTask<Void>ノードはTaskコードを参照しているので、そうするのがベストプラクティスです(私はちょうど学生ですから、これについて間違っていれば正解ですが、私が教えたものです)。私は、バインドが実行される前にタスクスレッドが完了していないので、それがあると信じて、以下を試してみましたが、NullPointerExceptionを投げ続ける:

@FXML 
public void handleCityChoice() { 
    Task task = new CityChoiceTask(cityChoiceBox.getValue()); 
    new Thread(task).start(); 
    countryTextField.textProperty().bind(task.valueProperty()); 
} 

class CityChoiceTask extends Task<SimpleStringProperty> { 
    String selection; 
    CityChoiceTask(String selection) { 
     this.selection = selection; 
    } 
    @Override 
    public SimpleStringProperty call() { 
     String result = Datasource.getInstance().getCountryNameByCityName(selection)); 
     return new SimpleStringProperty(result); 
    } 
} 

また、System.out.println(task.valueProperty());

プリント:

OBJECTPROPERTY [豆:[email protected]、 名前:値、値:NULL]

スレッドが実際に実行されていない理由は、NullPointerExceptionを投げているのですが、それを修正する方法はありますか?

TableViewを使用すると、この種のバインドがうまく動作します。 例えば、FXCollections.observableArrayListのValuePropertyを返すTaskを使用すると、スレッドが実行を終了したときに関係なく、myTableView.itemsProperty().bind(task);のようなものが正常に機能します。

+1

2番目のコードスニペットで 'Task'にtypeパラメータを追加してみてください... – fabian

答えて

1

Taskの型パラメータとして適切な戻り値の型を使用する必要があります。 Stringプロパティを割り当てたいので、Stringを使用する必要があります。 (あなたは生の型を使用しなかった場合、あなたのコンパイラは、このエラーについて訴えているでしょう。)

@Override 
public void start(Stage primaryStage) { 
    TextField text = new TextField(); 

    Button btn = new Button("Run"); 
    btn.setOnAction((ActionEvent event) -> { 
     Task<String> task = new Task<String>() { 

      @Override 
      protected String call() throws Exception { 
       Thread.sleep(1000); 
       return "Hello World"; 
      } 

     }; 
     text.textProperty().bind(task.valueProperty()); 
     new Thread(task).start(); 
    }); 

    VBox root = new VBox(btn, text); 

    Scene scene = new Scene(root); 

    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 

をまたupdateValueメソッドを使用して中間更新を投稿することができます。


また、最初のスニペットは、アプリケーション以外のスレッドで実際には動作しません。タスクは、後でアプリケーションスレッドで情報を取得するためのコードをスケジュールするためにのみ使用されます。この目的のためにTaskを使用することも不要です。シンプルRunnableは十分であろう:

final String selection = cityChoiceBox.getValue(); 
new Thread(() -> { 
    // do this on this thread, not on the JavaFX application thread 
    final String result = Datasource.getInstance().getCountryNameByCityName(selection); 

    Platform.runLater(() -> countryTextField.setText(result)); 
}).start(); 
1
あなたは Stringにあなたのタスクの種類を変更したり、タスクの call()方法から updateValue()を呼び出す必要があり

class CityChoiceTask extends Task<String> { 

    private final String selection; 

    CityChoiceTask(String selection) { 
     this.selection = selection; 
    } 

    @Override 
    public String call() { 
     String result = Datasource.getInstance().getCountryNameByCityName(selection); 
     updateValue(result); 
     return result; 
    } 
} 

そして、あなたは前countryTextField.textProperty()をバインドする必要がありますあなたのhandleCityChoice()方法で(結合を作成する)コードが実行される前に実行を終了することができるので、countryTextフィールドは更新されません。

@FXML 
public void handleCityChoice() { 
    CityChoiceTask task = new CityChoiceTask(cityChoiceBox.getValue()); 
    countryTextField.textProperty().bind(task.valueProperty()); 
    new Thread(task).start(); 

} 
+0

ありがとう、これは問題でした。私は 'Task 'を 'Task 'に変更する必要がありました。私はまた、コンパイルエラーを投げなかったので、間違いだった参照のための生のタイプのタスクを使用しました。スレッドを開始する前に 'udpateValue()'と 'countryTextField.textProperty()'のバインディングについてのヒントをありがとう。スレッドが実行を終了する前に値をバインドする必要があるかどうかはわかりませんでした。私は最初に投稿したのでファビアンへの答えを与えなければならなかったが、あなたの答えも同様だった。 – DayTripperID

関連する問題