JavaFX – 水平选框文本
我试图实现类似于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
的宽度。
现在,它没有任何意义,但如果动态计算转换的fromX
和toX
,那么它将导致各种速度的选框。
如何摆脱这些弊端?
我已经设法它工作,任何重新计算只能在转换停止后发生,所以我们不能将其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() { @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)); }
您应该可以通过聆听场景的widthProperty
来做到这widthProperty
。 您可以通过newsFeedText.getScene().widthProperty()
访问它,或从主类中获取引用并从那里公开它或将其传递给方法或构造函数,以在您的类中访问声明newsFeedText
。
这种方法的好处是,现在您的逻辑依赖于场景的宽度(动态依赖性)而不是监视器的宽度(静态依赖性)。 请注意,我没有测试过这种方法,但目前看不出任何理由(也许是天真的)它不应该起作用。
至于你的持续时间依赖性,你可以通过基于newsFeedText
本的长度执行某种计算来解决这个newsFeedText
。 类似于Duration.seconds(newsFeedText.get Text().length()/denominator)
,其中denominator
是您指定的某个值(例如7500,如代码中所示)。 这将使您的持续时间根据文本的长度动态计算。
如果你想使用newsFeedText
本身的宽度而不是文本的长度来操作,那么只需用newsFeedText.getText().length()
替换newsFeedText.getText().length()
newsFeedText.getWidth()
。 确保在设置newsFeedText
后执行此计算,以便调用获取其宽度返回实际宽度。 您还可以使用getPrefWidth()
, getMinWidth()
或getMaxWidth()
任何一个替换调用。