I realize that I can't be the first person who desires to keep the content of a ScrollPane within the borders of the ScrollPanes viewport, yet after several hours of searching, I cannot find an answer to my question.
I've scoured Google, you.com and duckduckgo with various search terms such as
- JavaFX ScrollPane viewport restrict contents to inside borders
- JavaFX ScrollPane viewport keep contents inside viewport borders
And other variations of the wording, and I have not found an answer.
I have created basic reproducible code that accurately models the data I am presenting in my actual program. It's actually quite simple:
- I have multiple VBoxes, each with three labels and a Separator.
- Each VBox gets added to a parent VBox.
- That parent VBox gets added to a ScrollPane.
- ScrollPane has its scroll bars removed with some light styling.
The problem: When scrolling, the contents of the ScrollPane overlap the borders of the ScrollPanes viewport, and I cannot figure out how to tell the ScrollPane to keep the contents of the viewport within its borders.
If there is another way of doing this so that the scrollable contents stay within the borders of the viewport, I do not know of it and would appreciate any guidance towards that end.
My assumption is that the actual border of the viewport is something that can obviously be defined as to its width and color etc. but that it happens to be "painted" within the same space as the actual contents of the viewport. So that it should not be assumed that the border is any kind of an expected boundary by which the contents would then be bound... and if that is true, I accept that of course, but that doesn't help me achieve the behavior I'm after, which is to make sure that the contents do not show over the viewports borders.
Here, you can see what I'm talking about
Here is the code that will show the behavior:
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Separator;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import java.util.Random;
public class Main extends Application {
@Override public void start(Stage stage) throws Exception {
random = new Random(System.currentTimeMillis());
makeScrollPane();
Scene scene = new Scene(scrollPane);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.centerOnScreen();
stage.setWidth(width);
stage.setHeight(height);
stage.show();
}
private Random random;
private final double width = 300;
private final double height = 500;
private ScrollPane scrollPane;
private final String scrollStyle = Main.class.getResource("scrollpane.css").toExternalForm();
private final String labelStyle = Main.class.getResource("label.css").toExternalForm();
private void makeScrollPane() {
VBox[] contentArray = new VBox[15];
for (int x = 0; x < 15; x++) {
String boxIndex = String.valueOf(random());
String boxNum = String.valueOf(random());
String lbl1 = "Title " + boxIndex;
String lbl2 = "Item " + boxIndex;
contentArray[x] = getVBox(lbl1, lbl2, boxNum);
}
VBox vBoxContent = new VBox(contentArray);
scrollPane = new ScrollPane(vBoxContent);
scrollPane.fitToWidthProperty().set(true);
scrollPane.fitToHeightProperty().set(true);
scrollPane.getStylesheets().add(scrollStyle);
scrollPane.hbarPolicyProperty().set(ScrollPane.ScrollBarPolicy.NEVER);
scrollPane.vbarPolicyProperty().set(ScrollPane.ScrollBarPolicy.NEVER);
}
private VBox getVBox(String label1, String label2, String label3) {
Label lbl1 = newLabel(label1);
Label lbl2 = newLabel(label2);
Label lbl3 = newLabel(label3);
lbl3.setId("big");
Separator separator = new Separator();
separator.setMaxWidth(250);
separator.setHalignment(HPos.CENTER);
separator.setPadding(new Insets(0, 0, 25, 0));
VBox vBox = new VBox(20, lbl1, lbl2, lbl3, separator);
vBox.setPrefWidth(width * .9);
vBox.setPrefHeight(100);
vBox.setAlignment(Pos.CENTER);
return vBox;
}
private int random() {
return random.nextInt(1000, 9999);
}
private Label newLabel(String content) {
Label label = new Label(content);
label.getStylesheets().add(labelStyle);
label.setPrefWidth(width * .9);
label.setPrefHeight(25);
label.setAlignment(Pos.CENTER);
return label;
}
};
And the two stylesheets to go with it:
label.css
.label {
-fx-font-size: 13pt;
-fx-background-color: transparent;
-fx-font-family: "Arial";
-fx-text-fill: ghostwhite;
}
#big {
-fx-font-size: 40;
-fx-text-fill: yellow;
}
scrollpane.css
.scroll-pane .viewport {
-fx-background-color: black;
-fx-border-color: darkorange;
-fx-border-width: .7em;
}
.root {
-fx-background-color: black;
}
I appreciate any guidance in finding a way to accomplish what I'm after here.
Thank you