Difference between Timeline's stop() and jumpTo("end") - animation

Could somebody explain me the difference between timeline.stop() and timeline.jumpTo("end")?

Timeline.stop() halts the animation and makes sure Timeline.play() starts form the beginning of the animation; no more updates for the "current run" are done.
timeline.jumpTo("end") goes to the mark "end" which is positioned at the end of the animation. This has the same effect as timeline.jumpTo(timeline.getTotalDuration()). Any effects of the animation arriving at that time are executed.
You can observe the different behavior in the following example:
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Play / (Stop/Jump)");
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(btn.translateXProperty(), 0d)),
new KeyFrame(Duration.seconds(10), new KeyValue(btn.translateXProperty(), 200d))
);
btn.setOnAction((ActionEvent event) -> {
if (timeline.getStatus() == Animation.Status.RUNNING) {
// timeline.jumpTo("end");
timeline.stop();
} else {
timeline.play();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
timeline.jumpTo("end") moves the Button to the end point of the animation, timeline.stop() stops the Button in it's current position.

Related

Rotation through images using JAVA FX

Essentially I'm trying to make a glowing warning image.
Starts just being a red triangle, but then emits a glow, then goes back to a red triangle.
But I'm trying to figure out a way to implement it.
I thought of using timelines, but it will only show the last picture, and stay on it.
I've replaced my Imaged with ones publicly available.
With these images it should come up "Number 1" for 2 seconds, "Number 2" for 2 seconds, "number 3" for 2 seconds, then go back to number 1 and repeat indefinitely.
Other than my way, if someone has a better way to make my objective happen in a different way with Java FX (That isn't too complex, I'm pretty new to Java FX). I'm all ears
Thanks again!
Here is the code I've fiddled with.
public class GlowEffect extends Application {
#Override
public void start(Stage primaryStage) {
Image img1 = new Image("http://clipart-library.com/images/dc9rEEbdi.jpg");
Image img2 = new Image("http://clipart-library.com/data_images/356167.png");
Image img3 = new Image("http://clipart-library.com/data_images/123556.png");
ImageView imgview1 = new ImageView();
imgview1.setX(0);
imgview1.setY(0);
Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(2), e -> imgview1.setImage(img1)),
new KeyFrame(Duration.seconds(2), e -> imgview1.setImage(img2)),
new KeyFrame(Duration.seconds(2), e -> imgview1.setImage(img3))
);
timeline.setCycleCount(Animation.INDEFINITE);
Pane pane = new Pane(imgview1);
Scene scene = new Scene(pane, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
timeline.play();
}
public static void main(String[] args) {
launch(args);
}
}

Javafx relocate and rotate

i have an node in javafx which are moving in a timeline.
Now i want rotate the node also.
I tried it but everytime the node doesn't hold the path anymore and "fly away". Is there a way to relcate and rotate (I tried it with rotatetransition)?
Edit:
That is my View -Class
public class MyView extends ImageView{
public MyView (Image image) {
super(image);
RotateTransition transition = new RotateTransition();
transition.setCycleCount(Animation.INDEFINITE);
transition.setNode(this);
transition.setDuration(Duration.millis(10));
transition.setFromAngle(5);
transition.setToAngle(5;
transition.setAutoReverse(true);
transition.play(); // */
}
}
On another class i have this:
private void startMoveAnimation(MyView[] views) {
x++;
y++;
this.timeline = new Timeline();
timeline.setCycleCount(Animation.INDEFINITE);
moveEvent = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
for(View view: views){
view.relocate(x,y);
}
}
}
};
KeyFrame moveKeyFrame = new KeyFrame(Duration.millis(SPEED), moveEvent);
timeline.getKeyFrames().add(moveKeyFrame);
timeline.play(); // */
}
x and y are double values.
Using transforms gives you better control of the order of the transformations. Furthermore some transfroms allow you to specify a pivot point, which is not possible for e.g. the Node.rotate property. Transforms in a list are applied "right to left". (The transform with the highest index is applied first).
The following example shows how to move a rectangle rotating arount its own center (even though the cycle resets to the original position instead of continuously moving in the same direction, but the properties of the transforms can be animated independently in arbitrary ways):
#Override
public void start(Stage primaryStage) {
Rectangle view = new Rectangle(100, 100);
// pivot point = center of rect
Rotate rotate = new Rotate(0, 50, 50);
Translate translate = new Translate();
// rotate first, then move
view.getTransforms().addAll(translate, rotate);
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(translate.xProperty(), 0d),
new KeyValue(translate.yProperty(), 0d), new KeyValue(rotate.angleProperty(), 0d)),
new KeyFrame(Duration.seconds(2), new KeyValue(translate.xProperty(), 300d),
new KeyValue(translate.yProperty(), 500d), new KeyValue(rotate.angleProperty(), 360d)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
Pane root = new Pane(view);
Scene scene = new Scene(root, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
That's what I would try first:
Put the node into a Group. Add the Group to the parent instead of the node. Do the translate animation on the Group and do the rotate animation on the node itself. This is just a first guess which I cannot try out because you haven't provided a minimal reproducible example.

How to change CURSOR to busy and prevent user clicking

I have three COMBO BOXES in my window. It is a family tree application I am developing using JavaFX and SQLIte. Each person has Father, Mother and Spouse info which can be selected from ComboBoxes. ComboBoxes are loaded with data from database.
It takes a while to load these three combo boxes. Actually different delays for different combo boxes.
If I click on a combo box while it is not ready or another combo box is not ready, the screen turns white until the other combo box is ready.
I want to prevent user input on entire window from Mouse, Keyboard and Buttons until entire window is ready to accept user's input. Until then I want change the cursor to something like STOP.
How to do this? Any suggestions?
Thanks,
Hornigold
Run a Task<ObservableList<SomeType>> (or a Task returning some object containing more than a single list) on a seperate Thread. Before starting the thread you disable the root and set the cursor for the scene and when the task finishes you initialize the GUI with the results and reenable the scene again:
#Override
public void start(Stage primaryStage) {
Button loadButton = new Button("load");
ComboBox<String> combo = new ComboBox<>();
VBox root = new VBox(combo, loadButton);
Scene scene = new Scene(root);
loadButton.setOnAction(evt -> {
root.setDisable(true);
// save old cursor to restore after finishing the task
final Cursor oldCursor = root.getScene().getCursor();
scene.setCursor(Cursor.WAIT);
Task<ObservableList<String>> task = new Task<ObservableList<String>>() {
#Override
protected ObservableList<String> call() throws Exception {
ObservableList<String> result = FXCollections.observableArrayList();
for (int i = 0; i < 100; i++) {
result.add(Integer.toString(i));
}
// simulate delay
Thread.sleep(5000);
return result;
}
};
task.setOnSucceeded(e -> {
// use results of task in the GUI
combo.setItems(task.getValue());
// restore cursor and reenable scene
root.setDisable(false);
scene.setCursor(oldCursor);
});
task.setOnFailed(e -> {
// todo: handle exception in Task.call
});
Thread thread = new Thread(task);
thread.start();
});
primaryStage.setScene(scene);
primaryStage.show();
}

How to have selectable images from image gallery in javafx?

I am making an image gallery. I am using javafx 8 along with scene builder for GUI. I want the user to have choice of selecting images from a gallery: I want to have clickable and selectable images in the gallery. I also want to note the sequence of those selected images, i.e. which one was selected first and which one was selected last. I have made the gallery but I was wondering what I would do to make the images clickable and get the images selected, noting their sequence? I don't want to use checkboxes with the images.
You can add a setOnMouseClicked handler on each ImageView.
Here is a code example of what I mean:
public class ClickableImage extends Application {
private ArrayList<String> clickedImages = new ArrayList<>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
String imgUrl = getClass().getResource("image.png").toExternalForm();
assert imgUrl != null;
Image img = new Image(imgUrl);
assert img != null;
BorderPane root = new BorderPane();
ImageView imgView = new ImageView(img);
imgView.setUserData(imgUrl);
root.setCenter(imgView);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.setTitle("ClickableImage");
primaryStage.show();
//-------------
imgView.setOnMouseClicked(e -> {
String clickedImgUrl = (String)((ImageView)e.getSource()).getUserData();
System.out.println("Image was clicked: " + clickedImgUrl);
clickedImages.add(clickedImgUrl);
});
}
}

How to get smooth animation with KeyPress event in javaFX?

I am trying to implement LEFT RIGHT movement of a rectangle shape in JavaFX. Below is my code:
public void start(Stage primaryStage) throws Exception {
AnchorPane ancPane = new AnchorPane();
final Rectangle rect = new Rectangle();
rect.setHeight(50);
rect.setWidth(50);
ancPane.getChildren().add(rect);
Scene scene = new Scene(ancPane, 400, 200, Color.GREEN);
primaryStage.setScene(scene);
primaryStage.show();
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
System.out.println("hello");
if(keyEvent.getCode().toString() == "RIGHT"){
System.out.println("Move Right");
TranslateTransition translateTransitionRight = new TranslateTransition();
translateTransitionRight.setDuration(Duration.millis(200));
translateTransitionRight.setNode(rect);
translateTransitionRight.setFromX(rect.getTranslateX());
translateTransitionRight.setToX(rect.getTranslateX()+30);
translateTransitionRight.play();
}
if(keyEvent.getCode().toString() == "LEFT"){
System.out.println("Move Left");
TranslateTransition translateTransitionRight = new TranslateTransition();
translateTransitionRight.setDuration(Duration.millis(200));
translateTransitionRight.setNode(rect);
translateTransitionRight.setFromX(rect.getTranslateX());
translateTransitionRight.setToX(rect.getTranslateX()-30);
translateTransitionRight.play();
}
}
});
}
Here when I press either LEFT/RIGHT key continuously (i.e. I don't released the key, I hold it for some times) the rectangle moves but not continuously. It pauses for a small fraction of time just after animation started. After the pause the animation continues smoothly.
How can I get rid of this pausing of animation with KeyEvents?
I would use an AnimationTimer for moving the rectangle, and just update a property representing the velocity on key pressed or key released:
final Rectangle rect = ... ;
final double rectangleSpeed = 100 ; // pixels per second
final double minX = 0 ;
final double maxX = 800 ; // whatever the max value should be.. can use a property and bind to scene width if needed...
final DoubleProperty rectangleVelocity = new SimpleDoubleProperty();
final LongProperty lastUpdateTime = new SimpleLongProperty();
final AnimationTimer rectangleAnimation = new AnimationTimer() {
#Override
public void handle(long timestamp) {
if (lastUpdateTime.get() > 0) {
final double elapsedSeconds = (timestamp - lastUpdateTime.get()) / 1_000_000_000.0 ;
final double deltaX = elapsedSeconds * rectangleVelocity.get();
final double oldX = rect.getTranslateX();
final double newX = Math.max(minX, Math.min(maxX, oldX + deltaX));
rect.setTranslateX(newX);
}
lastUpdateTime.set(timestamp);
}
};
rectangleAnimation.start();
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode()==KeyCode.RIGHT) { // don't use toString here!!!
rectangleVelocity.set(rectangleSpeed);
} else if (event.getCode() == KeyCode.LEFT) {
rectangleVelocity.set(-rectangleSpeed);
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT) {
rectangleVelocity.set(0);
}
}
});
UPDATE:
The AnimationTimer executes its handle method once each time a frame is rendered by the JavaFX mechanism. The long passed into the handle method is a timestamp of the render frame, in nanoseconds.
The way this works is that we keep track of the last update time. The handle(...) method computes the elapsed time since the last update, multiplies it by the rectangle's velocity, and updates the translateX of the rectangle by that amount. The AnimationTimer is always running, but initially the velocity is set to zero so the rectangle doesn't move.
The keyPressed handler simply changes the velocity: to a positive value if moving right and a negative value if moving left. The keyReleased handler sets the velocity back to zero.

Resources