【问题标题】:In JavaFX, How can I keep the contents of a ScrollPane inside the borders of the viewport?在 JavaFX 中,如何将 ScrollPane 的内容保留在视口的边界内?
【发布时间】:2022-11-19 20:52:48
【问题描述】:

我意识到我不可能是第一个希望将 ScrollPane 的内容保留在 ScrollPanes 视口边界内的人,但经过几个小时的搜索,我找不到问题的答案。

我用各种搜索词搜索了 Google、you.com 和 duckduckgo,例如

  • JavaFX ScrollPane 视口将内容限制在内部边框
  • JavaFX ScrollPane 视口将内容保留在视口边框内

和其他变体的措辞,我还没有找到答案。

我已经创建了基本的可重现代码,可以准确地模拟我在实际程序中呈现的数据。其实很简单:

  • 我有多个 VBox,每个都有三个标签和一个分隔符。
  • 每个 VBox 都添加到父 VBox。
  • 父 VBox 被添加到 ScrollPane。
  • ScrollPane 的滚动条已删除,并带有一些轻型样式。

问题:滚动时,ScrollPane 的内容与 ScrollPanes 视口的边界重叠,我无法弄清楚如何告诉 ScrollPane 将视口的内容保持在其边界内。

如果有另一种方法可以使可滚动内容保持在视口的边界内,我不知道它,并希望为此提供任何指导。

我的假设是视口的实际边界显然可以定义为它的宽度和颜色等,但它恰好是在与视口的实际内容相同的空间内“绘制”的。所以不应该假设边界是任何类型的预期边界,然后内容将被绑定......如果这是真的,我当然接受,但这并不能帮助我实现行为我在后面,这是为了确保内容不会显示在视口边界上。

在这里,你可以看到我在说什么

这是将显示行为的代码:

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

以及与之配套的两个样式表:

标签.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;
}

滚动面板.css

.scroll-pane .viewport {
    -fx-background-color: black;
    -fx-border-color: darkorange;
    -fx-border-width: .7em;
}

.root {
    -fx-background-color: black;
}

我感谢任何指导,以找到一种方法来完成我在这里所追求的目标。

谢谢

【问题讨论】:

  • 有趣的。视口似乎不考虑填充,这将是我在这里的第一种方法。将边框放在滚动窗格本身上并在视口中使用黑色背景的解决方案是否可用?我认为这适用于您提供的演示应用程序。
  • 对我来说看起来像是一个错误:视口被指定为 ScrollPane 的子结构,因此应该是完全可样式化的,并且皮肤应该尊重这些样式。在这种情况下,设计 scrollPane 本身的样式(如@James_D 所建议的那样)似乎可行。
  • @James_D - 我还尝试在滚动窗格中填充 VBox,但我相信你已经意识到,填充只会尊重 VBox 的边缘,顶部和底部将在视口边界之外。我更改了 stylesheet.css 以仅将边框应用于滚动窗格本身,这确实可以正常工作。想知道这是否应该作为错误报告提交?

标签: javafx scrollpane


【解决方案1】:

在这种情况下,我认为技术上的解决方案是仅使用边框设置 ScrollPane 本身的样式,并按照 James_D 的建议将视口保留为黑色背景。

简单地改变 scrollpane.css 就可以了:

.scroll-pane {
    -fx-background-color: black;
    -fx-border-color: darkorange;
    -fx-border-width: .7em;
}

.scroll-pane .viewport {
    -fx-background-color: black;
}

.root {
    -fx-background-color: black;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    相关资源
    最近更新 更多