Last active
July 18, 2024 14:51
-
-
Save FDelporte/c69a02c57acc892b4c996a9779d4f830 to your computer and use it in GitHub Desktop.
JavaFX experiment with JBang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///usr/bin/env jbang "$0" "$@" ; exit $? | |
//DEPS org.openjfx:javafx-controls:22.0.2 | |
//DEPS org.openjfx:javafx-graphics:22.0.2:${os.detected.jfxname} | |
import javafx.animation.AnimationTimer; | |
import javafx.animation.KeyFrame; | |
import javafx.animation.Timeline; | |
import javafx.application.Application; | |
import javafx.geometry.Pos; | |
import javafx.scene.control.Label; | |
import javafx.scene.Scene; | |
import javafx.scene.layout.Pane; | |
import javafx.scene.layout.VBox; | |
import javafx.scene.paint.Color; | |
import javafx.scene.shape.Circle; | |
import javafx.stage.Stage; | |
import javafx.util.Duration; | |
import java.util.Random; | |
/** | |
* Execute with a Java runtime with JavaFX included, and JBang: | |
* jbang FxDemo.java | |
* | |
* A demo is available in this movie: | |
* https://www.youtube.com/watch?v=XhDQvkcYJ88 | |
*/ | |
public class FxDemo extends Application { | |
private static int NUMBER_OF_BALLS = 10_000; | |
private Random r = new Random(); | |
private Scene scene; | |
private long lastUpdate = 0; | |
@Override | |
public void start(Stage stage) { | |
var javaVersion = System.getProperty("java.version"); | |
var javaVendor = System.getProperty("java.vendor"); | |
var javaVendorVersion = System.getProperty("java.vm.version"); | |
var javafxVersion = System.getProperty("javafx.version"); | |
VBox holder = new VBox(); | |
holder.setFillWidth(true); | |
holder.setAlignment(Pos.TOP_CENTER); | |
holder.setSpacing(5); | |
holder.getChildren().addAll( | |
new Label("Java: " + javaVersion + ", " + javaVendor + ", " + javaVendorVersion), | |
new Label("JavaFX: " + javafxVersion), | |
getFramerateLabel(), | |
getBouncingBallPane() | |
); | |
scene = new Scene(holder, 400, 700); | |
stage.setTitle("JavaFX Demo"); | |
stage.setScene(scene); | |
stage.show(); | |
} | |
public static void main(String[] args) { | |
launch(); | |
} | |
private Label getFramerateLabel() { | |
Label frameRateLabel = new Label(); | |
AnimationTimer frameRateMeter = new AnimationTimer() { | |
@Override | |
public void handle(long now) { | |
if (lastUpdate > 0) { | |
long nanosElapsed = now - lastUpdate; | |
double frameRate = 1_000_000_000.0 / nanosElapsed; | |
frameRateLabel.setText(String.format("Current frame rate: %.3f", frameRate)); | |
} | |
lastUpdate = now; | |
} | |
}; | |
frameRateMeter.start(); | |
return frameRateLabel; | |
} | |
private Pane getBouncingBallPane() { | |
Pane pane = new Pane(); | |
pane.setPrefWidth(Double.MAX_VALUE); | |
pane.setPrefHeight(Double.MAX_VALUE); | |
pane.setMinHeight(100.0); | |
for (var i = 0; i < NUMBER_OF_BALLS; i++) { | |
pane.getChildren().add(new Ball()); | |
} | |
return pane; | |
} | |
class Ball extends Circle { | |
private double dx = r.nextInt(1, 5); | |
private double dy = r.nextInt(1, 5); | |
private int size = r.nextInt(1, 15); | |
private Color randomColor = Color.color(Math.random(), Math.random(), Math.random()); | |
public Ball() { | |
this.setRadius(size); | |
this.setFill(randomColor); | |
relocate(r.nextInt(380), r.nextInt(620)); | |
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(5), t -> { | |
if (hitRightOrLeftEdge()) { | |
dx *= -1; // Ball hit right or left wall, so reverse direction | |
} | |
if (hitTopOrBottom()) { | |
dy *= -1; // Ball hit top or bottom, so reverse direction | |
} | |
setLayoutX(getLayoutX() + dx); | |
setLayoutY(getLayoutY() + dy); | |
})); | |
timeline.setCycleCount(Timeline.INDEFINITE); | |
timeline.play(); | |
} | |
private boolean hitRightOrLeftEdge() { | |
return (getLayoutX() < (scene.getX() + getRadius())) || | |
(getLayoutX() > (scene.getWidth() - getRadius())); | |
} | |
private boolean hitTopOrBottom() { | |
return (getLayoutY() < (scene.getY() - getRadius())) || | |
(getLayoutY() > (scene.getHeight() - getRadius() - 60)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment