Skip to content

Instantly share code, notes, and snippets.

@FDelporte
Last active July 18, 2024 14:51
Show Gist options
  • Save FDelporte/c69a02c57acc892b4c996a9779d4f830 to your computer and use it in GitHub Desktop.
Save FDelporte/c69a02c57acc892b4c996a9779d4f830 to your computer and use it in GitHub Desktop.
JavaFX experiment with JBang
///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