1. ホーム
  2. java

[解決済み] Java FXのシーンリフレッシュを強制的に行うには?

2022-02-08 20:46:32

質問

私は、スタートボタンとマップのタイルを表すいくつかの長方形を持つJava FXのシーンを持っています。また、エクスプローラーを表す球体も描きましたが(マップを探索する必要があります)、アニメーションを実行するのに苦労しています。

スタートボタンの OnMouseClicked ハンドラで、球体の位置と訪問したタイルの色を変更するマップ探索のアルゴリズムを開始しました。問題は、アルゴリズムが実行されている間、シーンが更新されないことです。どうすれば、シーンを強制的に更新して、すべての色の変化を順次見ることができるでしょうか?

後ほど編集します。

import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Test extends Application {

private static final double boxOuterSize = 50;
private static final double boxInnerSize = 48;
private static final double boxCornerRadius = 20;

private Stage applicationStage;
private Scene applicationScene;

private static double   sceneWidth  = 1024;
private static double   sceneHeight = 800;
private static HBox     container = new HBox();
private static Group    root = new Group();
private Rectangle[] rectangles = new Rectangle[10];

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

    applicationStage = mainStage;
    container.setSpacing(10);
    container.setPadding(new Insets(10, 10, 10, 10));

    try {
        applicationScene = new Scene(container, sceneWidth, sceneHeight);
        applicationScene.addEventHandler(EventType.ROOT,(EventHandler<? super Event>)this);
        applicationScene.setFill(Color.WHITE);

    } catch (Exception exception) {
        System.out.println ("exception : "+exception.getMessage());
    }

    applicationStage.setTitle("HurtLockerRobot - Tema 3 IA");
    applicationStage.getIcons().add(new Image("icon.png"));
    applicationStage.setScene(applicationScene);

    for(int i=0; i<10; i++) {
        Rectangle r = new Rectangle();
        r.setFill(Color.BLUE);
        r.setX(i * boxOuterSize);
        r.setY(0);
        r.setWidth(boxInnerSize);
        r.setHeight(boxInnerSize);
        r.setArcHeight(boxCornerRadius);
        r.setArcWidth(boxCornerRadius);
        r.setSmooth(true);
        rectangles[i] = r;
        root.getChildren().add(rectangles[i]);
    }

    container.getChildren().add(root);
    Button startButton = new Button("Start");
    startButton.setOnMouseClicked(new EventHandler<Event>() {
        @Override
        public void handle(Event arg0) {
            for(int i=0; i<10; i++) {
                rectangles[i].setFill(Color.RED);
                // TODO: some kind of scene refresh here
            }
        }
    });
    container.getChildren().add(startButton);

    applicationStage.show();
}

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

初期状態では、すべての矩形が青色です。ここで得たい動作は、矩形の色が順次変化していく様子を見ることです。問題は、最終的な結果(すべての矩形が同時に色を変える)しか見えないことです。

解決方法は?

これは古い質問ですが、JavaFXを始めたばかりの人が直面する非常に一般的な問題であるため、私の目を引きました。

OPが直面している問題は、すべての矩形を待たずに一度に更新していることです。

OPは、新しいスレッドを作成し、ループの反復ごとに推定秒数だけスレッドをスリープさせ、JavaFXアプリケーションのスレッドで、次のようにして矩形の色を更新することで待機できます。 Platform.runLater .

@Override
public void handle(Event arg0) {
  new Thread(() -> {
     for(int i=0; i<10; i++) {
       try {
          Thread.sleep(1000); // Wait for 1 sec before updating the color
       } catch (InterruptedException e) {
          e.printStackTrace();
       }
       int finalI = i;
       Platform.runLater(() -> rectangles[finalI].setFill(Color.RED));// Update on JavaFX Application Thread
   }
}).start();

上記のスニペットは、どちらかというと伝統的な方法です。もし、JavaFXのやり方を使いたいのであれば、同じように、quot;JavaFX;quot;quot;を使ってください。 Animation .

以下は、このコードです。 x-seconds 矩形の色を変更する前に、矩形の色を変更します。待ち時間は PauseTransition が各矩形に適用されます。

startButton.setOnMouseClicked(new EventHandler<Event>() {
    @Override
    public void handle(Event arg0) {
        for(int i=0; i<10; i++) {
            PauseTransition pauseTransition = new PauseTransition(Duration.seconds(i));
            int finalI = i;
            pauseTransition.setOnFinished(event -> rectangles[finalI].setFill(Color.RED));
            pauseTransition.play();
        }
    }
});

各矩形に対して PauseTransition を作成し、その配列内のインデックスに応じて rectangles で、同じ秒数だけ待ってから色を更新する。