Locked History Actions

Diff for "JavaFx/setManaged"

Differences between revisions 1 and 2
Deletions are marked like this. Additions are marked like this.
Line 15: Line 15:
AnimationTimerでもTimelineでも同じだが、こういった定期的に、しかも1秒に数十回以上行うような場合には、注意しないと不必要なrootからのレイアウトがその数だけ発生してしまう。

setManagedの意味

setManagedというメソッドがなぜ存在するのか不思議だったのだが、その意味はこうだ。

  • trueの場合、そこでの何らかの変更があった場合に、それをトップレベルにまで伝えてすべてのレイアウトをやり直す。
  • デフォルトではtrueになっている。
  • レイアウト用のペイン、つまりBorderPaneやら何やらのみではなく、すべてのParentとNodeの関係においてこの仕組みが働く。

ということ。例えば、以下の例のようにAnimationTimerを使用してボールを転がすような場合、ボールが転がるたび、つまりAnimationTimerのtickごとにトップレベルからの再レイアウトがかかってしまう。

このような場合には、Group自体をunmanagedにする。すると、再レイアウトはかからない。もちろん、再レイアウトがされないので、自力でレイアウトする必要がある。

この例では問題は無いが、例えばAnimationTimerのtickごとにLabelに現在時刻を表示するような場合、Labelをunmanagedにしなければならないが、そうするとおそらくLabelはレイアウトの枠組みからはずれてしまい、自力で所定の位置に置かなければならなくなると思われる。

AnimationTimerでもTimelineでも同じだが、こういった定期的に、しかも1秒に数十回以上行うような場合には、注意しないと不必要なrootからのレイアウトがその数だけ発生してしまう。

import static java.lang.Math.*;

import java.util.*;

import javafx.animation.*;
import javafx.application.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.stage.*;

public class GraphicsWithRegions extends Application {

  private Circle ball;
  private double direction;
  private Random random = new Random();
  private double speed = 10;
  @Override
  
  public void start(final Stage primaryStage) {

    ball = new Circle(100, 100, 20);
    ball.setFill(Color.BLUE);
    direction = 2 * PI * random.nextDouble();

    Group group = new Group(ball);
    Pane pane = new Pane(group);
    group.setManaged(false); // <------------- 無いとレイアウトがかかりすぎる。

    BorderPane border = new BorderPane() {
      @Override
      public void layoutChildren() {
        System.out.println("layoutChildren");
        super.layoutChildren();
      }
    };
    border.setCenter(pane);
    border.setTop(new TextArea("top area"));
    border.setBottom(new TextField("bottom field"));
    final Scene scene = new Scene(border, 800, 600, Color.BLACK);
    primaryStage.setScene(scene);
    primaryStage.show();

    ball.setCenterX(pane.getWidth() / 2);
    ball.setCenterY(pane.getHeight() / 2);
    
    new AnimationTimer() {
      @Override
      public void handle(long now) {
        double x = ball.getCenterX();
        double y = ball.getCenterY();
        double newDirection = random.nextDouble() * PI;
        
        if (y < 0) {
          direction = newDirection;
        } else if (pane.getWidth() < x) {
          direction = newDirection + PI * 0.5;
        } else if (pane.getHeight() < y) {
          direction = newDirection + PI;
        } else if (x < 0) {
          direction = newDirection + PI * 1.5;
        }

        ball.setCenterX(x + speed * cos(direction));
        ball.setCenterY(y + speed * sin(direction));
      }
    }.start();
  }

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