Как указали @Sedrick и @James_D, API Dialog
построен на концепции «типов кнопок». Неиспользование ButtonType
идет вразрез с API, и поэтому всегда будет казаться хакерским / неправильным. Тем не менее, вы можете внести небольшое изменение в ваш текущий код, который удовлетворяет вашей цели " без использования цели ButtonType-controls ". Похоже, что это не задокументировано, но если вы установите свойство result
вручную, это вызовет процесс закрытия и возврата результата. Это означает, что вам не нужно добавлять ButtonType
и вы можете полностью обойти resultConverter
. Вот подтверждение концепции :
OptonsDialog. java:
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Dialog;
import javafx.scene.layout.VBox;
public class OptionsDialog<T extends OptionsDialog.Option> extends Dialog<T> {
public interface Option {
String getDisplayText();
}
@SafeVarargs
public OptionsDialog(T... options) {
if (options.length == 0) {
throw new IllegalArgumentException("must provide at least one option");
}
var content = new VBox(10);
content.setAlignment(Pos.CENTER);
content.setPadding(new Insets(15, 25, 15, 25));
for (var option : options) {
var button = new Button(option.getDisplayText());
button.setOnAction(
event -> {
event.consume();
setResult(option);
});
content.getChildren().add(button);
}
getDialogPane().setContent(content);
}
}
Приложение. java:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.Window;
public class App extends Application {
private enum Foo implements OptionsDialog.Option {
OPTION_1("Option Number 1"),
OPTION_2("Option Number 2"),
OPTION_3("Option Number 3"),
OPTION_4("Option Number 4");
private final String displayText;
Foo(String displayText) {
this.displayText = displayText;
}
@Override
public String getDisplayText() {
return displayText;
}
}
@Override
public void start(Stage primaryStage) {
var button = new Button("Click me!");
button.setOnAction(
event -> {
event.consume();
showChosenOption(primaryStage, promptUserForOption(primaryStage));
});
primaryStage.setScene(new Scene(new StackPane(button), 500, 300));
primaryStage.show();
}
private static Foo promptUserForOption(Window owner) {
var dialog = new OptionsDialog<>(Foo.values());
dialog.initOwner(owner);
dialog.setTitle("Choose Option");
return dialog.showAndWait().orElseThrow();
}
private static void showChosenOption(Window owner, OptionsDialog.Option option) {
var alert = new Alert(AlertType.INFORMATION);
alert.initOwner(owner);
alert.setHeaderText("Chosen Option");
alert.setContentText(String.format("You chose the following: \"%s\"", option.getDisplayText()));
alert.show();
}
}
Это не сильно отличается от вашего текущего обходного пути и все еще работает против API. Это также зависит от недокументированного поведения (установка свойства result
вручную закрывает диалоговое окно и возвращает результат). ButtonBar
внизу все еще занимает некоторое место, хотя и меньше, чем при добавлении невидимой кнопки. Однако можно избавиться от этого пустого пространства, добавив следующее CSS:
.options-dialog-pane .button-bar {
-fx-min-height: 0;
-fx-pref-height: 0;
-fx-max-height: 0;
}
Обратите внимание, что выше предполагается, что вы изменили код для добавления класса стиля "options-dialog-pane"
в DialogPane
используется с OptionsDialog
.