java - 如何在不使用任何 "ButtonType"控件的情况下在 JavaFx 中创建自定义对话框?

标签 java javafx dialog

我想创建一个自定义Dialog,它只显示选项(参见图 1)。如果用户选择这些选项之一,对话框应关闭并立即返回相应的结果。

到目前为止,我只能通过向 Dialog 添加任意 ButtonType 来实现此目的,并使用 setVisible(false) 隐藏它,在单击选项的 EventHandler 中应用 fire()

这个奇怪的解决方法实际上工作得很好,但在我看来非常不专业......
那么,在不使用 ButtonType 技巧的情况下,如何以更专业或更正确的方式做到这一点

figure 1

我的解决方法代码如下所示(对话框类):

public class CustomDialog extends Dialog<String> {

    private static final String[] OPTIONS
            = new String[]{"Option1", "Option2", "Option3", "Option4"};
    private String selectedOption = null;
    Button applyButton;

    public CustomDialog() {
        super();
        initStyle(StageStyle.DECORATED);
        VBox vBox = new VBox();
        for (String option : OPTIONS) {
            Button optionButton = new Button(option);
            optionButton.setOnAction((event) -> {
                selectedOption = option;
                applyButton.fire();
            });
            vBox.getChildren().add(optionButton);
        }
        getDialogPane().setContent(vBox);
        getDialogPane().getButtonTypes().add(ButtonType.APPLY);
        applyButton = (Button) getDialogPane().lookupButton(ButtonType.APPLY);
        applyButton.setVisible(false);

        setResultConverter((dialogButton) -> {
            return selectedOption;
        });
    }
}

使用对话框类:

    CustomDialog dialog = new CustomDialog();
    Optional<String> result = dialog.showAndWait();
    String selected = null;
    if (result.isPresent()) {
        selected = result.get();
    } else if (selected == null) {
        System.exit(0);
    }

最佳答案

Dialog 只是一个显示 DialogPane 的窗口,并且引用 Javadocs for DialogPane :

DialogPane operates on the concept of ButtonType. A ButtonType is a descriptor of a single button that should be represented visually in the DialogPane. Developers who create a DialogPane therefore must specify the button types that they want to display

(我的重点)。因此,虽然您已经展示了一种可能的解决方法,并且在另一个答案 Slaw 中展示了另一种解决方法,但如果您尝试使用 Dialog 而不使用 ButtonType 及其关联结果转换器,您实际上是在将 Dialog 类用于其不适合的用途。

您所描述的功能可以通过常规模态Stage完美实现。例如,以下给出了您所描述的相同基本行为,并且不涉及 ButtonType:

package org.jamesd.examples.dialog;

import java.util.Optional;
import java.util.stream.Stream;

import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;

public class CustomDialog {

    private static final String[] OPTIONS 
        = {"Option 1", "Option 2", "Option 3", "Option 4"};

    private final Stage stage ;

    private String selectedOption = null ;

    public CustomDialog() {
        this(null);
    }

    public CustomDialog(Window parent) {
        var vbox = new VBox();
        // Real app should use an external style sheet:
        vbox.setStyle("-fx-padding: 12px; -fx-spacing: 5px;");
        Stream.of(OPTIONS)
            .map(this::createButton)
            .forEach(vbox.getChildren()::add);
        var scene = new Scene(vbox);
        stage = new Stage();
        stage.initOwner(parent);
        stage.initModality(Modality.WINDOW_MODAL);
        stage.setScene(scene);
    }

    private Button createButton(String text) {
        var button = new Button(text);
        button.setOnAction(e -> {
            selectedOption = text ;
            stage.close();
        });
        return button ;
    }

    public Optional<String> showDialog() {
        selectedOption = null ;
        stage.showAndWait();
        return Optional.ofNullable(selectedOption);
    }
}

这是一个使用此自定义对话框的简单应用程序类:

package org.jamesd.examples.dialog;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class App extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        var root = new VBox();
        // Real app should use an external style sheet:
        root.setStyle("-fx-padding: 12px; -fx-spacing: 5px;");
        var showDialog = new Button("Show dialog");
        var label = new Label("No option chosen");
        showDialog.setOnAction(e -> 
            new CustomDialog(stage)
                .showDialog()
                .ifPresentOrElse(label::setText, Platform::exit));
        root.getChildren().addAll(showDialog, label);
        stage.setScene(new Scene(root));
        stage.show();
    }

}

关于java - 如何在不使用任何 "ButtonType"控件的情况下在 JavaFx 中创建自定义对话框?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60102226/

相关文章:

java - 恶意代码漏洞 - 可能通过返回对可变对象的引用来暴露内部表示 - 使用哪些对象?

java - JavaFX TableView 宽度从何而来?

安卓 : Open google play dialog from my app

javascript - 使用 jQuery 设置值时 ng-model 不起作用

java - 弃用一组相关方法的最佳做法是什么?

java - 在独立应用程序中, session 对象存储在哪里?

java - 使用eclipse插件从源文件中获取类名列表、方法变量列表等

Javafx 自定义 slider 值

button - JavaFX Transition - 悬停时变暗按钮

android - onClick 不适用于自定义对话框