1

まず第一に、私はJavaFXが初めてなので、この質問がばかげている場合は申し訳ありません. タスクから戻りオブジェクトを取得するにはどうすればよいですか?

ここに私の問題があります:

モックからオブジェクトのリストを取得したい。モックには 1 ~ 5 秒の遅延があります。しかし、今回は GUI がフリーズするのは嫌です。

Java.Swing では Thread で簡単でしたが、JavaFX には私の知る限り Task があります。

多くのチュートリアルを読みましたが、どこでもテキスト プロパティを返します。だからここに私の質問があります: タスク/スレッド (私の場合はリスト) からの計算の結果でオブジェクトの値を設定するにはどうすればよいですか?

ありがとうございました。

4

2 に答える 2

2

レイ、

その例は、タスクから結果を返すことについてごまかしているように見えます。私が知っている結果を得るには、次の 2 つの方法があります。

  1. Task クラスのメソッドを介してgetValue()(これは私が行った方法です)
  2. 親 FutureTask クラスのメソッドを介してget()(私はこれを使用していませんが、原則として動作するはずです)。

最初のアプローチでは、タスクの call メソッドのメソッドをgetValue()介してタスクが値を設定することを確認する必要があります。updateValue(...)次に、WorkerStateEvent にリスナーを配置します。

myTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

    @SuppressWarnings("unchecked")
    @Override
    public void handle(WorkerStateEvent event) {
        ReturnType rt =  (ReturnType) event.getSource().getValue()
        // ... other stuff to do here ...
    }
});

最初のアプローチは少し冗長ですが、機能し、タスクが終了した後にいくつかのより複雑な操作を行うことができます。

2 番目の方法は、もう少し単純で簡単ですが、タスクが終了したときに何をするかをあまり制御できません。FutureTaskのget()メソッドを使用すると、Task が値を返すまでコードをブロックする必要があります。したがって、それを使用するのは次のように簡単です。

//
// Start the task in a thread (using whatever approach you like) 
//before calling the get() method.
//
ReturnType rt = myTask.get();

Future他のコードでオブジェクトを使用したことがありますが、FX API で使用しFutureTaskたことがないため、隠れた落とし穴があるかどうかはわかりません。

幸運を、

チョーク

于 2013-11-04T13:16:59.433 に答える
2

Task はジェネリック型です。つまりTask<Integer>、Task クラスのようなタイプを Task に適用すると、Integer を返す関数が含まれることになります。この関数の 1 つが で、valueProperty()他のシーン要素にバインドできます。ラベルなどに表示されます。理解を深めるために、 javafx binding tutorialを読むことをお勧めします。

以下は、またはそのプロパティを使用したタスクのサンプルです。

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TestingTasks extends Application{

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

    @Override
    public void start(Stage stage) throws Exception {

        VBox vbox = new VBox(10);
        vbox.setAlignment(Pos.TOP_CENTER);

        ListView<String> list = new ListView<>();
        HBox hbox = new HBox(10);
        hbox.setAlignment(Pos.CENTER_LEFT);
        Label labelMessage = new Label();
        hbox.getChildren().addAll(new Label("Message: "), labelMessage);
        ProgressBar progress = new ProgressBar(-1);
        progress.setVisible(false);

        Button button = new Button("Executing Task");
        button.setOnAction(event(button, list, progress, labelMessage));

        vbox.getChildren().addAll(list, hbox, button, progress);
        Scene scene = new Scene(vbox, 400, 300);
        stage.setScene(scene);
        stage.show();
    }

    private EventHandler<ActionEvent> event(final Button button, final ListView<String> list, final ProgressBar progress, final Label labelMessage) {       
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Task<ObservableList<String>> task = generateTask();
                list.itemsProperty().bind(task.valueProperty());
                progress.visibleProperty().bind(task.runningProperty());
                labelMessage.textProperty().bind(task.messageProperty());
                button.disableProperty().bind(task.runningProperty());
                task.runningProperty().addListener(listenerRunningTask());
                Thread t = new Thread(task);
                t.setDaemon(true);
                t.start();
            }

        };
    }

    private Task<ObservableList<String>> generateTask() {               
        return new Task<ObservableList<String>>() {                 
            @Override
            protected ObservableList<String> call() throws Exception {
                updateMessage("Waiting...");
                Thread.sleep(5000);
                updateMessage("Waking up");
                return FXCollections.observableArrayList("One", "Two", "Three");
            }
        };
    }   

    private ChangeListener<? super Boolean> listenerRunningTask() {     
        return new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if(oldValue && !newValue){
                    //TODO when finish
                }               
            }
        };
    }   
}

したがって、基本的に、タスクで変数を返すか、タスクの終了を待って何かを実行し、独自のバインディングを作成できます...

スレッドから画面の何かを変更したい場合は、FX スレッドから行う必要があります。タスク関数呼び出しは FX スレッドの外にあるため、画面はフリーズしません。ただし、バインド要素はすべて FX スレッドで発生するため、GUI を変更しても安全です。

FX スレッド以外から GUI を安全に変更したい場合は、次のようにします。

Platform.runLater(new Runnable() {                  
    @Override
    public void run() {
        //Safe modification in the FX Thread
    }
});

JavaFX2の並行性についても調べてください。これは、並行性、サービス、タスクをより深く説明しています...

それが役に立てば幸い!

于 2013-11-04T14:56:03.980 に答える