JavaFX - 水平选框文本

时间:2014-04-14 14:13:35

标签: java javafx javafx-2 marquee

我正在尝试实现类似于marquee的效果 - 在水平轴上移动的长行(在我的情况下)行。我设法让它工作,但我不能称之为令人满意。

我的Controller课程如下所示:

@FXML
private Text newsFeedText;

(...)
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
    TranslateTransition transition = TranslateTransitionBuilder.create()
            .duration(new Duration(7500))
            .node(newsFeedText)
            .interpolator(Interpolator.LINEAR)
            .cycleCount(Timeline.INDEFINITE)
            .build();   

    GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
    int width = gd.getDisplayMode().getWidth();

    transition.setFromX(width);
    transition.setToX(-width);
    transition.play();
}

newsFeedText被绑定到一些动态更新的文本源,因此它包含不同数量的文本。

我的代码至少有两个缺点:

  • 转换从-width转移到+width; width是显示器的分辨率宽度

如果窗口没有经过全面筛选,有时候根本看不到文字。 如果文字较长且newsFeedText宽度将大于显示器的分辨率宽度,则转换将消失"一半" (仍然在屏幕上)。

  • 目前Duration不依赖于newsFeedText的宽度。

现在,它没有任何意义,但如果动态计算转换fromXtoX,那么它将导致各种速度的选框。

如何摆脱这些弊端?

2 个答案:

答案 0 :(得分:5)

我已将其设置为有效,任何重新计算只有在转换停止后才会发生,因此我们无法将其cycleCount设置为Timeline.INDEFINITE。我的要求是我可以更改组件内的文本,因此有fxml接线:

@FXML
private Text node; // text to marquee

@FXML
private Pane parentPane; // pane on which text is placed

有效的代码是:

transition = TranslateTransitionBuilder.create()
        .duration(new Duration(10))
        .node(node)
        .interpolator(Interpolator.LINEAR)
        .cycleCount(1)
        .build();

transition.setOnFinished(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent actionEvent) {
        rerunAnimation();
    }
});

rerunAnimation();

其中rerunAnimation()是:

private void rerunAnimation() {
    transition.stop();
    // if needed set different text on "node"
    recalculateTransition();
    transition.playFromStart();
}

recalculateTransition()是:

private void recalculateTransition() {
    transition.setToX(node.getBoundsInLocal().getMaxX() * -1 - 100);
    transition.setFromX(parentPane.widthProperty().get() + 100);

    double distance = parentPane.widthProperty().get() + 2 * node.getBoundsInLocal().getMaxX();
    transition.setDuration(new Duration(distance / SPEED_FACTOR));
}

答案 1 :(得分:0)

你应该可以通过聆听你的场景widthProperty来做到这一点。您可以通过newsFeedText.getScene().widthProperty()访问此内容,也可以从主类中获取引用并从中公开,或者将其传递给方法或构造函数,以便在类中声明newsFeedText

这种方法的好处是,现在您的逻辑依赖于场景的宽度(动态依赖性)而不是监视器的宽度(静态依赖性)。请注意,我没有测试过这种方法,但目前看不出任何理由(也许天真地)它不应该起作用。

至于你的持续时间依赖性,你可以通过根据newsFeedText中文本的长度执行某种计算来解决这个问题。像Duration.seconds(newsFeedText.get Text().length()/denominator)这样的地方denominator是您指定的某个值(例如7500,如代码中所示)。这将使您的持续时间根据文本的长度动态计算。

如果您希望使用newsFeedText本身的宽度而不是文本的长度进行操作,则只需将newsFeedText.getText().length()替换为newsFeedText.getWidth()即可。确保在newsFeedText布局后执行此计算,以便调用获取其宽度返回实际宽度。您也可以使用getPrefWidth()getMinWidth()getMaxWidth()中的任意一个替换来电。