import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.scene.text.*; import javafx.scene.canvas.*; import javafx.scene.paint.Color; import javafx.animation.AnimationTimer; /** * This program displays 25 copies of a message, and it runs * an animation in which the strings move around on the screen. * The color, position, and velocity of each message is selected * at random when the program first starts, and there is a button that * the user can click to reinitialize all the random values. */ public class RandomStringsWithArray extends Application { public static void main(String[] args) { launch(args); } //---------------------------------------------- private final static String MESSAGE = "Hello JavaFX"; private Font[] fonts; // The five fonts. private Canvas canvas; // The canvas on which the strings are drawn. private StringData[] stringData; // Holds all information needed // to draw the strings. private static class StringData { // Info needed to draw one string. double x,y; // location of the string double dx,dy; // velocity of the string, in pixels per second Color color; // color of the string Font font; // the font that is used to draw the string } public void start( Stage stage ) { fonts= new Font[] { Font.font("Times New Roman", FontWeight.BOLD, 20), Font.font("Arial", FontWeight.BOLD, FontPosture .ITALIC, 28), Font.font("Verdana", 32), Font.font(40), Font.font("Times New Roman", FontWeight.BOLD, FontPosture .ITALIC, 60) }; canvas = new Canvas(500,300); createStringData(); draw(); // draw content of canvas the first time. Button redraw = new Button("Restart!"); redraw.setOnAction( e -> createStringData() ); // When the button is clicked, the string data is re-initialized. // There is no need to call draw() because the animation that // runs continually will redraw the canvas in the next frame. StackPane bottom = new StackPane(redraw); bottom.setStyle("-fx-background-color: gray; -fx-padding:5px;" + " -fx-border-color:black; -fx-border-width: 2px 0 0 0"); BorderPane root = new BorderPane(canvas); root.setBottom(bottom); root.setStyle("-fx-border-color:black; -fx-border-width: 2px"); stage.setScene( new Scene(root, Color.BLACK) ); stage.setTitle("Random Strings"); stage.setResizable(false); stage.show(); AnimationTimer timer = new AnimationTimer() { // The timer will run continually. In each frame, all the strings // will be moved, and the canvas will be redrawn. long previousTime; public void handle(long time) { if (previousTime > 0) { // Time since previous call to handle is (time - previousTime), // in nanoseconds. Dividing by 1e9 converts nanoseconds to seconds. // The first time handle() is called, previousTime is 0 and the // update is not done. updateStringData( (time - previousTime)/1e9 ); } draw(); previousTime = time; } }; timer.start(); } /** * Creates an array of 25 StringData objects and fills it with * randomly generated data for each of the 25 strings. This is * called in the start() method and when the user clicks the * "Restart!" button. */ private void createStringData() { stringData = new StringData[25]; for (int i = 0; i < 25; i++) { stringData[i] = new StringData(); stringData[i].x = canvas.getWidth() * Math.random(); stringData[i].y = canvas.getHeight() * Math.random(); stringData[i].dx = 50 + 150*Math.random(); // 50 to 200 pixels per second if (Math.random() < 0.5) // 50% chance that dx is negative stringData[i].dx = -stringData[i].dx; stringData[i].dy = 50 + 150*Math.random(); if (Math.random() < 0.5) // 50% chance that dy is negative stringData[i].dy = -stringData[i].dy; stringData[i].color = Color.hsb( 360*Math.random(), 1.0, 1.0 ); stringData[i].font = fonts[ (int)(5*Math.random()) ]; } } /** * Update the data for the 25 strings by moving each string, where the * distance moved depends on the velocity. If a string moves too far * off the canvas, move it to the opposite side of the canvas. * (To make sure a string has moved all the way off the canvas to the * left, wait until data.x reaches -400 before moving it to the * right of the canvas. * @param deltaTimeInSeconds time that has elapsed since the previous * call to updateStringData, measured in seconds. */ private void updateStringData(double deltaTimeInSeconds) { for ( StringData data : stringData ) { data.x += data.dx * deltaTimeInSeconds; data.y += data.dy * deltaTimeInSeconds; if (data.x < -400) data.x = canvas.getWidth(); if (data.x > canvas.getWidth()+10) data.x = -400; if (data.y < -10) data.y = canvas.getHeight() + 70; if (data.y > canvas.getHeight() + 80) data.y = -10; } } /** * The draw() method is responsible for drawing the content of the canvas. * It draws 25 copies of the message string, using a random color, font, and * position for each string. */ private void draw() { GraphicsContext g = canvas.getGraphicsContext2D(); double width = canvas.getWidth(); double height = canvas.getHeight(); g.setFill( Color.WHITE ); // fill with white background g.fillRect(0, 0, width, height); for ( StringData data : stringData ) { // Draw one string, using the properties in one of the // StringData objects from the array. g.setFill( data.color ); g.setFont( data.font); g.fillText(MESSAGE, data.x, data.y); g.setStroke(Color.BLACK); g.strokeText(MESSAGE, data.x, data.y); } // end for } // end draw() } // end class RandomStringsWithArray