JavaFX 2:在添加内容后使ScrollPane自动滚动到边缘

使用JavaFX 2,我有一个包含LabelHBoxScrollPane的基本示例。 我希望能够将Label添加到HBox ,同时滚动到ScrollPane的右边缘,以便可以看到新添加的Label 。 我当前的方法使用setHvalue()来设置滚动位置,使用getHmax()来获得允许的最大滚动距离。

问题是当我使用getHmax()设置滚动位置时,就好像在ScrollPanel的滚动宽度中没有计算刚刚添加的Label 。 有没有办法在尝试setHvalue之前更新这个内部宽度?

请参阅这个展示问题的简单示例代码。

特别是,请注意addChatItem(String item)方法,该方法包含滚动到ScrollPane边缘的逻辑。

  import java.util.Timer; import java.util.TimerTask; import javafx.application.Application; import javafx.application.Platform; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.text.Font; import javafx.stage.Stage; public class ScrollPaneTest extends Application { static int defaultFontSize = 30; ScrollPaneTest scrollPaneTest = this; ScrollPane chatBoxScrollPane = new ScrollPane(); HBox chatBox = new HBox(); Chatter chatter = new Chatter(); public static void main(String[] args) { launch(args);//default } @Override public void stop() throws Exception { super.stop(); System.exit(0); } @Override public void start(Stage primaryStage) { BorderPane borderPane = new BorderPane(); StackPane chatBoxStackPane = new StackPane(); chatBoxScrollPane.setContent(chatBox); //chatBoxScrollPane.setHbarPolicy(ScrollBarPolicy.NEVER); chatBoxScrollPane.setMaxHeight(50); chatBoxStackPane.getChildren().add(chatBoxScrollPane); borderPane.setCenter(chatBoxStackPane); Scene scene = new Scene(borderPane, 800, 600); primaryStage.setScene(scene); primaryStage.setTitle("Scroll Demo"); primaryStage.show(); new Thread("mainGameControlThread") { public void run() { chatter.chatLoop(scrollPaneTest); } }.start(); } public void addChatItem(String chatString) { Label title = new Label(chatString); title.setFont(new Font("Verdana", defaultFontSize)); chatBox.getChildren().add(title); chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax()); } class Chatter { public void chatLoop(final ScrollPaneTest test) { Timer closingCeremonyTimer = new Timer(); closingCeremonyTimer.schedule(new TimerTask() { public void run() { Platform.runLater(new Runnable() { @Override public void run() { test.addChatItem("Hello World. "); } }); chatLoop(test); } }, (long) (0.5*1000)); } } } 

这是一个问题的图像,注意ScrollPane没有滚动到右边缘。

图片

编辑:

我想出了一个解决方法,但它远非理想。 我的解决方案是启动一个计时器,在经过足够的时间让ScrollPane发现其内容的真实宽度后,将使用setHvalue() 。 我的addChatItem()方法现在看起来像这样:

 public void addChatItem(String chatString) { Label title = new Label(chatString); title.setFont(new Font("Verdana", defaultFontSize)); chatBox.getChildren().add(title); Timer closingCeremonyTimer = new Timer(); closingCeremonyTimer.schedule(new TimerTask() { public void run() { chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax()); } }, (long) 50); } 

不幸的是,该方法中的数字50需要大于ScrollPane更新其内部内容宽度所需的时间,这似乎远非保证。

你可以绑定到Hbox widthproperty chnages。

示例代码:

  //in start method add this code DoubleProperty wProperty = new SimpleDoubleProperty(); wProperty.bind(chatBox.widthProperty()); // bind to Hbox width chnages wProperty.addListener(new ChangeListener() { @Override public void changed(ObservableValue ov, Object t, Object t1) { //when ever Hbox width chnages set ScrollPane Hvalue chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax()); } }) ; 

  // remove below line from your addChatItem() method chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax()); 

结果:是添加编号以获得乐趣;)

在此处输入图像描述

在我的情况下,我需要在名为msgs的ScrollPane中包含一个名为标签的HBox,这是我处理autoscroll的方式。

注意:添加到标签HBox的changeListener是通过Lambda语法实现的(在JDK8中可用)

 labels.heightProperty().addListener((observable, oldVal, newVal) ->{ msgs.setVvalue(((Double) newVal).doubleValue()); });