web-dev-qa-db-ja.com

JavaFXを待機させ、コードを続行する

基本的に私はJavaFXを使用して短いエフェクトを作成しようとしています。 2つの値pを使用してサイズを変えることができるハートの形(2つの円とポリゴンから足し合わされたもの)があります。 「Standart Size」は_p = 1.0;_になります。

私は心臓にポンプ効果を加えようとしています。私はメソッドpumpOnce()を持っています:

_public void pumpOnce(){
    p = p + 1;
    initHeart();
    //Here goes what ever it takes to make stuff working!!
    p = p - 1;
    initHeart();
}
_

initHeart()は、pに基づいてハートを描画します。

Thread.sleep();または同様のメソッドは、JavaFXのスレッド哲学のために機能しないことがわかりました。

しかし、代わりに何を使用できますか?

9
Maverick283

JavaFXアニメーションはおそらく進むべき道ですが、JavaFXの「スレッドの哲学」は、独自にロールバックしたり、バックグラウンドスレッドで他のより複雑なことを実行したりする場合に簡単に機能します。

次のコードは一時停止し、ラベルの値を変更します(完全な開示、別の質問のために書いたコードを再利用しています)。

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class HelloWorld extends Application {

    private static Label label;

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

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        label = new Label();
        label.setText("Waiting...");
        StackPane root = new StackPane();
        root.getChildren().add(label);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();

        Task<Void> sleeper = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                }
                return null;
            }
        };
        sleeper.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent event) {
                label.setText("Hello World");
            }
        });
        new Thread(sleeper).start();
    }
}

基本的なJavaFXバックグラウンドツールはタスクです。実際に何かを実行するJavaFXアプリケーションは、おそらくこれらすべてに散らばっています。それらを使用する方法を学びます。

14
DaveB

Daveのソリューションは、JavaFXでの汎用のスレッドベースの作業に最適です。

JavaFXのアニメーション機能を使用したい場合、以下のソリューションは、タイムラインまたはScaleTransitionを使用してこれを示しています。タイムラインは、UI要素の個別のスケールを実装しているため、1/4秒ごとにUI要素が拡大または元のサイズに戻ります。スケール遷移はUI要素のスムーズなスケールを実装するため、補間されたスケール係数を デフォルトのイージングインターポレーター で使用すると、UIエレメントは徐々に大きくなり、小さくなります。

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;

public class BeatingHeart extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage stage) {
        ImageView heart = new ImageView(HEART_IMAGE_LOC);

        animateUsingTimeline(heart);
//        animateUsingScaleTransition(heart);

        StackPane layout = new StackPane(heart);
        layout.setPrefWidth(heart.getImage().getWidth() * 2);
        layout.setPrefHeight(heart.getImage().getHeight() * 2);

        Scene scene = new Scene(layout);
        stage.setScene(scene);
        stage.show();
    }

    private void animateUsingTimeline(ImageView heart) {
        DoubleProperty scale = new SimpleDoubleProperty(1);
        heart.scaleXProperty().bind(scale);
        heart.scaleYProperty().bind(scale);

        Timeline beat = new Timeline(
            new KeyFrame(Duration.ZERO,         event -> scale.setValue(1)),
            new KeyFrame(Duration.seconds(0.5), event -> scale.setValue(1.1))
        );
        beat.setAutoReverse(true);
        beat.setCycleCount(Timeline.INDEFINITE);
        beat.play();
    }

    private void animateUsingScaleTransition(ImageView heart) {
        ScaleTransition scaleTransition = new ScaleTransition(
            Duration.seconds(1), heart
        );
        scaleTransition.setFromX(1);
        scaleTransition.setFromY(1);
        scaleTransition.setFromZ(1);
        scaleTransition.setToX(1.1);
        scaleTransition.setToY(1.1);
        scaleTransition.setToZ(1.1);
        scaleTransition.setAutoReverse(true);
        scaleTransition.setCycleCount(Animation.INDEFINITE);
        scaleTransition.play();
    }

    private static final String HEART_IMAGE_LOC =
            "http://icons.iconarchive.com/icons/mirella-gabriele/valentine/128/Heart-red-icon.png";
    // icon obtained from: http://www.iconarchive.com/show/valentine-icons-by-mirella-gabriele/Heart-red-icon.html
    // icon license: Free for non-commercial use, commercial use not allowed.
}
6
jewelsea