Mamy animację obrazka uruchamianą i zatrzymywaną przy użyciu przycisku.
Przycisk znajdujący się się na poziomie animacji – nie da się włączyć. Jest obecny tylko po to, aby pokazać, że nie działa. Aktywny przycisk znajduje się na wyświetlaczu. Tym przyciskiem możemy uruchomić i zatrzymać animację. Wyświetlacz mógłby być całkowicie przezroczysty przy ustawieniu koloru wyświetlacza na Color.TRANSPARENT
albo Color.RGB(0, 0, 0)
Klasa Listing11_17c
package rozdzial11c; import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.beans.property.BooleanProperty; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Bounds; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.SubScene; import javafx.scene.control.ToggleButton; import javafx.scene.effect.DropShadow; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.*; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.util.Duration; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; public class Listing11_17c extends Application { private Timeline timeline; private BufferedInputStream bis; public static void main(String[] args) { Application.launch(args); } @Override public void init() { try { FileInputStream is = new FileInputStream( "rozdzial11c/src/rozdzial11c/kwiatek.jpg"); bis = new BufferedInputStream(is); } catch (FileNotFoundException e) { e.printStackTrace(); } } @Override public void start(Stage stage) { ToggleButton tgglass = new ToggleButton( "Włącz animację"); BooleanProperty selglass = tgglass.selectedProperty(); selglass.addListener((observable, oldValue, newValue) -> { tgglass.setText(newValue ? "Wyłącz animację" : "Włącz animację"); if (tgglass.selectedProperty().get()) { timeline.play(); } else { timeline.stop(); } }); StackPane spane = new StackPane(); spane.setPrefWidth(250); spane.setMaxWidth(250); spane.setMinWidth(250); spane.setPrefHeight(200); spane.setMinHeight(200); spane.setMinHeight(200); BackgroundFill bgf1 = new BackgroundFill( Color.rgb(0, 0, 0, 0.05), CornerRadii.EMPTY, new Insets(0, 0, 0, 0)); Background bg1 = new Background(bgf1); spane.setBackground(bg1); spane.getChildren().add(tgglass); SubScene sub = new SubScene(spane, 250, 200); DropShadow ds = new DropShadow(); sub.setEffect(ds); BorderStroke bs = new BorderStroke( Color.rgb(0, 0, 0, 0.4), BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(0.5), new Insets(0, 0, 0, 0)); spane.setBorder(new Border(bs)); //-------------------------------------- Image image = new Image(bis); ImageView iv = new ImageView(); iv.setImage(image); iv.setFitWidth(256); iv.setFitHeight(192); iv.setSmooth(true); iv.setCache(true); iv.relocate(100, 75); ToggleButton tg = new ToggleButton( "Włącz animację"); BooleanProperty sel = tg.selectedProperty(); sel.addListener((observable, oldValue, newValue) -> { tg.setText(newValue ? "Wyłącz animację" : "Włącz animację"); if (tg.selectedProperty().get()) { timeline.play(); } else { timeline.stop(); } }); BackgroundFill bgf = new BackgroundFill( Color.WHITE, CornerRadii.EMPTY, new Insets(0, 0, 0, 0)); Background bg = new Background(bgf); Pane root = new Pane(); root.setBackground(bg); root.getChildren().addAll(iv, tg, sub); Scene scene = new Scene( root, 500, 400, Color.WHITE); stage.setTitle("Bouncing Image"); stage.setScene(scene); stage.show(); EventHandler<ActionEvent> ev = new EventHandler<>() { double dx = 5; double dy = 3; @Override public void handle(ActionEvent t) { iv.setLayoutX(iv.getLayoutX() + dx); iv.setLayoutY(iv.getLayoutY() + dy); Bounds bounds = root.getBoundsInLocal(); if (iv.getLayoutX() <= (bounds.getMinX()) || iv.getLayoutX() >= (bounds.getMaxX() - iv.getFitWidth())) { dx = -dx; } if (iv.getLayoutY() >= (bounds.getMaxY() - iv.getFitHeight()) || iv.getLayoutY() <= (bounds.getMinY())) { dy = -dy; } } }; timeline = new Timeline( new KeyFrame( Duration.millis(40), ev)); timeline.setCycleCount(Timeline.INDEFINITE); } @Override public void stop() { Animation.Status s = timeline.getStatus(); if (!s.equals(Animation.Status.STOPPED)) { timeline.stop(); } } }
Klasa module-info.java
module rozdzial11c { requires java.desktop; requires javafx.graphics; requires javafx.controls; requires javafx.swing; exports rozdzial11c to javafx.graphics; }
Po uruchomieniu kodu i uruchomieniu animacji zobaczymy poruszający się obrazek, a nad nim nakładkę dla kontrolek:
Nakładka jest przezroczysta dla światła, a nieprzezroczysta dla zdarzeń.