ScrollPane.setVvalue() 不更新 javafx 中的滚动条

ScrollPane.setVvalue() does not update scrollbar in javafx

我有一个程序,我可以在文本字段中插入一些东西,然后在按下回车按钮后,它会在 VBox 中显示为标签。 我的布局如下所示: 一个带有边界窗格的选项卡,底部是一个包含文本字段和按钮的 hbox,顶部是一个包含充满标签的 vbox 的滚动窗格。

这是代码:

        Tab consoleTab = new Tab("Console");
        consoleTab.setClosable(false);
        BorderPane consoleContent = new BorderPane();
        
        TextField commandEntry = new TextField();
        commandEntry.setPromptText("Enter command...");
        Button exe = new Button("Enter");
        HBox input = new HBox(5, commandEntry, exe);
        VBox outputL = new VBox();
        ScrollPane output = new ScrollPane();
        output.setMinHeight(365);
        output.setMaxHeight(365);
        output.setContent(outputL);
        EventHandler<ActionEvent> customEvent = e -> {
            String in = commandEntry.getText();
            if (in.equals("")) return;
            Label inserted = new Label("> "+in);
            inserted.setStyle("-fx-font-weight: bold");
            outputL.getChildren().add(inserted);
            commandEntry.setText("");
            Command cmd = new Command(in, outputL);
            cmd.execute(true);
            output.setVvalue(1); // This does not work
        };
        commandEntry.setOnAction(customEvent);
        exe.setOnAction(customEvent);
        consoleContent.setTop(output);
        consoleContent.setBottom(input);
        consoleContent.setPadding(new Insets(5, 5, 5, 5));
        consoleTab.setContent(consoleContent);

这是 Command.java class:

public class Command {
    private String command;
    private VBox vbox;
    
    public static final String NEW_FILE = "new_file";
    public static final String OPEN_FILE = "open";
    public static final String SAVE_FILE = "save";
    public static final String LIST_FILES = "list";
    public static final String HELP = "help";
    
    public Command(String command, VBox v){
        this.command = command;
        this.vbox = v;
    }
    
    public void execute(boolean layout){
        String[] args = this.command.split(" ");
        String cmd = args[0];
        String outputText = "";
        switch (cmd){
            case NEW_FILE:
                break;
            case OPEN_FILE:
                outputText = "File opened";
                break;
            case SAVE_FILE:
                break;
            case LIST_FILES:
                outputText = "Files listed";
                break;
            case HELP:
                outputText = "Available commands:\nOPEN: open <file-name>\nLIST: list";
                break;
            default:
                outputText = "Command not found, type help to get the list of available commands";
                break;
        }
        if (layout){
            makeLayout(outputText);
        }
    }
    
    private void makeLayout(String outputText){
        this.vbox.getChildren().add(new Label(outputText));
    }
}

问题是当我调用滚动面板的setVvalue(1.0)方法时,并没有在底部设置滚动条。
我曾尝试在 output.setVvalue(1.0) 之前使用 output.setContent(outputL) 但没有任何变化。
感谢您的帮助

在设置滚动值之前生成布局通道。要生成布局通道,请参阅:

  • Get the height of a node in JavaFX (generate a layout pass)

// change the content of the scroll pane
// . . .

// generate a layout pass on the scroll pane.
scrollPane.applyCss();
scrollPane.layout();

// scroll to the bottom of the scroll pane.
scrollPane.setVvalue(scrollPane.getVmax());

为什么这样有效

发生布局传递时,滚动窗格的 vValue 将更改以保持显示当前可见区域而不是新区域。如果您随后将 vValue 设置为最大值,它将从布局传递中计算的值更改为最大值,将窗格滚动到可见内容的底部。

示例代码

这只是演示方法的代码片段,不是可执行的应用程序。

我确实使用原始问题中的示例代码测试了该方法,并且效果很好。

public void start(Stage stage) {
    VBox content = new VBox();
    final ScrollPane scrollPane = new ScrollPane();
    scrollPane.setContent(content);

    Button append = new Button("Append");
    append.setOnAction(e -> appendToScrollPane(scrollPane));
    
    VBox layout = new VBox(scrollPane, append);
    stage.setScene(new Scene(layout));
    stage.show();
}

public void appendToScrollPane(ScrollPane scrollPane) {
    // ... actions which add content to the scroll pane ...

    // generate a layout pass on the scroll pane.
    scrollPane.applyCss();
    scrollPane.layout();

    // scroll to the bottom of the scroll pane.
    scrollPane.setVvalue(scrollPane.getVmax());
}