转换 FXML 对话框的结果

Converting the result of an FXML dialog

我创建了一个带有单选按钮的简单对话框

<?xml version="1.0" encoding="UTF-8"?>

<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.image.Image?>


<Dialog fx:id="dialog"
    fx:controller="myapp.AddDialogController"
    xmlns:fx="http://javafx.com/fxml">
    <dialogPane>
        <DialogPane prefWidth="400.0" prefHeight="300.0">
            <stylesheets>
                <URL value="@/css/styles.css" />
            </stylesheets>
            <content>
                <VBox>
                    <fx:define>
                        <ToggleGroup fx:id="myToggleGroup"/>
                    </fx:define>
                    <children>
                        <RadioButton text="Comment" toggleGroup="$myToggleGroup"/>
                        <RadioButton text="Survey" toggleGroup="$myToggleGroup"/>
                        <RadioButton text="Suggestion" toggleGroup="$myToggleGroup"/>
                    </children>
                </VBox>
            </content>
        </DialogPane>
    </dialogPane>
</Dialog>

我是这样创建的:

private String convertDialogResult(ButtonType buttonType) {
    if (buttonType == ButtonType.OK) {
        return "A";
    } else {
        return null;
    }
}

private Dialog<String> createAddDialog() throws ApplicationException {

    try {
        Dialog<NodeViewModel> dialog = FXMLLoader.load(getClass().getResource("/fxml/add_dialog.fxml"));

        dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
        dialog.setResultConverter(this::convertDialogResult);

        return dialog;
    } catch (IOException e) {
        throw new ApplicationException(e);
    }
}

但现在我不想一直return "A",但是"A"如果选择"Comment","B"如果"Survey"被选中,等等

我该怎么做?

你试过了吗:

group.selectedToggleProperty().addListener(new ChangeListener<Toggle>(){
    public void changed(ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) {

         if (group.getSelectedToggle() != null) {

             System.out.println(group.getSelectedToggle().getUserData().toString());
             // Do something here with the userData of newly selected radioButton

         }

     } 
});

所以你有一个控制器:myapp.AddDialogController,你将在其中定义 @FXML ToggleGroup #myToggleGroup。因此控制器知道与对话框中的单选按钮关联的切换组。

不使用静态 FXMLLoader 加载函数,而是创建一个新的 FXMLLoader 并使用其中的(非静态)加载函数。完成后,您可以从加载程序实例中获取对控制器的引用。从控制器获取控制器引用的技术在以下答案中演示:Passing Parameters JavaFX FXML.

获得对控制器的引用后,您可以将其作为附加参数传递给 convertDialogResult 函数。在该函数中,不只是 return 字符 A,您还可以 return 来自切换组中所选切换的映射(您可以通过查询添加到 Controller [ 的新方法来发现) =16=]) 到您想要的字符串(例如 "Comment")。如果只需在选定的切换按钮上调用 getText() 就足够了,您甚至不需要在代码中维护映射。


但是,最后,我认为首选的选择不是像您所做的那样从控制器中外部化一些对话逻辑,而是将一些逻辑封装在控制器内部,如下所示:

myapp/add-dialog.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.VBox?>

<Dialog fx:id="dialog"
        fx:controller="myapp.AddDialogController"
        xmlns:fx="http://javafx.com/fxml">
  <dialogPane>
    <DialogPane prefWidth="400.0" prefHeight="300.0">
      <content>
        <VBox>
          <fx:define>
            <ToggleGroup fx:id="myToggleGroup"/>
          </fx:define>
          <RadioButton text="Comment" toggleGroup="$myToggleGroup"/>
          <RadioButton text="Survey" toggleGroup="$myToggleGroup"/>
          <RadioButton text="Suggestion" toggleGroup="$myToggleGroup"/>
        </VBox>
      </content>
    </DialogPane>
  </dialogPane>
</Dialog>

myapp/AddDialogController.java

package myapp;

import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.*;

public class AddDialogController {
    @FXML private ToggleGroup myToggleGroup;
    @FXML private Dialog<String> dialog;

    public void initialize() {
        dialog.getDialogPane().getButtonTypes().addAll(
                ButtonType.OK, ButtonType.CANCEL
        );

        Node okButton = dialog.getDialogPane().lookupButton(ButtonType.OK);
        okButton.disableProperty().bind(
                Bindings.isNull(
                        myToggleGroup.selectedToggleProperty()
                )
        );

        dialog.setResultConverter(this::convertDialogResult);
    }

    private String convertDialogResult(ButtonType buttonType) {
        if (ButtonType.OK.equals(buttonType)) {
            return getSelectedToggleValue();
        } else {
            return null;
        }
    }

    private String getSelectedToggleValue() {
        RadioButton selectedRadio = (RadioButton) myToggleGroup.getSelectedToggle();

        if (selectedRadio == null) {
            return null;
        }

        return selectedRadio.getText();
    }
}

myapp/DialogDisplayApp.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;

public class DialogDisplayApp extends Application {

    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader loader = new FXMLLoader(
                getClass().getResource(
                        "add-dialog.fxml"
                )
        );

        stage.setScene(new Scene(new VBox(new Label("Main Window")), 600, 400));
        stage.show();

        Dialog<String> dialog = loader.load();

        dialog.initOwner(stage);
        dialog.showAndWait();

        System.out.println(dialog.getResult());
    }

    public static void main(String[] args) {
        launch(args);
    }
}