2017-04-22 52 views
0

我想编写一个新的自定义容器类来扩展Region。这个CustomContainer的子列表不应该是可见的。它包含一个窗格(称为rootPane),该窗格又包含一个VBox。并且该VBox的子列表应该用于真正将子项添加到容器(可通过getInnerChildren访问)。这是它的简化结构。JavaFX中的意外布局行为

我的问题是,添加一个新的孩子会导致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方法导致这个问题,以及如何做到这一点。

回答