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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16992731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:38:21  来源:igfitidea点击:

JavaFX 2: Making a ScrollPane automatically scroll to the edge after adding content

javajavafx-2scrollpane

提问by user1298572

Using JavaFX 2, I have a basic example of a ScrollPanethat contains an HBoxof Labels. I want to be able to add a Labelto the HBox, and simultaneously scroll to the right edge of the ScrollPaneso that the newly added Labelis visible. My current method uses the setHvalue()to set the scroll position and getHmax()to get the maximum scrolling distance allowed.

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

The problem is that when I set the scroll position using getHmax(), it is as if the just-added Labelis not computed in the ScrollPanel's scroll width. Is there a way that I can update this inner width before trying setHvalue?

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

Please see this simple example code which exhibits the issue.

请查看这个简单的示例代码,它展示了这个问题。

In particular, please notice the addChatItem(String item)method, which contains the logic for scrolling to the edge of the ScrollPane.

特别要注意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));
            }
        }
    }

Here is an image of issue, notice how the ScrollPanehas not scrolled to the right edge.

这是问题的图像,请注意ScrollPane尚未滚动到右边缘。

image

图片

Edit:

编辑:

I've come up with a workaround but it is very far from ideal. My solution is to start a timer which will use setHvalue()after enough time has passed for the ScrollPaneto discover the true width of its content. my addChatItem()method now looks like this:

我想出了一个解决方法,但它离理想还很远。我的解决方案是启动一个计时器,该计时器将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);
}

Unfortunately, the number 50 in that method needs to be greater than the time that it takes the ScrollPaneto update its inner content's width, and that seems to be far from guaranteed.

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

回答by invariant

you can bind to Hbox widthproperty chnages .

您可以绑定到 Hbox widthproperty chnages 。

Sample Code :

示例代码:

   //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()); 
        }
    }) ;

and

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

Result :yes added numbering for fun ;)

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

enter image description here

在此处输入图片说明

回答by Pedram Esmaeeli

In my case I needed to enclose a HBox called labels inside a ScrollPane called msgs and here is the way I handled autoscroll.

在我的例子中,我需要在一个名为 msgs 的 ScrollPane 中包含一个名为 labels 的 HBox,这是我处理自动滚动的方式。

NOTE: The changeListener added to labels HBox is implemented via Lambda syntax(available in JDK8)

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

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