will
will

Reputation: 5061

How can we make text auto scroll continuious loop?

I'm looking for a method to make some lines of text auto-scroll continuous loop with JavaFX. This is very similar to the credits-like scrolling in these questions below. It is a workstation screen, not a mobile. The text is kind of fixed, not from a feed, so I want it to circulate...

A simple use case: you have 30 lines of text, but only 12 lines can be visible at any time. So I want to scroll the text up the screen with a bit of a break a the bottom, then the text wraps around and keeps scrolling.

I thought I could just add text at the bottom and take it away from the top, it turns out to not be the same. The visual effect of using a scrolling up... Is literally the important part of the specification. So I'm back to the beginning.

Some things I would prefer is to not need to destroy the text or re-load. Prefer to point to the current top-of-textbox or something so it wraps around. Otherwise it is like before, and I need to remove text from top and put text in at the bottom. Need JavaFX, can't use Javascript for app. What's your best shot? Thanks in advance.

Upvotes: 1

Views: 4085

Answers (2)

brian
brian

Reputation: 10969

Here's some scrolling text

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Scroll extends Application {

    @Override
    public void start(Stage primaryStage) {
        VBox vbox = new VBox();
        for (int i = 0; i < 30; i++)
            vbox.getChildren().add(new Text("line " + i));
        //add a copy of the first 12 lines that will be showing as wrapped
        for (int i = 0; i < 12; i++)
            vbox.getChildren().add(new Text("line " + i));

        ScrollPane sp = new ScrollPane(vbox);
        Scene scene = new Scene(sp, 300, 10*12);//guess height

        primaryStage.setScene(scene);
        primaryStage.show();
        //resize to exactly 12 lines
        double textHeight = vbox.getHeight() / vbox.getChildren().size();
        primaryStage.setHeight(textHeight*12+primaryStage.getHeight()-scene.getHeight());

        Timeline timeline = new Timeline();
        timeline.setCycleCount(Timeline.INDEFINITE);
        KeyValue kv = new KeyValue(sp.vvalueProperty(), sp.getVmax());
        KeyFrame kf = new KeyFrame(Duration.millis(5000), kv);
        timeline.getKeyFrames().addAll(kf);
        timeline.play();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

I realized it's not what you want. I tried some tricks to take an image of the vbox and play it over and over but there is some stuttering unless you get it just right. This is only to satisfy the requirement of only reading the text once. What you need is a circular structure that scrolls smoothly, like a cylinder. See my other answer for some fun.

Upvotes: 2

brian
brian

Reputation: 10969

Ok, I think I got all the requirements lol.

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Scroll extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        //a vbox to take a picture of
        VBox vbox = new VBox();
        for (int i = 0; i < 30; i++)
            vbox.getChildren().add(new Text(" longer line of text " + i + " "));

        //take a sideways picture to fit the cylinder
        SnapshotParameters snapshotParameters = new SnapshotParameters();
        snapshotParameters.setTransform(new Rotate(90));
        WritableImage snapshot = vbox.snapshot(snapshotParameters, null);

        //make sideways cyl with image
        PhongMaterial material = new PhongMaterial();
        final Cylinder cylinder = new Cylinder(500, snapshot.getWidth(),30);
        material.setDiffuseMap(snapshot);
        cylinder.setMaterial(material);
        cylinder.setRotate(-90);
        cylinder.setTranslateX(snapshot.getWidth());
        cylinder.setTranslateY(500);

        //lights camera show
        final Group root = new Group();
        root.getChildren().add(cylinder);

        final Scene scene = new Scene(root, snapshot.getWidth()*2, cylinder.getRadius()*2, true);
        PointLight pointLight = new PointLight(Color.ALICEBLUE);
        pointLight.setTranslateX(150);
        pointLight.setTranslateY(500);
        pointLight.setTranslateZ(-1000);
        PerspectiveCamera cam = new PerspectiveCamera(false);
        scene.setCamera(cam);
        root.getChildren().addAll(pointLight, cam);

        primaryStage.setScene(scene);
        primaryStage.show();

        //I'll spin bob 
        Rotate rx = new Rotate();
        rx.setAxis(Rotate.Y_AXIS);
        cylinder.getTransforms().add(rx);
        cam.setRotationAxis(Point3D.ZERO);
        Timeline timeline = new Timeline();
        timeline.setCycleCount(Timeline.INDEFINITE);
        final KeyValue kv = new KeyValue(rx.angleProperty(), -360);
        final KeyFrame kf = new KeyFrame(Duration.millis(10000), kv);
        timeline.getKeyFrames().add(kf);
        timeline.play();
    }
}

enter image description here

Upvotes: 1

Related Questions