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

4
使用JavaFX 2,我有一个基本的示例,其中包含一个HBox标签和标签的ScrollPane。我想能够向HBox添加一个Label,并同时滚动到ScrollPane的右侧边缘,以便新添加的Label可见。我当前的方法使用setHvalue()设置滚动位置和getHmax()获取允许的最大滚动距离。
问题是,当我使用getHmax()设置滚动位置时,好像刚刚添加的Label没有计算在ScrollPanel的滚动宽度中。是否有一种方法可以在尝试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没有滚动到右边缘。 image 编辑: 我想出了一个解决方法,但离理想状态还有很远的距离。我的解决方案是启动一个计时器,在足够的时间后使用setHvalue(),以便ScrollPane发现其内容的真实宽度。现在我的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更新其内部内容宽度所需的时间,而这似乎并不保证。

2个回答

4
你可以绑定到HBox的宽度属性变化。 示例代码:
   //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());

结果:是的,为了好玩添加了编号;)

输入图像描述


1
在我的情况下,我需要将名为labels的HBox包含在名为msgs的ScrollPane中,并且这是我处理自动滚动的方式。
注意:添加到标签HBox的changeListener是通过Lambda语法实现的(在JDK8中可用)。
labels.heightProperty().addListener((observable, oldVal, newVal) ->{
        msgs.setVvalue(((Double) newVal).doubleValue());
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接