2014-05-08 72 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