Probably I miss somehting out, but I'm struggeling to find a solution how I can pass dependencies like an instance of my event bus and some service interfaces to my javafx application.
I got an UI-Init class which does not much more than starting the application and receiving some dependencies for the UI like an eventBus:
public class Frontend {
public Frontend(MBassador<EventBase> eventBus) {
Application.launch(AppGui.class);
}
My AppGui class extends Application and loads an FXML:
public class AppGui extends Application {
private Stage primaryStage;
private GridPane rootLayout;
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("RootLayout.fxml"));
rootLayout = (GridPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
scene.setFill(null);
primaryStage.setScene(scene);
RootLayoutController rootController = loader.getController();
rootController.init(/*here I would like to inject my eventBus*/);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
Now, how can I pass my eventBus and other service interfaces to this controller? I've read about using DI frameworks like guice (How can JavaFX controllers access other services?) or afterburner.fx to use it. But even if I use guice for the rest of my application, somehow I need to pass the Injector instance to the JavaFX application?.
But Application.launch(AppGui.class); is static and internally creates an AppGui instance on the javafx thread, which I don't get access to. So how I can inject dependencies to my AppGui object without using static variables?
Here is what I do:
The Application class has a couple of lifecycle callbacks, init() and stop().
From the Javadocs:
public void init() throws java.lang.Exception
The application initialization method. This method is called immediately after the Application class is loaded and constructed. An application may override this method to perform initialization prior to the actual starting of the application.
public void stop() throws java.lang.Exception
This method is called when the application should stop, and provides a convenient place to prepare for application exit and destroy resources.
Also from the Javadocs, the lifecycle:
Constructs an instance of the specified Application class
Calls the init() method
Calls the start(javafx.stage.Stage) method
Waits for the application to finish, which happens when either of the following occur:
the application calls Platform.exit()
the last window has been closed and the implicitExit attribute on Platform is true
Calls the stop() method
I start the IoC container in init() and stop it in stop(). Now my Application class has a reference to the IoC container and can supply the first controller with its dependencies.
As a matter of fact, I let the IoC framework manage the controllers. I set them to the loaded FXML using FXMLLoader.setController(), instead of specifying them with fx:controller.
You can pass a static reference to your application class before you call launch(). Something like:
public class Frontend {
public Frontend(MBassador<EventBase> eventBus) {
AppGui.setEventBus(eventBus);
Application.launch(AppGui.class);
}
}
public class AppGui extends Application {
private static MBassador<EventBase> eventBus;
public static void setEventBus(MBassador<EventBase> eventBus) {
this.eventBus = eventBus;
}
private MBassador<EventBase> eventBus;
#Override
public void init() {
if (AppGui.eventBus == null) {
throw new IllegalStateException();
// or however you want to handle that state
} else {
this.eventBus = AppGui.eventBus;
AppGui.eventBus = null;
}
}
}
Whether you keep and use the static reference, or you copy the static reference to a local reference is up to you and the design of your application. If you expect to instantiate more than one copy of AppGui, you may need the local reference.
No idea if this is thread safe (probably not). The advice from #Nikos and #James_D is solid and preferred... but sometimes you just need a hack. :) YMMV
Related
I have a Quarkus app which runs a servlet and I'm trying to inject an Agroal datasource as there is a Thread which runs within the servlet where I need to do some database transactions. However, I've tried the below implementation inside the Thread class as well and another static class which is utilized inside the thread, but in both classes the datasource returns null.
I've added the datasource properties in the application.properties file as well. Also the servlet is set to load on startup, Hence as soon as the application is run, the thread starts as well. This thread starts after the servlet is initialized.
class LoopThread extends Thread {
#Inject
#Named("db")
AgroalDataSource datasource;
public LoopThread() {
super();
}
#Override
public void run() {
try {
DbUtil.userErrorLogged = false;
DbUtil.initDataSource(datasource);
LogUtil.debug("Thread started.");
catch (Exception ex) {
LogUtil.error(ex);
}
}
}
I have tried to inject the datasource in the Thread class and also in the static Util class but both did not return the datasource. I'm thinking whether it is due to the thread which is started as the servlet is initialized. Any help on this would be great
I set up multiple custom controllers during the creation of an app and would need some help in organizing these controllers with setControllerFactory in JavaFX.
I'm fairly inexperienced with JavaFX but invested quite some time in creating a small app with Scenebuilder and JavaFX.
Background of the app
The app consists of:
- a map (implemented as an imageView)
- a sidebar with buttons and icons for drag and drop events.
- the map also has separate layers as the target for the drag and drop of different icon types.
As a prototype of my drag and drop event I used the instructions of Joel Graff (https://monograff76.wordpress.com/2015/02/17/developing-a-drag-and-drop-ui-in-javafx-part-i-skeleton-application/). He writes "in order for an object to be visible beyond a container’s edges, it must be a child of a parent or other ancestral container – it must belong to a higher level of the hierarchy. In the case of our drag-over icon, this means we had to add it as a child to the RootLayout’s top-level AnchorPane." and he uses dynamic roots for his project.
To teach myself how to use custom control with FXML I used Irina Fedortsova's tutorial https://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm.
And to learn how to set up multiple screens I used the video https://www.youtube.com/watch?v=5GsdaZWDcdY and associating code from https://github.com/acaicedo/JFX-MultiScreen.
After building my app the logic tier of my app got more and more entangled with the presentation tier, and I feel as if my code would benefit greatly from some refactoring.
My problem seems to be a lack in the understanding of the load and initialize process of controller classes. Since the drag icons and the RootLayout have to be loaded from the beginning, it is a mystery to me how I can load these classes in a way that I can call them again at a later time.
When I was looking for further solutions, I repeatedly came across the method setControllerFactory. Unfortunately I can't find a good explanation for how to use it properly and what it's specific purpose is.
The only tutorial I found was: https://riptutorial.com/javafx/example/8805/passing-parameters-to-fxml---using-a-controllerfactory, unfortunately it seems to be a bit insufficient for my purpose.
I feel as if I would benefit the most from a methode/class with which I could organize all my custom controllers, load and initialize them at the appropriate time and then later access them again (similar to the interface and superclass in the video for JFX-MultiScreen).
I repeatedly came across the method setControllerFactory. Unfortunately I can't find a good explanation for how to use it properly and what it's specific purpose is
By default, the FXMLLoader.load() method instantiates the controller named in the fxml document using the 0-arg constructor. The FXMLLoader.setControllerFactory method is used when you want your FXMLLoader object to instantiate controllers in a certain way, e.g. use a different controller constructor on specific arguments, call a method on the controller before it's returned, etc, as in
FXMLLoader loader = new FXMLLoader(...);
loader.setControllerFactory(c -> {
return new MyController("foo", "bar");
});
Now when you call loader.load() the controller will be created as above. However, calling the FXMLLoader.setController method on a preexisting controller may be easier.
I feel as if I would benefit the most from a methode/class with which I could organize all my custom controllers, load and initialize them at the appropriate time and then later access them again
When I first came across this problem, as you have, I tried and retried many approaches. What I finally settled on was turning my main application class into a singleton. The singleton pattern is great when you need to create one instance of a class which should be accessible throughout your program. I know there are many people who will take issue with that (in that it's essentially a global variable with added structure), but I've found that it reduced complexity significantly in that I no longer had to manage a somewhat artificial structure of object references going every which way.
The singleton lets controllers communicate with your main application class by calling, for example, MyApp.getSingleton(). Still in the main application class, you can then organize all of your views in a private HashMap and add public add(...), remove(...), and activate(...) methods which can add or remove views from the map or activate a view in the map (i.e. set the scene's root to your new view).
For an application with many views that may be placed in different packages, you can organize their locations with an enum:
public enum View {
LOGIN("login/Login.fxml"),
NEW_USER("register/NewUser.fxml"),
USER_HOME("user/UserHome.fxml"),
ADMIN_HOME("admin/AdminHome.fxml");
public final String location;
View(String location) {
this.location = "/views/" + location;
}
}
Below is an example of the main application class:
public final class MyApp extends Application {
// Singleton
private static MyApp singleton;
public MyApp() { singleton = this; }
public static MyApp getSingleton() { return singleton; }
// Main window
private Stage stage;
private Map<View, Parent> parents = new HashMap<>();
#Override
public void start(Stage primaryStage) {
stage = primaryStage;
stage.setTitle("My App");
add(View.LOGIN);
stage.setScene(new Scene(parents.get(View.LOGIN)));
stage.show();
}
public void add(View view) {
var loader = new FXMLLoader(getClass().getResource(view.location));
try {
Parent root = loader.load();
parents.put(view, root);
} catch (IOException e) { /* Do something */ }
}
public void remove(View view) {
parents.remove(view);
}
public void activate(View view) {
stage.getScene().setRoot(parents.get(view));
}
public void removeAllAndActivate(View view) {
parents.clear();
add(view);
activate(view);
}
}
If you have application-wide resources you can put them in the app class and add getters/setters so your controllers can access them. Here is an example controller class:
public final class Login implements Initializable {
MyApp app = MyApp.getSingleton();
// Some #FXML variables here..
#FXML private void login() {
// Authenticate..
app.removeAllAndActivate(View.USER_HOME);
}
#FXML private void createAccount() {
app.add(View.NEW_USER);
app.activate(View.NEW_USER);
}
#Override
public void initialize(URL url, ResourceBundle rb) {}
}
When using spring-data-rest there is a post processing of Resource classes returned from Controllers (e.g. RepositoryRestControllers). The proper ResourceProcessor is called in the post processing.
The class responsible for this is ResourceProcessorHandlerMethodReturnValueHandler which is part of spring-hateoas.
I now have a project that only uses spring-hateoas and I wonder how to configure ResourceProcessorHandlerMethodReturnValueHandler in such a scenario. It looks like the auto configuration part of it still resides in spring-data-rest.
Any hints on how to enable ResourceProcessorHandlerMethodReturnValueHandler in a spring-hateoas context?
I've been looking at this recently too, and documentation on how to achieve this is non-existent. If you create a bean of type ResourceProcessorInvokingHandlerAdapter, you seem to lose the the auto-configured RequestMappingHandlerAdapter and all its features. As such, I wanted to avoid using this bean or losing the WebMvcAutoConfiguration, since all I really wanted was the ResourceProcessorHandlerMethodReturnValueHandler.
You can't just add a ResourceProcessorHandlerMethodReturnValueHandler via WebMvcConfigurer.addReturnValueHandlers, because what we need to do is actually override the entire list, as is what happens in ResourceProcessorInvokingHandlerAdapter.afterPropertiesSet:
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
// Retrieve actual handlers to use as delegate
HandlerMethodReturnValueHandlerComposite oldHandlers = getReturnValueHandlersComposite();
// Set up ResourceProcessingHandlerMethodResolver to delegate to originally configured ones
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<HandlerMethodReturnValueHandler>();
newHandlers.add(new ResourceProcessorHandlerMethodReturnValueHandler(oldHandlers, invoker));
// Configure the new handler to be used
this.setReturnValueHandlers(newHandlers);
}
So, without a better solution available, I added a BeanPostProcessor to handle setting the List of handlers on an existing RequestMappingHandlerAdapter:
#Component
#RequiredArgsConstructor
#ConditionalOnBean(ResourceProcessor.class)
public class ResourceProcessorHandlerMethodReturnValueHandlerConfigurer implements BeanPostProcessor {
private final Collection<ResourceProcessor<?>> resourceProcessors;
#Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
RequestMappingHandlerAdapter requestMappingHandlerAdapter = (RequestMappingHandlerAdapter) bean;
List<HandlerMethodReturnValueHandler> handlers =
requestMappingHandlerAdapter.getReturnValueHandlers();
HandlerMethodReturnValueHandlerComposite delegate =
handlers instanceof HandlerMethodReturnValueHandlerComposite ?
(HandlerMethodReturnValueHandlerComposite) handlers :
new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
requestMappingHandlerAdapter.setReturnValueHandlers(Arrays.asList(
new ResourceProcessorHandlerMethodReturnValueHandler(delegate,
new ResourceProcessorInvoker(resourceProcessors))));
return requestMappingHandlerAdapter;
}
else return bean;
}
}
This has seemed to work so far...
The new obsolete warning in Xamarin.Forms 2.5 really puzzled me.
What context should I be using in Dependency Services, for example, to call GetSystemService()?
Should I store in a static field the context of activity the xamarin forms were initialized against?
Should I override the android Application class and use its Context?
Should I call GetSystemService at activity create and save it somewhere?
I was having the same issue with several Dependency Services
The simplest solution
In a lot of cases for Single Activity Applications
Xamarin.Forms.Forms.Context
Can be replaced with
Android.App.Application.Context
The Background in more detail
Android.App.Application.Context returns the global Application Context of the current process tied to the lifecycle of the Application, as apposed to an Activity context.
A typical example of using the Application context is for starting an Activity e.g.
Android.App.Application.Context.StartActivity(myIntent);
The general rule of thumb is to use the current Activity Context, unless you need
to save a reference to a context from an object that lives beyond your
Activity. In which case use the Application context
Why did Forms.Context go obsolete?
Xmarin.Forms 2.5 introduced a new "Forms embedding" feature, which can embed Forms pages into Xamarin.iOS / Xamarin.Android apps. However, since Xamarin.Android apps can use multiple Activities, seemingly there was a danger of Xamarin.Android users calling Forms.Context and in turn getting a reference to the MainActivity, which has the potential cause problems.
The work around
Inside a Renderer you now get a reference to the view’s context which is passed into the constructor.
With any other class you are faced with the issue of how to get the Activity Context. In a single Activity application (in most cases) the Application.Context will work just fine.
However to get the current Activity Context in a Multiple Activity Application you will need to hold a reference to it. The easiest and most reliable way to do this is via a class that implements the Application.IActivityLifecycleCallbacks Interface.
The main idea is to keep a reference of the Context when an Activity
is created, started, or resumed.
[Application]
public partial class MainApplication : Application, Application.IActivityLifecycleCallbacks
{
internal static Context ActivityContext { get; private set; }
public MainApplication(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) { }
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
ActivityContext = activity;
}
public void OnActivityResumed(Activity activity)
{
ActivityContext = activity;
}
public void OnActivityStarted(Activity activity)
{
ActivityContext = activity;
}
public void OnActivityDestroyed(Activity activity) { }
public void OnActivityPaused(Activity activity) { }
public void OnActivitySaveInstanceState(Activity activity, Bundle outState) { }
public void OnActivityStopped(Activity activity) { }
}
With the above approach, single Activity Applications and multiple Activity Applications can now always have access to the Current/Local Activity Context. e.g instead of relying on the global context
Android.App.Application.Context
// or previously
Xamarin.Forms.Forms.Context
Can now be replaced with
MainApplication.ActivityContext
Example call in a Dependency Service
if (MainApplication.ActivityContext!= null)
{
versionNumber = MainApplication.ActivityContext
.PackageManager
.GetPackageInfo(MainApplication.ActivityContext.PackageName, 0)
.VersionName;
}
Additional Resources
Android.App.Application.IActivityLifecycleCallbacks
registerActivityLifecycleCallbacks
In the latest scaffold of a new Xamarin Forms solution the CrossActivityPlugin (https://github.com/jamesmontemagno/CurrentActivityPlugin) is referenced in the Android project. So you can use
CrossCurrentActivity.Current.Activity.StartActivity(myIntent)
I want to use Netbeans Java FX with Scene builder for a measurement application. I have designed a scene with controls. I can handle the events from the UI-controls within the '...Controller.java'.
The 'controller' is the standard piece of code that is referenced in the XML file and gets initialized by the system with:
public void initialize(URL url, ResourceBundle rb) { ..
My problem: how do I access my central, persisting, 'model' objects from within the controller? Or, to be more exact, from the event handlers created within the controller initialize function.
The 'model' object would be created within the application object.
The solution must be trivial, but I have not found a way to
either access the Application from the controller
or access the controller from within the Application.
What am I missing?
(the next question would be how to access the tree of panes within the object hierarchy created by screen builder, e.g. for graphics manipulation on output. Since the objects are not created by own code I can not store references to some of them. Ok, they could perhaps be found and referenced by tree-walking, but there must be a better way!)
Thanks for all insights!
I have used the 2nd approach (access the controller from within the Application) for awhile ago similar to following. In Application class:
//..
private FooController fooController;
private Pane fooPage;
private Model myModel;
#Override
public void start(Stage stage) {
//..
myModel = new Model();
getFooController().updateModel(myModel);
//..
Button button = new Button("Update model with new one");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Model myNewModel = new Model();
getFooController().updateModel(myNewModel);
}
}
// create scene, add fooPage to it and show.
}
private FooController getFooController() {
if (fooController == null) {
FXMLLoader fxmlLoader = new FXMLLoader();
fooPage = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
fooController = (FooController) fxmlLoader.getController();
}
return fooController;
}
Actually the first and second parts of your question is answered JavaFX 2.0 + FXML. Updating scene values from a different Task to the similar question of yours.