1

在我正在开发的 JavaFX 程序中,我有一个 StackPane。第一个孩子是一个 BorderPane,里面有其他东西。

我希望能够显示使除弹出窗口之外的所有内容变暗的弹出窗口,以创建额外的焦点。这就是为什么我创建了一个扩展 StackPane 的“DarkenStackPane”。在创建时(在构造函数中),它向其子项添加一个不透明度为 0.0 的 Rectangle。它有两个函数,变暗()和变亮()。darken() 具有从 0.0 到 0.5 的 FadeTransition,brighten() 相反。

我向 StackPane 添加了一个窗格,这调用了 darken() 函数。darken() 函数首先将黑色 Rectangle 放在前面,然后将 Pane 放在前面。

它工作正常,但 StackPane 会调整其所有子项的大小以适应其大小......我不希望这种情况发生。相反,我希望具有自己的宽度和高度的弹出窗格在 StackPane 中居中。

我知道我可以使用 StackPane.setMargin (它适用于硬编码值),但我无法确定正确的边距,因为在创建时窗格还没有父级。

当您的窗格被添加到父级时,是否有任何方法被调用?

我尝试使用 ChangeListener 执行此操作,但无法绑定匿名函数中的属性。

4

1 回答 1

5

考虑使用 ControlsFX

ControlsFX库有一个称为“轻量级对话框”的功能,它执行相同的对话框叠加效果。为这种解决方案使用预构建的库通常比滚动自己的实现更好。

轻的

如果您选择推出自己的解决方案而不是使用 ControlsFX,请继续阅读。. .

解决方案

StackPane的覆盖子窗格放在Group中。

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

为什么这样有效

Group 不可调整大小,因此效果将是 mainPane 可调整大小,并且 popupPane 将假定其内部首选大小并放置在一个 Group 中,该 Group 将由 StackPane 在 mainPane 顶部居中。

示范

我很久以前写的一个项目中的DialogFactory演示了这种在 WebView 之上覆盖对话框的方法。下面的屏幕截图显示了在Java 8下运行willow-0.3-prerelease-jar并导航到http://www.w3schools.com/js/tryit.asp?filename=tryjs_alert的输出,然后单击“尝试一下”按钮。它所做的是覆盖位于 WebView 控件顶部的警报框(在 JavaFX 中呈现和编程),该控件在显示警报时被禁用和变暗。

警报

样品来源

这是从柳树项目中选择的源代码,它不是独立的,但您需要稍微调整它以适应您的情况。此处仅提供代码以演示该技术和模式。

/**
 * 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。

于 2014-03-04T23:37:48.117 回答