如何将此 JavaFX 更改为使用 ControllerFactory

How to change this JavaFX into using a ControllerFactory

我研究了很多 ControllerFactory 的使用,以允许从数据库实例化此代码,并具有跨控制器兼容性。但是由于我的原始设置与我在网上找到的其他设置不同,我发现很难遵循,也很难使用他们的适合我的程序的设置。关于从哪里开始的任何建议?

当前控制器创建 -

        // get Main Class package name to get correct files path
        String pathRef = mainRef.getClass().getPackage().getName();
        // set FXRouter current route reference
        currentRoute = route;
        // create correct file path.  "/" doesn't affect any OS
        String scenePath = "/" + pathRef + "/" + route.scenePath;




        // Creates controller for route
        Controller_Factory cf = new Controller_Factory();
        Object controller  = cf.CreateController(route.scenePath);


        FXMLLoader loader = new FXMLLoader(controller.getClass().getResource(scenePath));
        loader.setController(controller);


        Parent root = loader.load();



        // set window title from route settings or default setting
        window.setTitle(route.windowTitle);
        // set new route scene
        window.setScene(new Scene(root, route.sceneWidth, route.sceneHeight));
        // show the window
        window.show();


    }

控制器示例-

public class BuyController extends Controller {

    @FXML
    public Button CloseAppButton;
    @FXML public Button SwitchToProfileButton;
    @FXML public Button SwitchToSellButton;
    @FXML public Button SwitchToBuyButton;
    @FXML public Button SwitchToMainButton;

@FXML public TextField BuyText;


String AmountBought;

    public void initialize (URL location, ResourceBundle resources){
        CloseAppButton.setPrefHeight(30);
        CloseAppButton.setPrefWidth(56);

        SwitchToBuyButton.setPrefHeight(30);
        SwitchToBuyButton.setPrefWidth(56);

        SwitchToMainButton.setPrefHeight(30);
        SwitchToMainButton.setPrefWidth(56);

        SwitchToSellButton.setPrefHeight(30);
        SwitchToSellButton.setPrefWidth(56);

        SwitchToProfileButton.setPrefHeight(30);
        SwitchToProfileButton.setPrefWidth(56);
    }
    public void OnBuyButton (ActionEvent event) {
AmountBought = BuyText.getText();
System.out.println("You have bought " + AmountBought + " of crypto");
BuyText.clear();
    }


    @Override
    public void initilize(URL url, ResourceBundle rb) {

    }


}

当前Controller_Factory-

public class Controller_Factory {

    private static final Controller_Factory instance = new Controller_Factory();

public static Controller_Factory getInstance() {
    return instance;
}



public Object CreateController (String routeScenePath) throws IllegalArgumentException, IOException {



    Object controller = null;



    switch (routeScenePath) {
        case  "Buy.fxml":
            controller = new BuyController();
            break;
        case "Error.fxml":
            controller = new ErrorController();
            break;
        case "Home.fxml":
            controller = new HomeController();
            break;
        case "Profile.fxml":
            controller = new ProfileController();
            break;
        case "Sell.fxml":
            controller = new SellController();
            break;
        default:

    }
   System.out.println(routeScenePath);
    return controller;
}


}

我如何将此信息传递给所述控制器? (这不是我的真实代码,而是配置示例 JSON 我想与控制器一起传递。)

  "HomePage": {
    "ValidPages": [
      "BuyPage",
      "SellPage"
    ],
    "InternalID": "HP"
  },
  "BuyPage": {
    "ValidPages": [
      "HomePage"
    ],
    "InternalID": "BP",
    "Cryptos": [
      "BTC",
      "LTC"
    ]

控制器工厂只是一个 Callback<Class<?>, Object>,其 call(Class<?> type) 函数采用 FXML 文件中 fx:controller 属性中定义的 class 和 returns用作控制器的对象。这是在加载 FXML 时由 FXMLLoader 调用的。

我认为您的问题是询问是否可以使用控制器工厂自动将存储在 JSON 中的数据填充到控制器中,这些数据将在运行时读取。

你可以这样做:

public class NavigationInfo {

    private final Map<String, PageNavigationInfo> pageInfoPerPage ;

    public NavigationInfo(Map<String, PageNavigationInfo pageInfoPerPage) {
        this.pageInfoPerPage = pageInfoPerPage;
    }

    public PageNavigationInfo getInfoForPage(String page) {
        return pageInfoPerPage.get(page);
    }
}
public class PageNavigationInfo {

    private final String internalID ;

    private final List<String> validPages ;

    private final List<String> cryptos ;

    // .... etc
}
public class NavigationControllerFactory implements Callback<Class<?>, Object> {

    private final NavigationInfo navigationInfo ;

    public NavigationControllerFactory() {
        // read and parse JSON and create NavigationInfo instance
    }

    @Override
    public Object call(Class<?> type) {
        try {
            for (Constructor<?> c : type.getConstructors()) {
                if (c.getParameterCount() == 1 && c.getParameterTypes()[0].equals(NavigationInfo.class)) {
                    return c.newInstance(navigationInfo);
                }
            }
            // no suitable constructor, just use default constructor as fallabck
            return type.getConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

现在只需按照通常的方式在每个 FXML 中定义 fx:controller 属性即可。例如。对于 Buy.fxml

<BorderPane ... fx:controller="com.yourcompany.yourproject.BuyController">

    <!-- ... -->
</BorderPane>

然后

public class BuyController {

    private final PageNavigationInfo navInfo ;

    public BuyController(NavigationInfo navigationInfo) {
        this.navInfo = navigationInfo.getInfoForPage("BuyPage");
    }

    @FXML
    private void initialize() {
        // do whatever you need with navInfo
    }
}