如何使用Guava获取具体的控制器类型

编程语言 2026-07-10

我在我的JavaFX应用中使用Google Guava来切换内容面板。

@Subscribe
public void handleChangeViewDataModel(ChangeViewEventDataModel event) {
    try {

        FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(getClass().getResource(event.getViewName())));
        loader.setControllerFactory(new ControllerFactory());
        Parent root = loader.load();

        // change the content pane
        contentController.getContent().getChildren().clear();
        contentController.getContent().getChildren().add(root);

以及

public class ControllerFactory implements Callback<Class<?>, Object> {
    @Override
    public Object call(Class<?> controllerType) {
        if (controllerType == ContentController.class) return new ContentController();
        if (controllerType == ContentHomeController.class) return new ContentHomeController();
        if (controllerType == ContentOneController.class) return new ContentOneController();
        throw new RuntimeException("Controller of type '" + controllerType.getSimpleName() + "' is not supported!");
    }
}

如何获取控制器的具体实现类,以便调用其他方法来设置UI元素?

我需要类似这样的:

ContentOneController contentOneController = loader.getController();
contentOneController.setLabelText(event.getNewData());

或者是否有其他推荐的做法?

解决方案

是否有其他推荐的方法?

我建议让控制器来承担初始化工作,向它提供完成初始化所需的数据,而不是像你现在尝试的那样从外部调用一个方法来执行初始化。为此,你可以按如下方式进行重构:

首先,通过构造函数让控制器获得对事件的访问权,然后只需在通常的 initialize() 方法中完成初始化:

public class ContentOneController {

    private ChangeViewEventDataModel event ;

    public ContentOneController(ChangeViewEventDataModel event) {
        this.event = event;
    }

    public ContentOneController() {
        this(null);
    }

    @FXML
    private void initialize() {
        if (event != null) {
            setLabelText(event.getNewData());
        }
    }

    // exisiting code ...
}

现在你只需要修改控制器工厂,使其能够访问事件:

public class ControllerFactory implements Callback<Class<?>, Object> {

    private ChangeViewEventDataModel event ;

    public ControllerFactory(ChangeViewEventDataModel event) {
        this.event = event;
    }


    @Override
    public Object call(Class<?> controllerType) {
        if (controllerType == ContentController.class) return new ContentController();
        if (controllerType == ContentHomeController.class) return new ContentHomeController();
        if (controllerType == ContentOneController.class) return new ContentOneController(event);
        throw new RuntimeException("Controller of type '" + controllerType.getSimpleName() + "' is not supported!");
    }
}

最后只需把事件传递给控制器工厂:

@Subscribe
public void handleChangeViewDataModel(ChangeViewEventDataModel event) {
    try {

        FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(getClass().getResource(event.getViewName())));
        loader.setControllerFactory(new ControllerFactory(event));
        Parent root = loader.load();

        // change the content pane
        contentController.getContent().getChildren().clear();
        contentController.getContent().getChildren().add(root);
    } catch (Exception e) {
        // ...
    }
}

现在控制器将自行处理初始化,你就不需要在外部调用 setLabelText(...) 方法。这将是我首选的方法,因为初始化发生在“自然”的位置。


如果你愿意不进行重构,你可以只使用带模式匹配的switch(甚至只是使用 if 语句序列,结合 instanceof)。这看起来不太可取,因为它需要对控制器类型进行第二轮测试,超出了你在控制器工厂中已经需要实现的内容:

@Subscribe
public void handleChangeViewDataModel(ChangeViewEventDataModel event) {
    try {

        FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(getClass().getResource(event.getViewName())));
        loader.setControllerFactory(new ControllerFactory(event));
        Parent root = loader.load();

        // change the content pane
        contentController.getContent().getChildren().clear();
        contentController.getContent().getChildren().add(root);

        switch (loader.getController()) {
            case ContentOneController c1c -> c1c.setLabelText(event.getNewData());
            // other cases as needed
            default -> {}
        }

    } catch (Exception e) {
        // ...
    }
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章