今天我将Guice添加到我的Java FX应用程序中。主要目标是用注入替换我的单例并打破依赖关系。 到目前为止一切正常,这是我必须开始一个新场景的代码:
public class App extends Application{
public static void main(String[] args){
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
final String LANGUAGE_BUNDLE = "myBundlePath";
final String FXML = "myFXMLPath";
try {
ResourceBundle resourceBundle = ResourceBundle.getBundle(LANGUAGE_BUNDLE, Locale.GERMAN, this.getClass().getClassLoader());
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(FXML), resourceBundle, new JavaFXBuilderFactory(), getGuiceControllerFactory());
primaryStage.setScene(new Scene(fxmlLoader.load()));
primaryStage.show();
}catch (IOException ex) {
ex.printStackTrace();
}
}
private Callback<Class<?>, Object> getGuiceControllerFactory(){
Injector injector = Guice.createInjector(new GuiceModule());
return new Callback<Class<?>, Object>() {
@Override
public Object call(Class<?> clazz) {
return injector.getInstance(clazz);
}
};
}
}
我的Guice模块看起来像这样:
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
bind(ITester.class).to(Tester.class);
bind(ISecondTest.class).to(SecondTest.class);
}
}
请注意,我替换了ressource包和fxml文件的路径,因为它们会显示我的身份。但加载和一切都有效,所以这不应该是一个问题;)
现在问题是,我想在不同的视图中点击按钮来实例化一个新视图。第二个视图应在视图1中显示更详细的数据版本。 我需要传递给第二个视图的所有东西都是Integer(或int),但我完全不知道如何做到这一点。
我有标准的FX设置:
View.fxml (with a reference to the ViewController)
ViewController.java
Model.java
ViewModel.java
ViewController
然后绑定到ViewModel
提供的属性。
我需要int来选择正确的模型。
我能找到的一切都是关于注释@Named
但是据我所知,这对于注入动态数据是不可用的。
你能不能给我一个提示,告诉我这个我想要做的是什么?
或者长话短说:如何在第二个ViewController
中注入一个由不同视图选择的变量,并将其余部分留在标准的FX方式中?
任何帮助表示感谢并提前致谢!
此致,基督徒
答案 0 :(得分:3)
在尝试了一下之后,似乎我自己找到了解决方案! 然而,它“感觉”我正在做的很难看,所以我想要一些确认;)
首先理论:Guice支持“AssistedInject”。这是,当一个类不能由默认构造函数构造时。为了能够使用AssistedInject,您必须下载扩展名(我从maven repository下载了jar)。
AssistedInject为您做的是它允许您指定为您构建变量的工厂。所以这就是我所做的:
首先,为我稍后要使用的类创建一个接口,在我的例子中:
public interface IViewController {
}
其次,为工厂创建一个界面。重要提示:您不必实施工厂
public interface IControllerFactory {
ViewController create(@Assisted int myInt);
}
第三,将带有相应参数的构造函数添加到您希望稍后实例化的类,并让它实现您创建的接口,如下所示:
public class ViewController implements IViewController{
@AssistedInject
public ViewController(@Assisted int i){
final String LANGUAGE_BUNDLE = "languageBundle";
final String FXML = "View.fxml";
try{
ResourceBundle resourceBundle = ResourceBundle.getBundle(LANGUAGE_BUNDLE, Locale.GERMAN, this.getClass().getClassLoader());
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(FXML), resourceBundle, new JavaFXBuilderFactory());
fxmlLoader.setController(this);
Stage second = new Stage();
second.setScene(new Scene(fxmlLoader.load()));
second.show();
}catch (IOException e){
e.printStackTrace();
}
System.out.println("ViewController constructor called with: " + i);
}
以下是一些需要注意的事项:
接下来,我们需要在我们想要实例化另一个类的类中添加一个变量:
@Inject
IControllerFactory controllerFactory;
我们可以在课堂上使用它:
controllerFactory.create(3)
注意:我们调用我们从未在ViewController类中实现的方法“create”! Guice知道它必须调用构造函数 - magic
作为最后一步,我们需要在GuiceModule中添加与上下文的连接,如下所示:
@Override
protected void configure(){
install(new FactoryModuleBuilder()
.implement(IPagingDirectoryViewController.class, PagingDirectoryViewController.class)
.build(IPagingDirectoryControllerFactory.class));
}
注意我收到了错误:无法解析方法'实现java.lang.Class&lt;“接口类”&gt ;, java.lang.Class&lt;“实现类”&gt;'。这是因为我忘了让我的Controller类实现接口。
好的,这就是我如何运作的。 正如我所说,我对某些意见感到非常高兴!
此致,基督徒
答案 1 :(得分:2)
在您的模块配置中,您只需为FXMLLoader添加一个提供者方法,您可以在其中指定Guices&#39; injector.getInstance()&#39;作为装载程序的ControllerFactory。
@Provides
public FXMLLoader getFXMLLoader(com.google.inject.Injector injector) {
FXMLLoader loader = new FXMLLoader();
loader.setControllerFactory(injector::getInstance);
return loader;
}
您现在要做的就是在模块配置的configure()方法中绑定ViewControllers。
// for example:
bind(ViewController.class);
确保控制器类正确绑定在fxml文件中。
fx:controller="your.package.ViewController"
现在您只需使用您的注入器来获取FXMLLoader的实例。