import java.lang.Number; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.application.Application; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.StringProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.geometry.Bounds; import javafx.scene.CacheHint; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.layout.GridPane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; import javafx.scene.transform.Affine; import javafx.stage.Stage; import javafx.util.Duration; /* * Rows contain objects with the same initial transform: * Row 0 - identity * Row 1 - translate * Row 2 - scale * Row 3 - rotate * Row 4 - shear * * Columns contain objects with the same cache hint: * Col 0 - cache = false * Col 1 - DEFAULT * Col 2 - SPEED * Col 3 - QUALITY * Col 4 - SCALE * Col 5 - ROTATE * Col 6 - ROTATE_AND_SCALE * * All nodes will undergo an animation timeline with the following effects: * 3 seconds of translate by 10,5 and back * 3 seconds of scale by 1.2,1.3 and back * 3 seconds of rotate full circle and back * 3 seconds of shear, 1s shearX .1, 1s shearY .1, 1s shearBoth .1 */ public class CacheHintTest extends Application { SimpleDoubleProperty transX = new SimpleDoubleProperty(0.0); SimpleDoubleProperty transY = new SimpleDoubleProperty(0.0); SimpleDoubleProperty rotate = new SimpleDoubleProperty(0.0); SimpleDoubleProperty scaleX = new SimpleDoubleProperty(1.0); SimpleDoubleProperty scaleY = new SimpleDoubleProperty(1.0); SimpleDoubleProperty shearX = new SimpleDoubleProperty(0.0); SimpleDoubleProperty shearY = new SimpleDoubleProperty(0.0); Affine animateTransform = new Affine(); CacheHint hints[] = { null, CacheHint.DEFAULT, CacheHint.SPEED, CacheHint.QUALITY, CacheHint.SCALE, CacheHint.ROTATE, CacheHint.SCALE_AND_ROTATE, }; public void start(Stage stage) { GridPane gp = new GridPane(); gp.setHgap(2); gp.setVgap(2); for (int i = 0; i < hints.length; i++) { int col = i + 1; CacheHint hint = hints[i]; gp.add(makeTitle(hint), col, 0); gp.add(makeNode(hint, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0), col, 1); gp.add(makeNode(hint, -5.0, -5.0, 0.0, 1.0, 1.0, 0.0, 0.0), col, 2); gp.add(makeNode(hint, 0.0, 0.0, 0.0, 1.2, 1.1, 0.0, 0.0), col, 3); gp.add(makeNode(hint, 0.0, 0.0, 30.0, 1.0, 1.0, 0.0, 0.0), col, 4); gp.add(makeNode(hint, 0.0, 0.0, 0.0, 1.0, 1.0, 0.2, 0.3), col, 5); } gp.add(makeLabel("identity\nnode"), 0, 1); gp.add(makeLabel("translated\nnode"), 0, 2); gp.add(makeLabel("scaled\nnode"), 0, 3); gp.add(makeLabel("rotated\nnode"), 0, 4); gp.add(makeLabel("sheared\nnode"), 0, 5); Scene scene = new Scene(gp); stage.setScene(scene); stage.show(); makeTimeline(stage.titleProperty()); } public Node makeTitle(CacheHint hint) { String s; if (hint == null) { s = "(no cache)"; } else if (hint == CacheHint.SCALE_AND_ROTATE) { s = "SCALE +\nROTATE"; } else { s = hint.toString(); } return makeLabel(s); } public Node makeLabel(String s) { Text t = new Text(s); Bounds b = t.getBoundsInParent(); t.setX(50 - b.getWidth()/2 - b.getMinX()); t.setY(50 - b.getHeight()/2 - b.getMinY()); return new Group(new Rectangle(100, 100, Color.WHITE), t); } public Node makeNode(CacheHint hint, double tx, double ty, double rot, double scx, double scy, double shx, double shy) { Rectangle r = new Rectangle(40, 40, 20, 20); r.setFill(Color.BLUE); if (hint == null) { r.setCache(false); } else { r.setCache(true); r.setCacheHint(hint); } if (shx != 0.0 || shy != 0.0) { Affine aff = new Affine(); aff.appendTranslation(50, 50); aff.appendTranslation(tx, ty); aff.appendRotation(rot); aff.appendScale(scx, scy); aff.appendShear(shx, shy); aff.appendTranslation(-50, -50); r.getTransforms().add(aff); } else { r.setTranslateX(tx); r.setTranslateY(ty); r.setRotate(rot); r.setScaleX(scx); r.setScaleY(scy); } Group animr = new Group(r); animr.getTransforms().add(animateTransform); return new Group(new Rectangle(100, 100, Color.WHITE), animr); } public void makeTimeline(StringProperty titleprop) { ChangeListener listener = new ChangeListener() { public void changed(ObservableValue observable, Number oldValue, Number newValue) { animateTransform.setToIdentity(); animateTransform.appendTranslation(50, 50); animateTransform.appendTranslation(transX.get(), transY.get()); animateTransform.appendRotation(rotate.get()); animateTransform.appendScale(scaleX.get(), scaleY.get()); animateTransform.appendShear(shearX.get(), shearY.get()); animateTransform.appendTranslation(-50, -50); } }; transX.addListener(listener); transY.addListener(listener); rotate.addListener(listener); scaleX.addListener(listener); scaleY.addListener(listener); shearX.addListener(listener); shearY.addListener(listener); KeyValue trx0 = new KeyValue(transX, 0.0); KeyValue try0 = new KeyValue(transY, 0.0); KeyValue trx1 = new KeyValue(transX, 10.0); KeyValue try1 = new KeyValue(transY, 10.0); KeyValue rot0 = new KeyValue(rotate, 0.0); KeyValue rot1 = new KeyValue(rotate, 360.0); KeyValue scx0 = new KeyValue(scaleX, 1.0); KeyValue scy0 = new KeyValue(scaleY, 1.0); KeyValue scx1 = new KeyValue(scaleX, 1.5); KeyValue scy1 = new KeyValue(scaleY, 1.5); KeyValue shx0 = new KeyValue(shearX, 0.0); KeyValue shx1 = new KeyValue(shearX, 0.5); KeyValue shy0 = new KeyValue(shearY, 0.0); KeyValue shy1 = new KeyValue(shearY, 0.5); KeyValue ttl0 = new KeyValue(titleprop, "Initial rendering"); KeyValue ttlt = new KeyValue(titleprop, "Translation"); KeyValue ttlr = new KeyValue(titleprop, "Rotation"); KeyValue ttlc = new KeyValue(titleprop, "Scaling"); KeyValue ttlh = new KeyValue(titleprop, "Shearing X"); KeyValue ttlv = new KeyValue(titleprop, "Shearing Y"); KeyValue ttlb = new KeyValue(titleprop, "Shearing Both"); Timeline t = new Timeline(); double s = 0.0; t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 0.0), trx0, try0, rot0, scx0, scy0, shx0, shy0, ttl0)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), trx0, try0, ttlt)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 3.0), trx1, try1)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 3.0), trx0, try0)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), rot0, ttlr)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 3.0), rot1)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 3.0), rot0)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), scx0, scy0, ttlc)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 3.0), scx1, scy1)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 3.0), scx0, scy0)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx0, shy0, ttlh)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx1, shy0)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx0, shy0)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx0, shy0, ttlv)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx0, shy1)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx0, shy0)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx0, shy0, ttlb)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx1, shy1)); t.getKeyFrames().add(new KeyFrame(Duration.seconds(s += 1.0), shx0, shy0)); t.setAutoReverse(false); t.setCycleCount(Timeline.INDEFINITE); t.play(); } }