2014-05-08 44 views
0

我有一个问题,我的对话框(基本上是AnchorPanes有他们的标题)在他们的父节点(也是AnchorPane,但我相信这是无关紧要的)。JavaFX没有定位节点在父节点

代码去如下:

public void showDialog(final Dialog dialog) { 
    dialogStack.add(dialog); 

    dialogCanvas.toFront(); 
    dialog.toFront(); 

    dialogCanvas.setVisible(true); 
    dialog.setVisible(true); 

    getChildren().add(dialog); 
    dialog.widthProperty().addListener(new ChangeListener<Number>() { 
     @Override 
     public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { 
      if(newValue.doubleValue() > 0) { 
       centerDialog(dialog); 
      } 
     } 
    }); 
} 

public void centerDialog(final Dialog dialog) { 
    double width = getWidth(); 
    double height = getHeight(); 

    dialog.setLayoutX(width/2 - dialog.getWidth()/2); 
    dialog.setLayoutY(height/2 - dialog.getHeight()/2); 
} 

我使用widthProperty变化监听器,因为当它被渲染,然后才它获得的宽度/高度设置你只能中心节点。

当我在设置对话框的布局x/y时调试代码时,值计算得很好,但最后的对话框节点位于上/左角(X:0/Y:0)。

为什么?

我可以以某种方式触发重绘父节点,以便元素的位置正确吗?我究竟做错了什么?

亲切的问候, 斯捷潘

回答

0

的问题是,这是所有在单个线程完成,还不知道关于布局的信息......但使用Platform.runLater(...)我能够解决这个问题。

在这是很优雅的,当你知道如何解决它的结束......

public void showDialog(final Dialog dialog) { 
dialogStack.add(dialog); 

dialogCanvas.toFront(); 
dialog.toFront(); 

dialogCanvas.setVisible(true); 
dialog.setVisible(true); 

getChildren().add(dialog); 
dialog.widthProperty().addListener(new ChangeListener<Number>() { 
    @Override 
    public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { 
     if(newValue.doubleValue() > 0) { 
      centerDialog(dialog); 
     } 
    } 
}); 
} 

public void centerDialog(final Dialog dialog) { 
    Platform.runLater(new Runnable() { 
     @Override 
     public void run() { 
      double width = getWidth(); 
      double height = getHeight(); 

      dialog.setLayoutX(width/2 - dialog.getWidth()/2); 
      dialog.setLayoutY(height/2 - dialog.getHeight()/2); 
     } 
    }); 

}

+1

您不需要每次都运行Platform.runLater(),并且也因为性能原因)。只有在这个Platform.runLater()中第一次调用centerDialog就足够了。这与在primaryStage.show()之后运行centerDialog具有相同的效果。 –

0

您的选择:

  • 继续使用AnchorPane作为父母,但通过使用锚约束

    AnchorPane.setTopAnchor(dialog, height/2 - dialog.getHeight()/2); 
    AnchorPane.setLeftAnchor(dialog, width/2 - dialog.getWidth()/2); 
    

    中心的孩子在宽度的每一个变化和高度值家长窗格。如果希望子窗格保持以窗口大小调整为中心,则需要为宽度和高度属性添加事件侦听器。

  • 使用Pane代替AnchorPane为家长和中心由setLayoutX(子窗格)/ setLayoutY(),在父母的宽度和高度值的每一个变化(再次使用事件侦听器)。与AnchorPane相反的Pane,除了将它们调整为他们喜欢的尺寸之外,不会布置其子项。

  • 使用StackPane代替AnchorPane作为父节点,并且不需要居中子窗格,因为StackPane会自动为您执行。

  • 使用ControlsFX对话框。



对于第一种选择的演示代码:

public class AnchorDemo extends Application { 

    private final AnchorPane anchorPaneParent = new AnchorPane(); 
    private final AnchorPane anchorPaneChild = new AnchorPane(new Label("TEXT TEXT TEXT TEXT TEXT")); 

    @Override 
    public void start(Stage primaryStage) { 
     anchorPaneParent.setStyle("-fx-border-color:red"); 
     anchorPaneChild.setStyle("-fx-border-color:green"); 
     anchorPaneParent.getChildren().add(anchorPaneChild); 

     anchorPaneParent.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() { 
      @Override 
      public void changed(ObservableValue<? extends Bounds> arg0, Bounds oldBound, Bounds newBound) { 
       System.out.println("oldBound = " + oldBound); 
       System.out.println("newBound = " + newBound); 
       System.out.println(""); 
       if (oldBound.getHeight() != newBound.getHeight() || oldBound.getWidth() != newBound.getWidth()) { 
        updateChildAnchorConstraint(); 
       } 
      } 
     }); 

     Scene scene = new Scene(anchorPaneParent, 300, 250); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
     updateChildAnchorConstraint(); 

    } 

    private void updateChildAnchorConstraint() { 
     AnchorPane.setTopAnchor(anchorPaneChild, anchorPaneParent.getHeight()/2 - anchorPaneChild.getHeight()/2); 
     AnchorPane.setLeftAnchor(anchorPaneChild, anchorPaneParent.getWidth()/2 - anchorPaneChild.getWidth()/2); 
    } 

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

} 
+0

它不会与你所建议的第一个解决方案工作...我不知道为什么,但是当你将对话框添加到父项并尝试设置位置时,任何类型的定位都不起作用。当我钩住宽度和高度属性,并调整窗口大小,然后对话框重新定位自己......其他选项不幸不适用,因为我需要父节点为AnchorPane。感谢Uluk的建议! – StjepanV

+0

@StjepanVukadin,这是因为您提到的相同行为,即宽度和高度值不计算,直到节点呈现。解决方法是在primaryStage.show()后面一次调用AnchorPane.setTopAnchor(...)和AnchorPane.setLeftAnchor(...)。 –

+0

我试过了。我用建议的代码替换了我的代码来使用锚定,但它不起作用......我真的不知道为什么。除了这种特殊场景以外,我没有任何其他定位元素问题。 setLayoutX/Y在其他地方工作就好了... – StjepanV