JavaFX ScrollPane setVvalue() not working as intended

左心房为你撑大大i 提交于 2019-12-25 08:29:01

问题


In my application I have a ScrollPane with a VBox that potentially contains anywhere from 0 to 1000 panes at a set height of 90 each. Each pane has related items that could loaded from a button inside that clears the VBox and adds its children along with a 'Return to Results' button that loads the previous list and should return to the same place in the ScrollPane. However, the setVvalue() doesn't appear to be working. The panes and their children are of the same class.

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

The setVvalue() works and changes the ScrollPane back to its old value when printing it out but the ScrollPane itself does not go anywhere and stays at the top. Does it have to do with removing and adding Nodes to the VBox? Why is the ScrollPane not moving when setting its Vvalue?


回答1:


At the time you call scroll.setVvalue(vValue), the scroll pane hasn't performed the layout since its content has changed, and consequently hasn't "remeasured" the size of its content. So the scroll bar "thumb" is being repositioned by interpreting the vvalue in the context of the previous layout. You can fix this with

public void returnToResults() {
    Platform.runLater(() -> {
        vbox.getChildren.clear();
        vbox.getChildren.addAll(results);

        scroll.layout();

        scroll.setVvalue(vValue); 
        returnToResults.setDisable(true);
    });
}

Aside: Are these methods being called from a background thread? Why are their contents wrapped in a Platform.runLater(...)?




回答2:


In my case calling the layout() method didn't work. I also had to call applyCss() to my current scene.

The relevant FXML:

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

I wanted the scrollpane to automatically scroll down if I add a new Label to

messageBox 

So my method to achieve this is the following:

public void addMessage(String message) {
    messageBox.getChildren().add(new Label(message));

    currentScene.applyCss();
    currentScene.layout();

    messageScrollPane.setVvalue(1.0);
}

Hope it helps someone.



来源:https://stackoverflow.com/questions/41534418/javafx-scrollpane-setvvalue-not-working-as-intended

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!