我在javafx中旋转用户控件时遇到问题。我的设置如下:
我在中心有一个名为scrollpane
的400 x 600滚动面板,后来用vbox动态填充,其中包含带文本的标签列表。
我想要做的是在此面板上添加一个旋转,使其看起来像星球大战的介绍文本。我已经设法获得滚动文本的动画,但是当试图在X_AXIS上旋转面板时,它不会按我的意愿执行。
目标:Panel that is rotated as if it was this text
目前My best attempt after spending hours transforming:
scrollpane.getTransforms().add(new Rotate(50, 300, 200, 20, Rotate.X_AXIS));
正如您所看到的那样,文本瞄准了正确的角度,但控件本身实际上并未在X轴上旋转3d。 我需要添加什么才能从目前的状态变为理想的效果? (以绝对像素为单位的面板顶部与底部相比较宽)。
答案 0 :(得分:3)
这对我有用:
import javafx.application.Application;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.text.Font;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class StarWarsScrollPane extends Application {
private final String text = "It is a period of civil war. Rebel spaceships, "
+ "striking from a hidden base, have won their first victory against the evil Galactic Empire."
+ " During the battle, Rebel spies managed to steal secret plans to the Empire's ultimate weapon,"
+ " the DEATH STAR, an armored space station with enough power to destroy an entire planet."
+ " Pursued by the Empire's sinister agents, Princess Leia races home aboard her starship,"
+ " custodian of the stolen plans that can save her people and restore freedom to the galaxy....";
@Override
public void start(Stage primaryStage) {
Label label = new Label(text);
label.setWrapText(true);
label.setFont(Font.font(18));
ScrollPane crawler = new ScrollPane(label);
crawler.setVbarPolicy(ScrollBarPolicy.NEVER);
crawler.setFitToWidth(true);
crawler.getTransforms().add(new Rotate(-50, 300, 200, 20, Rotate.X_AXIS));
Scene scene = new Scene(crawler, 400, 400);
scene.setCamera(new PerspectiveCamera());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
请注意,如果您真的想要滚动“抓取”文本,则实际上并不需要滚动窗格,但您可以使用文本节点并在动画中进行翻译。如果这样做,请务必在添加旋转后添加转换:转换以相反的顺序应用(就好像你正确地乘以仿射变换矩阵一样)。
这是一个例子;)
import java.util.Random;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.DepthTest;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;
public class StarWarsCrawler extends Application {
private final String text = "It is a period of civil war. Rebel spaceships, "
+ "striking from a hidden base, have won their first victory against the evil Galactic Empire.\n\n"
+ "During the battle, Rebel spies managed to steal secret plans to the Empire's ultimate weapon,"
+ " the DEATH STAR, an armored space station with enough power to destroy an entire planet.\n\n"
+ "Pursued by the Empire's sinister agents, Princess Leia races home aboard her starship,"
+ " custodian of the stolen plans that can save her people and restore freedom to the galaxy....";
@Override
public void start(Stage primaryStage) {
Rectangle2D primaryScreenBounds = Screen.getPrimary().getBounds();
int width = (int) primaryScreenBounds.getWidth() ;
int height = (int) primaryScreenBounds.getHeight() ;
Text textNode = createText(width);
Translate translate = new Translate();
textNode.getTransforms().add(new Rotate(-60, 300, height/2, height/30, Rotate.X_AXIS));
textNode.getTransforms().add(translate);
Timeline animation = new Timeline(
new KeyFrame(Duration.seconds(45), new KeyValue(translate.yProperty(), -10*height))
);
textNode.setTranslateY(2*height);
StackPane root = new StackPane();
generateStarField(width, height, root);
root.getChildren().add(textNode);
Scene scene = createScene(root);
primaryStage.setFullScreenExitHint("");
primaryStage.setFullScreen(true);
primaryStage.setScene(scene);
primaryStage.show();
animation.play();
animation.setOnFinished(e -> Platform.exit());
}
private Scene createScene(StackPane root) {
Scene scene = new Scene(root, Color.BLACK);
PerspectiveCamera camera = new PerspectiveCamera();
camera.setDepthTest(DepthTest.ENABLE);
scene.setCamera(camera);
scene.setCursor(Cursor.NONE);
scene.setOnMouseClicked(e -> {
if (e.getClickCount() ==2) {
Platform.exit();
}
});
return scene;
}
private Text createText(int width) {
Text textNode = new Text(text);
textNode.setWrappingWidth(width*1.25);
textNode.setFont(Font.font("Franklin Gothic", width/12));
textNode.setFill(Color.rgb(229, 177, 58));
return textNode;
}
private void generateStarField(int width, int height, StackPane root) {
int numStars = width * height / 900 ;
Random rng = new Random();
for (int i = 1 ; i <= numStars ; i++) {
double hue = rng.nextDouble() * 360 ;
double saturation = rng.nextDouble() * 0.1 ;
Color color = Color.hsb(hue, saturation, 1.0);
Circle circle = new Circle(rng.nextInt(width), rng.nextInt(height), 2*rng.nextDouble(), color);
circle.setManaged(false);
circle.setTranslateZ(rng.nextDouble() * height * 1.25);
root.getChildren().add(circle);
}
}
public static void main(String[] args) {
launch(args);
}
}