使用扩展 JavaFX Class Dialog<R> 和初始化 DialogPane 的问题

issue with using extended JavaFX Class Dialog<R> and initializing the DialogPane

我在我的 JavaFX 应用程序中使用了扩展对话框 class,但是我未能初始化 DialogPane 的字段。似乎从未调用过初始化方法。我对程序代码进行了多次修改,不幸的是我没有成功。因此我希望你能帮助我。谢谢!

应用程序减少到最少:主程序通过PortalController ControllerFactory启动。有一个按钮可以打开我的'DialogFriZi'。相关的 DialogPane 包含一个标签。此标签初始化失败。

主程序:

public class Main extends Application {
private final Logger logger = Logger.getLogger(this.getClass().getName());
private final String FXML_PORTAL = "portal.fxml";
private MyHandler myHandler = new MyHandler();

@Override
public void init() {
    try{
        // Thread.currentThread is the FX-Launcher thread:
        Thread.currentThread().setUncaughtExceptionHandler(myHandler);
        try {
            logger.addHandler(new FileHandler("java.myLOG"));
        }
        catch (IOException e) {
            throw new IllegalStateException("IOException when adding File Handler");
        }
    }
    catch (Exception ex) {
        myHandler.uncaughtException(Thread.currentThread(), ex);
        throw(ex);
    }
}
@Override
public void start(Stage primaryStage) {
    try{
        logger.info("Test Application started");
        Thread.currentThread().setUncaughtExceptionHandler(myHandler);
        try{
            URL location = new URL(this.getClass().getResource("resources/fxml/" + FXML_PORTAL).toString());
            FXMLLoader loader = new FXMLLoader(location);
            loader.setControllerFactory(new SimpleControllerFactory(primaryStage));
            Pane root = loader.load();
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.setTitle("*** TEST App ***");
            primaryStage.show();
        }
        catch(IOException ex) {
            ex.printStackTrace();
            throw new IllegalStateException("check program source code!");
        }
    }
    catch(Exception ex) {
        myHandler.uncaughtException(Thread.currentThread(), ex);
        throw(ex);
    }
}

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

class MyHandler implements Thread.UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        logger.log(Level.SEVERE, "** STOPP ** due to uncaught exception", throwable);
        Platform.exit();
    }
}

}

控制器工厂

public class SimpleControllerFactory implements Callback<Class<?>,Object> {
private static final Logger logger = Logger.getLogger(SimpleControllerFactory.class.getName());
private final Stage primaryStage;
// types of controller
public SimpleControllerFactory(Stage stage) {
    this.primaryStage = stage;
}
public SimpleControllerFactory() { this(null); }

@Override
public Object call(Class<?> type) {
    try {
        for (var c : type.getConstructors()) {

            switch(c.getParameterCount()) {
                case 0 -> { }
                case 1 -> {
                    if ( c.getParameterTypes()[0] == Stage.class) {
                        return c.newInstance(primaryStage) ;
                    }
                    else;
                }
                default -> { }
            }
        }
        return type.getDeclaredConstructor().newInstance();
    }
    catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException ex) {
        logger.log(Level.SEVERE,ex.toString(),ex);
        throw new RuntimeException(ex);
    }
}

}

门户控制器

public class PortalController implements Initializable {

private static final Logger logger = Logger.getLogger(PortalController.class.getName());
private final Stage recentStage;
private ResourceBundle resourceBundle;

public PortalController(Stage stage) {
    this.recentStage = stage;
}
public PortalController() {
    this(null);
}

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
    this.resourceBundle = resourceBundle;
}

@FXML
private void start(ActionEvent event) {
    DialogFriZi dialog = null;
    dialog = new DialogFriZi(recentStage);
    Optional<Boolean> result = dialog.showAndWait();
}

}

相关的 FXML 文件

<VBox prefHeight="500.0" prefWidth="400.0" spacing="5.0" style="-fx-padding: 5 5 5 5;-fx-font-size: 11px" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="TestSimpleDialog.PortalController">
<children>
    <HBox alignment="CENTER">
        <children>
            <Button mnemonicParsing="false" onAction="#start" text="start FriZi dialog">
                <HBox.margin>
                    <Insets top="50.0" />
                </HBox.margin>
            </Button>
        </children>
    </HBox>
</children>

扩展对话框class

public class DialogFriZi extends Dialog<Boolean> {

@FXML private ButtonType okButtonType;
@FXML Label label;

private static final Logger logger = Logger.getLogger(DialogFriZi.class.getName());
private final Stage recentStage;

public DialogFriZi(Stage primaryStage) {
    this.recentStage = primaryStage;
    runDialog();
}
public DialogFriZi() {
    this(null);
}

@FXML private void initialize() {
    System.out.println("start initializing");
    label.setText("hello");
}

private void runDialog() {
    FXMLLoader loader = new FXMLLoader();
    try {
        loader.setLocation(new URL
                (this.getClass().getResource("resources/fxml/dialogFriZi.fxml").toString()));
        DialogPane dialogPane = loader.load();
        loader.setController(this);
        initOwner(recentStage);

        initModality(Modality.APPLICATION_MODAL);
        setResizable(true);
        setTitle("FriZi Dialog");
        setDialogPane(dialogPane);

    }
    catch (IOException e) {
        String message = "illegale state due to problem with 'resource dialogFriZi.fxml'";
        logger.log(Level.SEVERE,message);
        throw new IllegalStateException(message);
    }
}

}

相关的 FXML 文件

<DialogPane prefHeight="400.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1">
<content>
    <HBox prefHeight="100.0" prefWidth="200.0">
     <children>
        <Label fx:id="label" text="Label" />
     </children></HBox>

</content>
<buttonTypes>
    <ButtonType buttonData="OK_DONE" text="ok" />
    <ButtonType buttonData="CANCEL_CLOSE" text="Abbrechen" />
</buttonTypes>

initalize() 方法在控制器上调用,如果有的话,在 load() 方法执行期间。您正在设置控制器 调用 load() 之后,因此当 load() 运行时,没有控制器。您需要更改调用顺序:

private void runDialog() {
    FXMLLoader loader = new FXMLLoader();
    try {
        loader.setLocation(new URL
                (this.getClass().getResource("resources/fxml/dialogFriZi.fxml").toString()));

        loader.setController(this);

        DialogPane dialogPane = loader.load();
        // loader.setController(this);
        initOwner(recentStage);

        initModality(Modality.APPLICATION_MODAL);
        setResizable(true);
        setTitle("FriZi Dialog");
        setDialogPane(dialogPane);

    }
    catch (IOException e) {
        String message = "illegale state due to problem with 'resource dialogFriZi.fxml'";
        logger.log(Level.SEVERE,message);
        throw new IllegalStateException(message);
    }
}