【问题标题】:JavaFX ScrollPane setVvalue() not working as intendedJavaFX ScrollPane setVvalue() 未按预期工作
【发布时间】:2017-01-08 15:36:59
【问题描述】:

在我的应用程序中,我有一个带有 VBox 的 ScrollPane,它可能包含 0 到 1000 个窗格,每个窗格的设置高度为 90。每个窗格都有相关的项目,可以从内部的按钮加载,该按钮清除 VBox 并添加其子项以及“返回结果”按钮,该按钮加载前一个列表并应返回到 ScrollPane 中的同一位置。但是, setVvalue() 似乎没有工作。窗格及其子级属于同一类。

package application;

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;


public class Main extends Application {

    public VBox resultsBox;
    public ScrollPane scroll;
    public List<CustomClass> results = new ArrayList<CustomClass>();
    public Button returnToResults;

    public class CustomClass extends HBox {
        public List<CustomClass> items;

        public boolean hasItems() {
            return items != null && !items.isEmpty();
        }

        public CustomClass(String text, boolean hasItems) {
            setMinHeight(90);
            setPrefHeight(90);
            setMaxHeight(90);
            setMaxWidth(Double.MAX_VALUE);
            setAlignment(Pos.CENTER);
            setStyle("-fx-border-color: red");

            Button children = new Button("View Children "+text);
            children.setDisable(!hasItems);
            getChildren().add(children);
            children.setOnAction(e -> {
                viewChildren(this);
            });

            if(hasItems) {
                items = new ArrayList<CustomClass>();
                for(int i=0; i<10; i++) {
                    items.add(new CustomClass(text+"."+i, false));
                }
            }
        }
    }

    public double vValue = 0.0;

    public void viewChildren(CustomClass cc) {
        Platform.runLater(() -> {
            vValue = scroll.getVvalue();
            System.out.println("0. "+vValue);
            resultsBox.getChildren().clear();
            resultsBox.getChildren().addAll(cc.items);
            returnToResults.setDisable(false);
        });
    }

    public void returnToResults() {
        Platform.runLater(() -> {
            resultsBox.getChildren().clear();
            resultsBox.getChildren().addAll(results);
            System.out.println("1. "+vValue+"    "+scroll.getVvalue());
            scroll.setVvalue(vValue);
            System.out.println("2. "+vValue+" -> "+scroll.getVvalue()); // Sets correctly.
            returnToResults.setDisable(true);
        });
    }

    public void start(Stage stage) throws Exception {

        resultsBox = new VBox(5);
        resultsBox.setFillWidth(true);
        resultsBox.setAlignment(Pos.TOP_CENTER);

        scroll = new ScrollPane(resultsBox);
        scroll.setMaxWidth(Double.MAX_VALUE);
        scroll.setFitToWidth(true);

        for(int i=0; i<100; i++) {
            results.add(new CustomClass("#"+i, true));
        }

        resultsBox.getChildren().addAll(results);

        returnToResults = new Button("Return to Results");
        returnToResults.setStyle("-fx-base: green");
        returnToResults.setDisable(true);
        returnToResults.setOnAction(e -> {
            returnToResults();
        });

        BorderPane root = new BorderPane();
        root.setCenter(scroll);
        root.setBottom(returnToResults);

        Scene scene = new Scene(root,400,400);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

setVvalue() 工作并将 ScrollPane 打印出来时将其更改回其旧值,但 ScrollPane 本身不会去任何地方并停留在顶部。它与删除和添加节点到 VBox 有关系吗?为什么设置 Vvalue 时 ScrollPane 不动?

【问题讨论】:

    标签: java javafx scrollpane


    【解决方案1】:

    就我而言,调用layout() 方法不起作用。 我还必须给我当前的场景打电话 applyCss()

    相关的 FXML:

    <ScrollPane fx:id="messageScrollPane" fitToWidth="true" fitToHeight="true">
        VBox fx:id="messageBox"/>
    </ScrollPane>
    

    如果我向其中添加新标签,我希望滚动窗格自动向下滚动

    messageBox 
    

    所以我的实现方法如下:

    public void addMessage(String message) {
        messageBox.getChildren().add(new Label(message));
    
        currentScene.applyCss();
        currentScene.layout();
    
        messageScrollPane.setVvalue(1.0);
    }
    

    希望对某人有所帮助。

    【讨论】:

    • @derfect 太棒了:)
    【解决方案2】:

    在您调用scroll.setVvalue(vValue) 时,滚动窗格尚未执行布局,因为其内容已更改,因此尚未“重新测量”其内容的大小。因此,滚动条“拇指”正在通过在先前布局的上下文中解释 vvalue 来重新定位。你可以解决这个问题

    public void returnToResults() {
        Platform.runLater(() -> {
            vbox.getChildren.clear();
            vbox.getChildren.addAll(results);
    
            scroll.layout();
    
            scroll.setVvalue(vValue); 
            returnToResults.setDisable(true);
        });
    }
    

    旁白:这些方法是从后台线程调用的吗?为什么它们的内容被包裹在 Platform.runLater(...) 中?

    【讨论】:

    • 我添加了一个示例来复制问题,但这解决了问题!谢谢。好吧,我以为我需要它,但我删除了 Platform.runLater 并没有挂起,所以我删除了它们。在习惯了 Swing 这么久之后,对 JavaFX 还算陌生。
    • @Matthew 它对你做事的顺序非常敏感。最好有不同的VBoxes,每个都包裹在自己的滚动窗格中,并完全替换滚动窗格,而不是尝试自己操作 vbox 的内容并管理滚动位置。
    • 我发帖后其实也想过这样做,以后得试试看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 2022-01-24
    • 2015-05-11
    • 2020-05-15
    相关资源
    最近更新 更多