如何将此 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
}
}
我研究了很多 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
}
}