2014-03-04 54 views
1

在我開發的JavaFX程序中,我有一個StackPane。第一個孩子是其中有其他東西的BorderPane。JavaFX - StackPane中居中的彈出窗格

我希望能夠顯示彈出窗口,使除彈出窗口以外的所有內容變暗,以創建額外的焦點。這就是爲什麼我創建了一個擴展StackPane的「DarkenStackPane」。在創建時(在構造函數中),它爲它的子元素添加一個0.0不透明度的Rectangle。它有兩個函數,darken()和brighten()。 darken()具有從0.0到0.5的FadeTransition,使相反。

我添加一個窗格到StackPane,這個窗口調用了darken()函數。 darken()函數首先將黑色矩形放在前面,然後將窗格放在前面。

它工作正常,但StackPane將其所有子級調整爲適合其大小......我不希望發生這種情況。相反,我希望帶有自己寬度和高度的彈出窗格在StackPane中居中。

我知道我可以使用StackPane.setMargin(它與硬編碼的值一起工作),但是我無法確定正確的頁邊空白的原因,因爲該窗格沒有父項。當你的窗格被添加到父項時,是否有任何方法會被調用?我試着用ChangeListener做這件事,但我無法綁定匿名函數中的屬性。

我希望這有點清楚我的意思。 :-)

謝謝!

回答

4

考慮使用ControlsFX

ControlsFX庫有一個名爲「輕量級對話」功能,執行此相同的對話框疊加效應。對於這種解決方案使用預構建的庫通常比滾動您自己的實現更好。

lightweight

如果選擇推出自己的解決方案,而不是使用ControlsFX,然後閱讀。 。 。

解決方案

放置在一個GroupStackPane的疊加子窗格。

StackPane stack = new StackPane(mainPane, new Group(popupPane)); 

爲什麼這個作品

A組是不可調整大小,所以效果將是在mainPane是可調整大小的,並且popupPane將假設它的內部優選尺寸和放置在組內,這將是集中在StackPane的mainPane頂部。

示範

在一個項目中,我寫了一個很久以前的DialogFactory演示了這種方法來覆蓋上的WebView的頂部對話框。下面的屏幕截圖顯示了在Java 8下運行willow-0.3-prerelease-jar並導航到http://www.w3schools.com/js/tryit.asp?filename=tryjs_alert的輸出,然後單擊「嘗試」按鈕。它所做的是覆蓋警戒框(在JavaFX中呈現並編程,而不是JavaScript),該警報框以顯示警報時禁用和變暗的WebView控件爲中心。

alert

這是從willow project選擇的源樣品來源,它不是獨立的,但你需要稍微調整它它採用您的情況。代碼只是在這裏展示的技術和模式。

/** 
* Overlay a dialog on top of the WebView. 
* 
* @param dialogNode the dialog to overlay on top of the view. 
*/ 
private void overlayView(Node dialogNode) { 
    // if the view is already overlaid we will just ignore this overlay call silently . . . todo probably not the best thing to do, but ok for now. 
    if (!(webView.getParent() instanceof BorderPane)) return; 

    // record the view's parent. 
    BorderPane viewParent = (BorderPane) webView.getParent(); 

    // create an overlayPane layering the popup on top of the webview 
    StackPane overlayPane = new StackPane(); 
    overlayPane.getChildren().addAll(webView, new Group(dialogNode)); 
    webView.setDisable(true); 

    // overlay the popup on the webview. 
    viewParent.setCenter(overlayPane); 
} 

/** 
* Removes an existing dialog overlaying a WebView. 
*/ 
private void removeViewOverlay() { 
    BorderPane viewParent = (BorderPane) webView.getParent().getParent(); 
    viewParent.setCenter(webView); 
} 

public EventHandler<WebEvent<String>> createAlertHandler() { 
    return stringWebEvent -> { 
     AlertHandler alertHandler = new AlertHandler(
       stringWebEvent.getData(), 
       event -> { 
        webView.setDisable(false); 
        removeViewOverlay(); 
       } 
     ); 
     overlayView(alertHandler); 

     // todo block until the user accepts the alert. 
    }; 
} 

. . . 

// add an effect for disabling and enabling the view. 
getView().disabledProperty().addListener(new ChangeListener<Boolean>() { 
    final BoxBlur soften = new BoxBlur(); 
    final ColorAdjust dim = new ColorAdjust(); 
    { 
     dim.setInput(soften); 
     dim.setBrightness(-0.5); 
    } 

    @Override 
    public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue, Boolean newValue) { 
     if (newValue) { 
      getView().setEffect(dim); 
     } else { 
      getView().setEffect(null); 
     } 
    } 
}); 

. . . 

public class AlertHandler extends VBox { 
    public AlertHandler(String message, EventHandler<ActionEvent> confirmHandler) { 
     super(14); 

     // add controls to the popup. 
     final Label promptMessage = new Label(message); 
     final ImageView alertImage = new ImageView(ResourceUtil.getImage("alert_48.png")); 
     alertImage.setFitHeight(32); 
     alertImage.setPreserveRatio(true); 
     promptMessage.setGraphic(alertImage); 
     promptMessage.setWrapText(true); 
     promptMessage.setPrefWidth(350); 

     // action button text setup. 
     HBox buttonBar = new HBox(20); 
     final Button confirmButton = new Button(getString("dialog.continue")); 
     confirmButton.setDefaultButton(true); 

     buttonBar.getChildren().addAll(confirmButton); 

     // layout the popup. 
     setPadding(new Insets(10)); 
     getStyleClass().add("alert-dialog"); 
     getChildren().addAll(promptMessage, buttonBar); 

     final DropShadow dropShadow = new DropShadow(); 
     setEffect(dropShadow); 

     // confirm and close the popup. 
     confirmButton.setOnAction(confirmHandler); 
    } 
} 

. . . 

getView().getEngine().setOnAlert(dialogFactory.createAlertHandler()); 

真的,我上面寫代碼的唯一原因是因爲當時沒有可用的ControlsFX的等效庫。如果我從頭開始開發一個項目,我會首先嚐試使用ControlsFX。

+0

什麼是一個良好的,好的和堅實的答案!而且速度也很快;-)。我將研究ControlsFX,似乎可以幫助您解決JavaFX帶來的一些困難。我不知道解決方案很簡單。謝謝jewelsea,你是最棒的! – d0ggy

+0

好貼,非常感謝! – Flipbed