這可能是newb-swimming-upstream的一種情況,但是...在JavaFX-8中,是否可以將控制器動態添加到未使用FXML/FXMLLoader創建的節點?
在FXML文件中,其中一個屬性標識控制器。我假設控制器和標識的方法在加載期間與節點綁定(即,控制器實例被實例化並且其方法被綁定爲FXML中標識的監聽器)。
有沒有辦法通過程序將控制器實例與通過FXMLLoader創建的JavaFX節點(例如TableView)關聯起來?
這可能是newb-swimming-upstream的一種情況,但是...在JavaFX-8中,是否可以將控制器動態添加到未使用FXML/FXMLLoader創建的節點?
在FXML文件中,其中一個屬性標識控制器。我假設控制器和標識的方法在加載期間與節點綁定(即,控制器實例被實例化並且其方法被綁定爲FXML中標識的監聽器)。
有沒有辦法通過程序將控制器實例與通過FXMLLoader創建的JavaFX節點(例如TableView)關聯起來?
如果我理解正確,你想用Java代碼定義控制器實例,而不是讓FXMLLoader
實例化它。
在致電load()
之前,您可以致電setController
聯繫FXMLLoader
。請注意,這意味着你必須創建一個FXMLLoader
實例並調用實例load()
方法,絕不能叫靜態load(URL)
方法:
MyController controller = new MyController();
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
loader.setController(controller);
Parent root = loader.load();
如果你使用這個技術,你不得使用FXML文件的根元素中的fx:controller
屬性。
請注意,這使您能夠以任何喜歡的方式實例化控制器 - 例如,如果你有控制器類,它們具有帶參數的構造函數,你可以在這裏使用它們(默認機制使用的控制器必須有一個零參數構造函數)。
更先進,但相關信息:
相關技術,但也許更專業化的使用情況,是設置控制器工廠在FXMLLoader
。控制器工廠是將Class<?>
(由fx:controller
屬性定義的那個)映射到對象(控制器)的功能。這本質上使您可以對控制器實例化的方式進行編程控制(通常使用反射)。其中一個用途是如果你有一個模型類:
public class Model { /* ... */ }
和幾個不同的控制器類,將模型引用作爲構造器參數。通常情況下,您想要使用相同的模型實例並將其傳遞給所有控制器。所以,你可以定義一個控制器工廠如下:
Model model = new Model();
Callback<Class<?>, Object> controllerFactory = type -> {
try {
// look for a constructor with a single parameter of type Model:
for (Constructor<?> c : type.getConstructors) {
if (c.getParameterCount() == 1 && c.getParameterTypes()[0] == Model.class) {
return c.newInstance(model);
}
}
// no constructor found, just invoke no-arg constructor as in default:
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
然後你可以設置控制器工廠對你FXMLLoader
(S):
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
loader.setControllerFactory(controllerFactory);
Parent root = loader.load();
這項技術的另一個用途是結合依賴注入Spring和Guice等框架。如果您將DI框架配置爲爲您實例化控制器,並且可能將模型實例注入到它們中,則可以使用控制器工廠允許FXMLLoader
從框架中檢索控制器實例。例如。同春:
ApplicationContext context = ... ;
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
loader.setControllerFactory(context::getBean);
Parent root = loader.load();
或與吉斯:
Injector injector = Guice.createInjector(...);
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
loader.setControllerFactory(injector::getInstance);
Parent root = loader.load();
所以,這似乎是(A)我在GUI開發成爲新的結果,和(b)在使用JavaFX甚至更新。
的底線似乎是...
如果你要堅持在非FX方式使用JavaFX組件(即沒有FXML文件,沒有用FXMLLoader的),然後準備以非FX樣式註冊事件處理程序(在構造節點期間以程序方式添加它們)。
我還不清楚。我沒有使用FXMLLoader(即沒有FXML文件),只是手動滾動節點。 「明顯的答案」是「按照他們想要的方式使用FXML」,但我只是好奇地看看是否有其他方法。 這可能有點破解,但我注意到我可以簡單地在生成節點時實例化一個控制器實例,然後在將節點移交給調用者之前將事件處理程序註冊到節點上。 – SoCal
儘管做什麼?如果你在代碼中創建控件,我不明白你想要做什麼。編輯你的問題,包括一些代碼,說明你的意思。 –