Reputation: 5061
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
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
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();
}
}
Upvotes: 1