JavaFX TimeLine与Canvas文本动画

时间:2019-03-14 09:14:48

标签: javafx javafx-8

我一直在尝试编写一种有效的“标签”控件,以垂直滚动方式(字幕/行情指示器)呈现文本。 我已经写了2个版本(以我在这里看到的一些模式为基础)来尝试提高性能,但是我希望有人可以指出一种更好的方法,因为这两个都使用大约4-9%的CPU。

PC规格:(Intel i7-7660U @ 2.50GHz)/ 16GB RAM /图形卡:Intel(R)Iris(TM)Plus图形640 / Win10。

虽然这是可以接受的,但那只是我希望我的应用程序执行的所有操作,它们将被用于现有的大型复杂应用程序中,并且在任何其他时间,除了其他详细视图之外,还有30多个可见的内容。< / p>

我尝试的第一个版本使用TimeLine,并且它与我想要的外观最接近。它仍然需要完善,以使文本根据需要显示/消失,但足够接近以进行基准测试。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.CacheHint;
import javafx.scene.Scene;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

public class TickerLabelTester extends Application {



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

    @Override
    public void start(Stage stage) {
        List<String> list1 = new ArrayList<String>(
                Arrays.asList("Name 1",
                        "Name 2"));
        List<String> list2 = new ArrayList<String>(
                Arrays.asList("Name 3",
                        "Name 4"));

        VBox root = new VBox(2.0);
        root.setStyle("-fx-background-color:orange;");
        for (int i = 0; i < 30; i++) {
            TickerLabel tickerLabel = new TickerLabel();
            if (i % 2 == 0) {
                tickerLabel.setStrings(list1);
            } else {
                tickerLabel.setStrings(list2);
            }
            HBox hBox = new HBox(tickerLabel);
            hBox.setBorder(new Border(new BorderStroke(Color.BLACK,
                    BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderWidths.DEFAULT)));
            root.getChildren().add(hBox);
        }
        root.setPrefSize(250, 700);
        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.setTitle("Scrolling Strings");
        stage.show();


    }

    class TickerLabel extends Pane {
        private Timeline timeline;
        private Text text;
        private List<String> strings = new ArrayList<String>();

        public TickerLabel() {
            Rectangle clip = new Rectangle();
            this.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> {
                clip.setWidth(newValue.getWidth());
                clip.setHeight(newValue.getHeight());
            });
            this.setClip(clip);
            text = new Text();
            this.getChildren().add(text);
            text.setCache(true);
            text.setCacheHint(CacheHint.SPEED);
            timeline = new Timeline();
            timeline.setCycleCount(Timeline.INDEFINITE);
        }

        public void setStrings(List<String> strings) {
            this.strings = strings;
            rerunTransition();
        }

        private void rerunTransition() {
            timeline.stop();
            if (strings.size() > 0) {
                recalculateTranslateTransition();
                timeline.playFromStart();
            }
        }

        private void recalculateTranslateTransition() {
            Duration duration = Duration.ZERO;
            double startPos = text.getLayoutBounds().getHeight() + 8;
            for (String string : strings) {
                KeyValue initKeyValue = new KeyValue(text.translateYProperty(), startPos);
                KeyValue initTextKeyValue = new KeyValue(text.textProperty(), string);
                KeyFrame initFrame = new KeyFrame(duration, initKeyValue, initTextKeyValue);
                timeline.getKeyFrames().add(initFrame);
                duration = Duration.seconds(duration.toSeconds() + 2);
                KeyValue endKeyValue = new KeyValue(text.translateYProperty(), 0);
                KeyFrame endFrame = new KeyFrame(duration, endKeyValue);
                timeline.getKeyFrames().add(endFrame);
            }
        }

    }

}

第二个版本使用Canvas和GraphicsContext。我以前没有使用过JavaFX Canvas,但我希望它可以像Swing / AWT一样,可以在其中使用一些屏幕外缓冲来提高性能,但不幸的是,此版本的性能不如TimeLine。在切换到下面显示的AnimationTimer之前,我曾尝试使用自己的Task / Service类来执行渲染,但是性能较差。希望我缺少有关应如何使用GraphicsContext的一些信息?

在实际应用中,字符串列表将不时为每个标签分别更新,因此时间线或AnimationTimer需要选择列表更改。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.CacheHint;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class TickerCanvasLabelTester extends Application {



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

    @Override
    public void start(Stage stage) {

        List<String> list1 = new ArrayList<String>(
                Arrays.asList("Name 1",
                        "Name 2"));
        List<String> list2 = new ArrayList<String>(
                Arrays.asList("Name 3",
                        "Name 4"));

        VBox root = new VBox(2.0);
        root.setStyle("-fx-background-color:orange;");
        for (int i = 0; i < 30; i++) {
            TickerLabel tickerLabel = new TickerLabel();
            if (i % 2 == 0) {
                tickerLabel.setStrings(list1);
            } else {
                tickerLabel.setStrings(list2);
            }
            HBox hBox = new HBox(tickerLabel);
            hBox.setBorder(new Border(new BorderStroke(Color.BLACK,
                    BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderWidths.DEFAULT)));
            root.getChildren().add(hBox);
        }
        root.setPrefSize(250, 700);
        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.setTitle("Scrolling Strings");
        stage.show();


    }

    class TickerLabel extends Pane {
        private List<String> strings = new ArrayList<String>();
        private int stringPointer = 0;
        private Canvas canvas;
        private GraphicsContext gc;
        private AnimationTimer at;
        private String string;

        public TickerLabel() {
            Rectangle clip = new Rectangle();
            this.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> {
                clip.setWidth(newValue.getWidth());
                clip.setHeight(newValue.getHeight());
            });
            this.setClip(clip);
            canvas = new Canvas();
            canvas.setCache(true);
            canvas.setCacheHint(CacheHint.SPEED);
            canvas.setWidth(100);
            canvas.setHeight(20);
            gc = canvas.getGraphicsContext2D();
            string = "";

            at = new AnimationTimer() {
                private long lastUpdate = 0;
                private double i = canvas.getHeight() + 2;

                @Override
                public void handle(long now) {
                    // limit how often this is called
                    if (now - lastUpdate >= 200_000_000) {
                        if (i >= -2) {
                            gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
                            gc.strokeText(string, 0, i);
                            i--;

                        } else {
                            i = canvas.getHeight();
                            selectNextString();
                        }
                        lastUpdate = now;
                    }
                }
            };
            this.getChildren().add(canvas);

        }

        public void setStrings(List<String> strings) {
            this.strings = strings;
            at.stop();
            selectNextString();
            at.start();
        }

        private void selectNextString() {
            if (strings.size() > 0) {
                string = strings.get(stringPointer);
                if (stringPointer >= strings.size() - 1) {
                    stringPointer = 0;
                } else {
                    stringPointer++;
                }
            }
        }
    }

}

在此先感谢您的帮助。

0 个答案:

没有答案