Pour ceux que ca interresse, voici mon 1er jet en JavaFX 2.0, le port d'une animation simple : un rectangle rempli d'un dégradé de rouge dont la largeur varie. L'animation se lance en cliquant sur un bouton situé sous le rectangle tandis que le texte de ce même bouton change suivant que l'animation est lancée ou pas. Cela permet voir quelques petites choses : la création de la scène, le placement des noeuds, l'initialisation du gradient, la déclaration de l'animation et de sa keyframe, ainsi que le binding.
Ce permier code est la version 1.3.1, donc écrite en JavaFX Script, de ce même programme (il est relativement simple à comprendre même s'il est écrit dans un language différent du Java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| package test;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.shape.Rectangle;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.paint.Color;
import javafx.animation.Timeline;
import javafx.animation.Interpolator;
/**
* @author Fabrice
*/
def rectangle: Rectangle = Rectangle {
x: 100
y: 100
width: 200
height: 100
arcHeight: 10
arcWidth: 10
fill: LinearGradient {
startX: 0.0
startY: 0.0
endX: 1.0
endY: 0.0
stops: [
Stop {
color: Color.RED
offset: 0.0
},
Stop {
color: Color.DARKRED
offset: 1.0
},
]
}
}
def button: Button = Button {
layoutX: 250
layoutY: 250
action: toggleAnimation
text: bind if (animation == null) { "Start" } else { "Stop" }
}
Stage {
title: "JavaFX 1.3.1 animation + bind test"
width: 600
height: 600
scene: Scene {
content: [
rectangle,
button
]
}
}
var animation: Timeline;
function toggleAnimation(): Void {
if (animation == null) {
animation = Timeline {
autoReverse: true
repeatCount: Timeline.INDEFINITE
keyFrames: [
at (2s) {
rectangle.width => 50 tween Interpolator.EASEBOTH
}
]
}
animation.playFromStart();
} else {
animation.stop();
animation.time = 0s;
animation = null;
}
} |
[ATTACH]78108d1/a/a/a" />
Ce second code est la nouvelle version pour JavaFX 2.0 écrite en Java (Java7 pour être précis, voir la syntaxe des Generics utilisée, facilement modifiable pour faire tourner sur Java 6.).
Deux aménagements faits par rapport au programme initial :
- Il m'a fallu initialiser le texte de mon bouton à une valeur par défaut puisque le binding fonctionne différement ici.
- J'ai inversé la syntaxe d'arrêt de l'animation : mise à 0 puis stop() car sinon si je faisais comme en 1.x, mon rectangle n'était pas remis à son état initial (un bug ? ou moi qui m'y prend mal ?). C'est génant bien sur car dans le cas d'animations rapide, il peut y avoir un déplacement de l'objet animé entre les deux étapes. Si c'est un bug, j'espère qu'il sera rapidement corrigé.
Bien sur comme c'est mon tout premier code, il est probablement possible de faire mieux et bien sur aussi qu'on pouvait gérer l'état du texte du bouton d'une manière beaucoup plus simple "en Java normal" (avec un membre Timeline animation privé surlequel on fait directement des tests sans passer par des getters et setters) mais le but ici était d'arriver à reproduire le binding de FX 1.x le plus fidèlement possible.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| package test;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* @author Fabrice
*/
public class Main extends Application {
/**
* @param args the command line arguments
*/
public static void main(String... args) {
Application.launch(Main.class, args);
}
private Rectangle rectangle = new Rectangle(100, 100, 200, 100);
private Button button = new Button("Start");
/**
* {@inheritDoc}
*/
@Override
public void start(Stage primaryStage) {
Group root = new Group();
rectangle.setArcHeight(10);
rectangle.setArcWidth(10);
rectangle.setFill(new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, new Stop[]{
new Stop(0, Color.RED),
new Stop(1, Color.DARKRED)
}));
button.setLayoutX(250);
button.setLayoutY(250);
button.setOnAction(new EventHandler<ActionEvent>() {
/**
* {@inheritDoc}
*/
@Override
public void handle(ActionEvent event) {
toggleAnimation();
}
});
root.getChildren().addAll(rectangle, button);
Scene scene = new Scene(root);
primaryStage.setTitle("JavaFX 2.0 animation + bind test");
primaryStage.setWidth(600);
primaryStage.setHeight(600);
primaryStage.setScene(scene);
primaryStage.setVisible(true);
animationProperty().addListener(new ChangeListener<Timeline>() {
/**
* {@inheritDoc}
*/
@Override
public void changed(ObservableValue<? extends Timeline> observable, Timeline oldValue, Timeline newValue) {
button.setText(newValue == null ? "Start" : "Stop");
}
});
}
private void toggleAnimation() {
if (getAnimation() == null) {
Timeline animation = new Timeline();
animation.setAutoReverse(true);
animation.setCycleCount(Timeline.INDEFINITE);
final KeyValue<Number> keyValue = new KeyValue<>(rectangle.widthProperty(), 100, Interpolator.EASE_BOTH);
final KeyFrame keyFrame = new KeyFrame(new Duration(2000), keyValue);
animation.getKeyFrames().add(keyFrame);
animation.playFromStart();
setAnimation(animation);
} else {
Timeline animation = getAnimation();
animation.jumpTo(Duration.ZERO);
animation.stop();
setAnimation(null);
}
}
private ObjectProperty<Timeline> animationProp = new ObjectProperty<>();
// Define a getter for the property's value
public final Timeline getAnimation() {
return animationProp.get();
}
// Define a setter for the property's value
public final void setAnimation(Timeline value) {
animationProp.set(value);
}
// Define a getter for the property itself
public ObjectProperty<Timeline> animationProperty() {
return animationProp;
}
} |
[ATTACH]78109d1/a/a/a" />
Evidement dans cette version, la syntaxe est beaucoup plus lourde et plus verbeuse mais en même temps probablement plus compréhensible pour des gens habitués à du Swing ou de l'AWT.
2 |
0 |