JavaFX z Arią - powrót do strony głównej
Przykładem wyświetlacza przeziernego może być wyświetlanie informacji GPS na przedniej szybie samochodu. Kierowca widzi te informacje bez zmian położenia głowy i rozpraszania uwagi. Wyświetlacz może zajmować całą powierzchnię i może być całkowicie przezroczysty – czyli być niewidoczny dopóki nie pojawi się informacja. Ewentualne kontrolki pod wyświetlaczem są klikalne. Samego wyświetlacza, ani niczego na nim nie da się kliknąć – wyświetlacz jest transparentny dla myszy.

Klasa Listing11c_19c.java
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.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Listing11_19c 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) {
        Font font = Font.font(30);
        Text text = new Text(
                "Mouse transparent\nheads-up display");
        text.setFont(font);
        text.setFill(Color.BLUE);
        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(text);
        SubScene sub = new SubScene(spane, 250, 200);
        sub.setMouseTransparent(true);
        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) {
                double x = iv.getLayoutX() + dx;
                iv.setLayoutX(x);
                double y = iv.getLayoutY()+ dy;
                iv.setLayoutY(y);
                text.setText("x:" + x +  "\ny:"+ y );
                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 zobaczymy, że wysietlacz wyświetla informacje o aktualnym położeniu obrazka.

Wyświetlacz przezierny
Wyświetlacz przezierny