当前位置: 首页 > 知识库问答 >
问题:

JavaFX中意外的布局行为

晏鸿畅
2023-03-14

我想写一个新的扩展区域的自定义容器类。此CustomContainer的子级列表不应可见。它包含一个窗格(称为rootPane),而这个窗格又包含一个vbox。并且这个VBox的children列表应该用于真正地向容器中添加子级(通过getInnerChildren访问)。这就是它的简化结构。

我的问题是,添加一个新的子项会导致CustomContainer本身的错误布局行为,因为它的高度增加了,所以应用了一个边框。但只有第一次添加孩子!下面是一个非常简单的可执行演示来测试它:

public class LayoutDemo extends Application
{
    @Override
    public void start(Stage stage)
    {
        CustomContainer container = new CustomContainer(new Label("First Label"), new Label("Second Label"), new Label("Third Label"));
        // The border here is involved in the problem. In fact, only the top width has influence.
        container.setBorder(new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(30, 3, 3, 3))));

        Button buttonAddNode = new Button("Add node");
        buttonAddNode.setOnAction(e -> container.specialAction());
        Button buttonSysout = new Button("Sysout height");
        buttonSysout.setOnAction(e -> System.out.println(container.getHeight()));

        HBox boxButtons = new HBox(10, buttonAddNode, buttonSysout);
        VBox sceneRoot = new VBox(20, container, boxButtons);
        sceneRoot.setPadding(new Insets(15)); // Just to make it look nicer.
        stage.setScene(new Scene(sceneRoot, 200, 200));
        stage.show();
    }

    public static class CustomContainer extends Region
    {
        private VBox innerBox = new VBox();
        private Pane rootPane = new StackPane(innerBox);

        public CustomContainer(Node... children)
        {
            getChildren().addAll(rootPane);
            getInnerChildren().addAll(children);
        }

        public void specialAction()
        {
            // Just for testing... Forces the CustomContainer to add a child to itself. And this is where the trouble begins...
            Node newChild = new Pane();
            newChild.setManaged(false); // I tried this, but it really has no influence.

            // The new child won't be visible in this test because it is not considered by layoutChildren(). But even layouting it would have no influence.
            getChildren().add(newChild);
        }

        @Override
        protected void layoutChildren()
        {
            System.out.println("LAYOUT");
            Insets borderInsets = getBorder().getInsets();
            double left = borderInsets.getLeft(),
                top = borderInsets.getTop(),
                width = getWidth() - left - borderInsets.getRight(),
                height = getHeight() - top - borderInsets.getBottom();
            layoutInArea(rootPane, left, top, width, height, 0, HPos.CENTER, VPos.CENTER);
        }

        public ObservableList<Node> getInnerChildren()
        {
            return innerBox.getChildren();
        }
    }

    public static void main(String... args)
    {
        launch();
    }
}

进一步提示:
-它在高度上增长的大小等于边框的顶部宽度。
-如果用HBox替换VBox,边框的左侧宽度将起决定性作用。
-它与我重写的layoutChildren()方法有关。如果不重写,问题就不会出现(但当然我需要正确地实现这个方法)。
-如前所述,它只在第一次添加子项时出现。但删除它不会恢复大小。
-“specialAction”方法表示一些内部完成的逻辑。这是因为我想在内部向CustomContainer(而不是向VBox)添加和删除一些新的子级!但当向VBox添加子项时,问题也会出现。

如果你很好奇,我对这个容器的计划是什么:它将实现一些拖放行为,通过一些自定义的视觉反馈来移动儿童。并且此可视化反馈将安装在CustomContainer的非公共子级列表上。
请不要建议更改容器结构。相反,我希望你能给我一些建议,为什么我的layoutChildren方法会导致这个问题,以及如何正确地做它。

共有1个答案

卜季萌
2023-03-14

尝试设置节点的最小宽度和高度。我的行为与您的非常相似,我看到了这篇文章https://dzone.com/articles/size-does-mater-in-javafx,然后我为锚窗格设置了最小高度,意外的行为就消失了。

 类似资料:
  • 主要内容:手风琴事件可以使用手风琴(accordion)控件对标题窗格进行分组。 上面的代码生成以下结果。 手风琴事件 当在手风琴中打开标题窗格时,手风琴的展开窗格属性会更改。 上面的代码生成以下结果。

  • 主要内容:创建标题窗格标题窗格是具有标题的面板,窗格可以打开和关闭。我们可以添加节点(如UI控件或图像)和一组元素到窗格。 上面的代码生成以下结果。 创建标题窗格 要创建一个控件,请调用其构造函数。 以下代码使用的两个参数构造函数。它将标题窗格命名为“我的窗格”,并用一个控件填充窗格。 接下来的几行做了与上面的代码相同的事情,但不使用带参数的构造函数。 它创建一个带有默认空构造函数的,然后再设置控件的标题和内容。 以下

  • 主要内容:创建滚动窗格,可滚动ScrollPane,滚动条策略,调整滚动窗格中的组件大小,滚动操作滚动窗口提供UI元素的可滚动视图。 我们使用可滚动面板,当需要显示有限的空间大内容。可滚动窗格视口,其将显示内容的一部分,并且在必要时提供滚动条。 上面的代码生成以下结果。 创建滚动窗格 以下代码使用文件创建一个图像,并将该图像添加到滚动窗格。如果图像较大,滚动窗格将显示滚动条,我们可以使用它来查看隐藏的部分。 可滚动ScrollPane 调用方法通过单击并移动鼠标光标来预览图像。 上面的代码生成

  • 主要内容:示例,示例2GridPane通常用于布局:第一列上的只读标签的输入表单和第二列上的输入字段。 GridPane可以在行,列或单元格级别指定约束。 例如,我们可以设置包含输入文本字段的第二列,以在窗口调整大小时调整大小。 示例 以下代码演示使用GridPane布局的简单表单应用程序。它有以下布局。 完整的代码实现如下所示 - 上面的代码生成以下结果。 示例2 以下是一个实现登录窗口的代码 - 上面的代码生成以下

  • 主要内容:示例,实例-2BorderPane布局顶部,底部,左,右或中心区域中的子节点。每个区域只能有一个节点。BorderPane的顶部和底部区域允许可调整大小的节点占用所有可用宽度。 左边界区域和右边界区域占据顶部和底部边界之间的可用垂直空间。 默认情况下,所有边界区域尊重子节点的首选宽度和高度。放置在顶部,底部,左侧,右侧和中心区域中的节点的默认对齐方式如下: 顶部: 底部: 左侧: 右侧: 中心: 示例 将按钮添

  • 主要内容:1- FlowPane布局,2- FlowPane示例,3- Scene Builder上的FlowPaneJavaFX FlowPane布局 1- FlowPane布局 是一个容器。它在一行上排列连续的子组件,并且如果当前行填满了以后,则自动将子组件向下推到下一行。 2- FlowPane示例 代码如下 - 运行示例,得到以下结果: 3- Scene Builder上的FlowPane 您可以使用JavaFX Scene Builder轻松设计界面。下图显示了使用Scane Buil