Reputation: 43
I'm trying to animate elements in GridPane
. I have a class Unit
that represents the things that I'm trying to move.
public class Unit {
private Text text;
private Rectangle rectangle;
private StackPane stackPane;
public Unit(Text text, Rectangle rectangle) {
this.text = text;
this.rectangle = rectangle;
text.setFill(Color.WHITE);
stackPane = new StackPane(rectangle, text);
}
public Text getText() {
return text;
}
public void setText(Text text) {
this.text = text;
}
public Rectangle getRectangle() {
return rectangle;
}
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
public StackPane getStackPane() {
return stackPane;
}
public void setStackPane(StackPane stackPane) {
this.stackPane = stackPane;
}
}
This is how i'm moving things now
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
GridPane gridPane = new GridPane();
gridPane.setVgap(5);
gridPane.setHgap(5);
Unit unit = new Unit(new Text("1"), new Rectangle(50, 50));
gridPane.add(unit.getStackPane(), 0, 0);
TranslateTransition translateTransition = new TranslateTransition();
translateTransition.setDuration(Duration.seconds(6));
translateTransition.setToX(200);
translateTransition.setToY(200);
translateTransition.setNode(unit.getStackPane());
translateTransition.play();
Scene scene = new Scene(gridPane, 300, 275);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Is there a way to move the unit to a specific row - column location. I assume that gridpane might not be suitable for my purpose but it's easy way to layout things the way i want.
Upvotes: 2
Views: 1762
Reputation: 18792
Some what hackish, but you can move the unit to the desired row - column, measure the new X,Y and use it for the translation.
The following code demonstrates animating from 0,0 to 20,20 :
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private Button move;
private Pane unitPane, root;
private GridPane gridPane;
@Override
public void start(Stage primaryStage) throws Exception{
gridPane = new GridPane();
gridPane.setVgap(5);
gridPane.setHgap(5);
unitPane = new Unit(new Text("1"), new Rectangle(50, 50)).getStackPane();
gridPane.add(unitPane, 0, 0);
move = new Button("Move");
move.setOnAction(e->animate());
root = new BorderPane(gridPane, null, null, move, null);
Scene scene = new Scene(root, 300, 275);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
private void animate() {
//remove unit, make it invisible, and add it to desired location
gridPane.getChildren().remove(unitPane);
unitPane.setVisible(false);
gridPane.add(unitPane, 20, 20);
root.layout(); //apply top down layout pass
//get x y of new location
double x = unitPane.getLayoutX(); double y = unitPane.getLayoutY(); //measure new location
//return to original location
gridPane.getChildren().remove(unitPane);
gridPane.add(unitPane, 0, 0);
unitPane.setVisible(true);
//apply translation to x,y of new location
TranslateTransition translateTransition = new TranslateTransition();
translateTransition.setDuration(Duration.seconds(3));
translateTransition.setToX(x);
translateTransition.setToY(y);
translateTransition.setNode(unitPane);
translateTransition.play();
//when translation is finished remove from original location
//add to desired location and set translation to 0
translateTransition.setOnFinished(e->{
gridPane.getChildren().remove(unitPane);
unitPane.setTranslateX(0);unitPane.setTranslateY(0);
gridPane.add(unitPane, 20, 20);
});
}
public static void main(String[] args) {
launch(args);
}
}
class Unit {
private Text text;
private Rectangle rectangle;
private StackPane stackPane;
Unit(Text text, Rectangle rectangle) {
this.text = text;
this.rectangle = rectangle;
text.setFill(Color.WHITE);
stackPane = new StackPane(rectangle, text);
}
public Text getText() {
return text;
}
public void setText(Text text) {
this.text = text;
}
public Rectangle getRectangle() {
return rectangle;
}
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
public StackPane getStackPane() {
return stackPane;
}
public void setStackPane(StackPane stackPane) {
this.stackPane = stackPane;
}
}
Upvotes: 2
Reputation: 159341
Here is an example based upon the layout animator at Animation upon layout changes (also in the gist https://gist.github.com/jewelsea/5683558). I don't really know if it is really what you are looking for (it might be pretty close). But in any case it is pretty neat ;-)
I won't explain it too much here as the main explanation on what it is and how it works is at the previously linked question.
The referenced Unit
class is the one from your question.
AnimatedSparseGrid.java
import javafx.animation.*;
import javafx.application.Application;
import javafx.collections.*;
import javafx.geometry.Point2D;
import javafx.scene.*;
import javafx.scene.layout.GridPane;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.*;
public class AnimatedSparseGrid extends Application {
private static final int NUM_UNITS = 10;
private static final int UNIT_SIZE = 30;
private static final int GRID_SIZE = 5;
private static final int GAP = 5;
private static final Duration PAUSE_DURATION = Duration.seconds(3);
private Random random = new Random(42);
private ObservableList<Unit> units = FXCollections.observableArrayList();
private GridPane gridPane = new GridPane();
@Override
public void start(Stage stage) throws Exception {
configureGrid();
LayoutAnimator animator = new LayoutAnimator();
animator.observe(gridPane.getChildren());
generateUnits();
relocateUnits();
continuouslyAnimateGrid();
stage.setScene(new Scene(gridPane));
stage.setResizable(false);
stage.show();
}
private void configureGrid() {
gridPane.setVgap(GAP);
gridPane.setHgap(GAP);
int size = GRID_SIZE * UNIT_SIZE + GAP * (GRID_SIZE - 1);
gridPane.setMinSize(size, size);
gridPane.setMaxSize(size, size);
}
private void generateUnits() {
for (int i = 0; i < NUM_UNITS; i++) {
Unit unit = new Unit(
new Text((i + 1) + ""),
new Rectangle(UNIT_SIZE, UNIT_SIZE)
);
units.add(unit);
}
}
private void relocateUnits() {
Set<Point2D> usedLocations = new HashSet<>();
for (Unit unit : units) {
Node node = unit.getStackPane();
int col;
int row;
do {
col = random.nextInt(GRID_SIZE);
row = random.nextInt(GRID_SIZE);
} while (usedLocations.contains(new Point2D(col, row)));
usedLocations.add(new Point2D(col, row));
GridPane.setConstraints(unit.getStackPane(), col, row);
if (!gridPane.getChildren().contains(node)) {
gridPane.add(node, col, row);
}
}
}
private void continuouslyAnimateGrid() {
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, event -> relocateUnits()),
new KeyFrame(PAUSE_DURATION)
);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 2