Javafx 儿童溢出 FlowPane

Javafx children overflowing FlowPane

我正在重做 project i did with processing,因为我想在 JavaFX 中进行一些练习,因为明年我将在 uni 中需要它,这将使我在 ui 方面比 ui 更自由加工确实如此。这意味着我刚开始使用 javafx,抱歉。

我正在尝试在我的主 window 中放置一个容器来容纳一些窗格。在这些窗格上,我稍后会单独使用。我选择了 FlowPane,较小的窗格只是,嗯,窗格。我希望如果 window 的大小发生变化,则会创建(删除)更多窗格,并且容器上始终可以看到完美数量的窗格(这有点难以解释,但请看一下在下面链接的图片中,您会明白的)。这在 99% 的时间里都能正常工作,但有时窗格会溢出流程窗格。我尝试了很多来解决这个问题(几乎是蛮力解决的,哈哈),但我找不到比这更好的了。

不良行为

期望的行为

Github项目的如果你想自己尝试

控制器代码:

public class MainWindowController {

    private int sizeOfOneGame = 100; //In pixel

    //Space between the frame of the Pane that holds all games and the games
    private int[] paddingAroundGames = {30, 30, 30, 30}; //Top, Right, Bottom, Left

    //Space between two games
    private int[] gapBetweenGames = {10, 10}; //X, Y

    @FXML
    FlowPane flowPaneGames;

    public void initialize(){

        //Sets space between two games in the flowPane
        flowPaneGames.setHgap(gapBetweenGames[0]);
        flowPaneGames.setVgap(gapBetweenGames[1]);

        //Sets space between all games and the border of the flowPane
        flowPaneGames.setPadding(new Insets(paddingAroundGames[0], paddingAroundGames[1], paddingAroundGames[2], paddingAroundGames[3]));

        //Draws one frame around the flowPane
        flowPaneGames.setStyle("-fx-border-color: black");

        //Aligns the panes to the center
        flowPaneGames.setAlignment(Pos.BASELINE_CENTER);

        //Adds listeners to the width and height of the flowPane holding the games -> Adjusts shown Panes on size change
        flowPaneGames.widthProperty().addListener(e -> flowPaneGamesSizeChanged());
        flowPaneGames.heightProperty().addListener(e -> flowPaneGamesSizeChanged());

    }

    private void flowPaneGamesSizeChanged(){

        //TODO: Sometimes some panes are bigger than the flowPane

        //Available space for games x and y
        int totalSpaceX = (int) (flowPaneGames.getWidth() - paddingAroundGames[1] - paddingAroundGames[3] + gapBetweenGames[0]);
        int totalSpaceY = (int) (flowPaneGames.getHeight() - paddingAroundGames[0] - paddingAroundGames[2] + gapBetweenGames[1]);

        int totatlSizeOfOneGameX = sizeOfOneGame + gapBetweenGames[0];
        int totatlSizeOfOneGameY = sizeOfOneGame + gapBetweenGames[1];

        int totalSpaceForGamesX = (int) (((double) totalSpaceX) / ((double) totatlSizeOfOneGameX));
        int totalSpaceForGamesY = (int) (((double) totalSpaceY) / ((double) totatlSizeOfOneGameY));

        //Total amount of games
        int totalSpaceForGames = totalSpaceForGamesX * totalSpaceForGamesY;

        System.out.println("Width: " + flowPaneGames.getWidth());
        System.out.println("Height: " + flowPaneGames.getHeight());

        //We have more games shown that there should be we remove the last ones
        while (flowPaneGames.getChildren().size() > totalSpaceForGames) {

            //We remove the last game
            flowPaneGames.getChildren().remove(flowPaneGames.getChildren().size() - 1);
        }

        //While we have less games shown that there should be we add new ones
        while (flowPaneGames.getChildren().size() < totalSpaceForGames) {

            flowPaneGames.getChildren().add(generateNewPane());

        }
    }

    private Pane generateNewPane(){

        //Generates a new pane and returns it
        Pane pane = new Pane();
        pane.setPrefSize(sizeOfOneGame, sizeOfOneGame);
        pane.setStyle("-fx-border-color: black");

        return pane;
    }
}

如果有人能帮我解决这个问题,我会很高兴(即使它只在少数情况下发生)它真的很困扰我。

旁注:我已经在这里问过这个问题,但我几乎没有努力解决这个问题,结果几乎没有任何答案,这次我试着做得更好。人们还抱怨我没有真正遵循 java 的命名约定,我试着听听并希望代码现在更好读。

问题的原因是没有考虑到容器的边框宽度。考虑到容器的边框宽度,totalSpaceXtotalSpaceY 必须确定如下:

int totalSpaceX = (int) (flowPaneGames.getWidth() - paddingAroundGames[1] - paddingAroundGames[3] + gapBetweenGames[0] - flowPaneGames.getBorder().getStrokes().get(0).getWidths().getLeft() - flowPaneGames.getBorder().getStrokes().get(0).getWidths().getRight());
int totalSpaceY = (int) (flowPaneGames.getHeight() - paddingAroundGames[0] - paddingAroundGames[2] + gapBetweenGames[1] - flowPaneGames.getBorder().getStrokes().get(0).getWidths().getTop() - flowPaneGames.getBorder().getStrokes().get(0).getWidths().getBottom());

左图显示了容器的高度和宽度各为492,并考虑了容器的边框宽度。容器的边框宽度默认为1。正好有 4 个子窗格适合宽度:492 = 2 x border width of container (= 1) + 2 * padding (= 30) + 3 * gap (= 10) + 4 * child pane width (= 100)。高度也是如此。

如果宽度 and/or 高度减少 11 子窗格的宽度 and/or 高度将被省略。中间的图显示了容器的高度和宽度 491,每个都考虑了容器的边框宽度。

在不考虑容器边框宽度的情况下,假设 space 比实际可用的多,并且创建了太多的子窗格。右图显示了容器高度和宽度 491 每个 没有 考虑边框宽度(即它显示了当前代码的作用)。

编辑:

根据@Slaw 的建议,使用 Region#snappedXXXInset():

可以更轻松地计算 totalSpaceXtotalSpaceY
int totalSpaceX = (int) (flowPaneGames.getWidth() - flowPaneGames.snappedLeftInset() - flowPaneGames.snappedRightInset() + gapBetweenGames[0]);
int totalSpaceY = (int) (flowPaneGames.getHeight() - flowPaneGames.snappedTopInset() - flowPaneGames.snappedBottomInset() + gapBetweenGames[1]);

还应设置 snapToPixel(默认设置)。