2016-04-21 33 views
0

這可能是newb-swimming-upstream的一種情況,但是...在JavaFX-8中,是否可以將控制器動態添加到未使用FXML/FXMLLoader創建的節點?

在FXML文件中,其中一個屬性標識控制器。我假設控制器和標識的方法在加載期間與節點綁定(即,控制器實例被實例化並且其方法被綁定爲FXML中標識的監聽器)。

有沒有辦法通過程序將控制器實例與通過FXMLLoader創建的JavaFX節點(例如TableView)關聯起來?

回答

1

如果我理解正確,你想用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(); 
+0

我還不清楚。我沒有使用FXMLLoader(即沒有FXML文件),只是手動滾動節點。 「明顯的答案」是「按照他們想要的方式使用FXML」,但我只是好奇地看看是否有其他方法。 這可能有點破解,但我注意到我可以簡單地在生成節點時實例化一個控制器實例,然後在將節點移交給調用者之前將事件處理程序註冊到節點上。 – SoCal

+0

儘管做什麼?如果你在代碼中創建控件,我不明白你想要做什麼。編輯你的問題,包括一些代碼,說明你的意思。 –

0

所以,這似乎是(A)我在GUI開發成爲新的結果,和(b)在使用JavaFX甚至更新。

的底線似乎是...

如果你要堅持在非FX方式使用JavaFX組件(即沒有FXML文件,沒有用FXMLLoader的),然後準備以非FX樣式註冊事件處理程序(在構造節點期間以程序方式添加它們)。

相關問題