Don't create a new transition every time you want to shake the field, otherwise the field will shake while it is already shaking, the outcome of which would be difficult to predict but probably pretty undesirable.
The other thing you need to do is to setFromX(0) for the translate transition. This is actually pretty important because what happens with a translate transition is that, when it stops, the translateX value for the node remains at whatever it was when the transition stopped.
When you invoke playFromStart multiple times while the transition is playing, the transition will be stopped again and then started from the beginning. If you don't have a fromX, then the beginning will be wherever the translateX value last ended up at (which might not be what you want at all and, after shaking, the item might start moving to seemingly random positions on the screen). However, if you have a fromX, then the beginning translateX value will always start from an untranslated position.
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ShakenNotStirred extends Application {
@Override
public void start(Stage stage) throws Exception {
TextField field = new TextField();
Shaker shaker = new Shaker(field);
field.textProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
try {
Integer.parseInt(newValue);
} catch (NumberFormatException e) {
shaker.shake();
}
}
});
StackPane layout = new StackPane(field);
layout.setPadding(new Insets(20));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
class Shaker {
private TranslateTransition tt;
public Shaker(Node node) {
tt = new TranslateTransition(Duration.millis(50), node);
tt.setFromX(0f);
tt.setByX(10f);
tt.setCycleCount(2);
tt.setAutoReverse(true);
}
public void shake() {
tt.playFromStart();
}
}
}