JavaFX ScrollPane setVvalue() 没有按预期工作
JavaFX ScrollPane setVvalue() not working as intended
在我的应用程序中,我有一个带有 VBox 的 ScrollPane,它可能包含 0 到 1000 个窗格,每个窗格的设置高度为 90。每个窗格都有相关的项目,可以从内部的按钮加载,该按钮清除 VBox 并添加其子项以及加载前一个列表的 'Return to Results' 按钮,并且应该 return 到 ScrollPane 中的相同位置。但是,setVvalue() 似乎不起作用。窗格及其子窗格属于相同的 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);
}
}
setVvalue() 工作并在打印时将 ScrollPane 更改回其旧值,但 ScrollPane 本身不会去任何地方并停留在顶部。它与在 VBox 中删除和添加节点有关吗?为什么 ScrollPane 在设置它的 Vvalue 时没有移动?
在您调用 scroll.setVvalue(vValue)
时,滚动窗格没有执行布局,因为它的内容已更改,因此 "remeasured" 其内容的大小没有改变。因此,滚动条 "thumb" 通过在先前布局的上下文中解释 vvalue
来重新定位。你可以用
解决这个问题
public void returnToResults() {
Platform.runLater(() -> {
vbox.getChildren.clear();
vbox.getChildren.addAll(results);
scroll.layout();
scroll.setVvalue(vValue);
returnToResults.setDisable(true);
});
}
旁白:这些方法是从后台线程调用的吗?为什么它们的内容包裹在 Platform.runLater(...)
?
在我的例子中,调用 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);
}
希望对大家有所帮助。
在我的应用程序中,我有一个带有 VBox 的 ScrollPane,它可能包含 0 到 1000 个窗格,每个窗格的设置高度为 90。每个窗格都有相关的项目,可以从内部的按钮加载,该按钮清除 VBox 并添加其子项以及加载前一个列表的 'Return to Results' 按钮,并且应该 return 到 ScrollPane 中的相同位置。但是,setVvalue() 似乎不起作用。窗格及其子窗格属于相同的 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);
}
}
setVvalue() 工作并在打印时将 ScrollPane 更改回其旧值,但 ScrollPane 本身不会去任何地方并停留在顶部。它与在 VBox 中删除和添加节点有关吗?为什么 ScrollPane 在设置它的 Vvalue 时没有移动?
在您调用 scroll.setVvalue(vValue)
时,滚动窗格没有执行布局,因为它的内容已更改,因此 "remeasured" 其内容的大小没有改变。因此,滚动条 "thumb" 通过在先前布局的上下文中解释 vvalue
来重新定位。你可以用
public void returnToResults() {
Platform.runLater(() -> {
vbox.getChildren.clear();
vbox.getChildren.addAll(results);
scroll.layout();
scroll.setVvalue(vValue);
returnToResults.setDisable(true);
});
}
旁白:这些方法是从后台线程调用的吗?为什么它们的内容包裹在 Platform.runLater(...)
?
在我的例子中,调用 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);
}
希望对大家有所帮助。