I'm currently teaching myself JavaFX, and I've taken a simple example program that's hardcoded the view and am turning it into one that uses FXML (mostly so I can use SceneBuilder for building UIs). Rather than writing a separate controller class, I'm using the application class (so there's 1 Java file and 1 FXML file). I'm not using an initialize() method as it's a linear flow (display the UI, populate the fields, wait for input). The view pops up, but then the app errors out as none of the controls are mapped to the appropriate variables (so for #FXML TableView<...> table, table is null).
However, I put in an initialize() method for debugging, the controls are injected while in initialize(), and then return to null when initialize() exits.
So the question is, does JavaFX instantiate a new instance of the application class as a separate controller class? This would explain why the variable are going out of scope. Or is it something else (e.g. the controls are injected only when being called back from JavaFX actions)?
The default behavior of the FXMLLoader is to create a new instance of the controller class and use that instance as the controller.
Specifically, the FXMLLoader does something like:
Read the root FXML element.
If the root FXML element has a fx:controller attribute, then
If a controller already exists, throw an exception, otherwise create an instance of the specified class1 and set that as the controller
Continue parsing the FXML file. If elements have a fx:id attribute, and a controller exists (by any mechanism), inject those fields into the controller. Similarly register event handlers as calls to methods in the controller instance.
Invoke initialize() on the controller, if a controller exists and it has such a method.
So, the question you asked:
Can application class be the controller class
Yes, but it's probably a terrible idea. If you simply specify the Application subclass as the controller class using fx:controller, then a second instance of the Application subclass is created, #FXML-annotated fields are injected on that second instance, and the initialize() method is invoked on that second instance. Obviously, the #FXML-fields are never initialized on the instance on which start(...) is invoked, and the initialize() method is never invoked on that instance.
The question you probably meant is:
Can the application class instance created at launch be used as the controller?
The answer to this is also yes, and, aside from very small demo programs you intend to immediately discard, it's also probably a very bad idea. You would do this by
public class MyApp extends Application {
#FXML
private Node someNode ;
public void initialize() {
// do something with someNode
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file.fxml"));
loader.setController(this);
Parent root = loader.load();
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
Note that to use this code, your FXML file must not have a fx:controller attribute.
The problem with this is that you have no separation and no flexibility. (E.g. if you create a second instance of the view defined in your FXML file somewhere, you end up with a second Application subclass instance, which is at best counterintuitive (one application with two Application instances...).)
So I would advocate using a separate class for the controller in basically every case. The Application subclass should contain minimal code and should be used only for starting the application.
1 This step is actually a little more complex. If a class is specified in the fx:controller attribute, and no controller already exists, the FXMLLoader checks for a controllerFactory. If one exists, then the controller is set as the result of passing the specified Class to the controllerFactory's call() method, otherwise it is created by calling newInstance() on the specified class (effectively calling its no-argument constructor).
If you have defined your application class to be the controller in the FXML file, JavaFX will, if I remember correctly, create a new instance of your application class and use the new instance as a controller. Thus, your existing application class still has null for the table.
You can however define the controller programmatically in your application class to use your own instance:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("example.fxml"));
fxmlLoader.setController(this);
Parent root = (Parent)fxmlLoader.load();
Related
In a .Net Core 2.2 application, I need a version of a service as transient and a version as scoped.
For a "regular" service, I could create two different interfaces, register one as transient and one as scoped, but if both need a DbContext, it would mean I'd need to create two DbContext (yes, one can just be a wrapper) and register both, but it feels improper.
I'm using dotnet Core's default Dependency Injection framework, which I'm not that familiar with. In UnityIoC, I could easily have done that using named registrations:
//Note: Pseudo-code
void Register(IUnityContainer container)
{
container.RegisterType<IMyInterface, MyClass>(
"Transient",
new TransientLifetimeManager()
new InjectionConstructor(
new ResolvedParameter<MyDbContext>("Transient")));
container.RegisterType<IMyInterface, MyClass>(
"PerResolve",
new "PerResolve", new PerResolvedLifetimeManager()()
new InjectionConstructor(
new ResolvedParameter<MyDbContext>(PerResolve)));
container.RegisterType<MyDbContext>("Transient", new TransientLifetimeManager());
container.RegisterType<MyDbContext, MyClass>("PerResolve", new PerResolvedLifetimeManager());
}
Bonus points: Using the IServiceProvider, how do I ask for the transient resolution vs the scoped resolution?
The simplest way to implement this is with two interfaces as shown in the following example:
interface IMyScopedInterface
{
void Foo();
}
interface IMyTransientInterface
{
void Foo();
}
class MyClass : IMyTransientInterface, IMyScopedInterface
{
public MyClass(MyDbContext dbContext)
{
}
public void Foo()
{
}
}
and then register your class using the following:
services.AddTransient<IMyTransientInterface, MyClass>();
services.AddScoped<IMyScopedInterface, MyClass>();
You don't need to do anything special with your DbContext in order to support this. Let's walk through how the DI system would resolve these services to see if it can clarify why that's the case.
To start, the DI system tries to obtain an instance of IMyScopedInterface (typically because the DI system is trying to instantiate some other service whose constructor takes an IMyScopedInterface parameter).
Because IMyScopedInterface has been registered with a scoped lifetime, the DI system first looks within it's collection of services that have already been instantiated for the current scope to see if it has already created an IMyScopedInterface. That search comes up empty handed, so the DI system then moves on to create a new instance of MyClass.
To do that, it examines MyClass's constructor and determines that it needs a MyDbContext, so it recurses back through this same flow in order to obtain a MyDbContext.
The DI system constructs an instance of MyClass supplying the obtained MyDbContext, and then caches this MyClass object as part of the current scope so that subsequent requests for IMyScopedInterface within the same scope can receive the shared object.
The same basic flow holds true for IMyTransientInterface except that the DI system doesn't bother looking for a previously instantiated instance of the object, and after constructing the new MyClass instance it doesn't cache it at all.
What should hopefully be clear from this flow is that it doesn't really matter what the lifetime of MyDbContext is. If it's registered as transient, then every new instance of MyClass will get it's own unique instance of MyDbContext. If MyDbContext's lifetime is scoped (which is the default behavior in Entity Framework), then all instances of MyClass created within a given scope will share a single instance of MyDbContext regardless of whether the MyClass instances were instantiated for IMyScopedInterface or IMyTransientInterface.
In JavaFx, I understand that if I want a button to make some code run when it is clicked, I need to somehow have the code that I want to have run inside a method, and because this is Java, I wrap that method inside a class that extends EventHandler . For example:
// (myButton is a reference variable to a Button object)
myButton.setOnAction(new MyButtonEventHandlerClass() );
// inner class
public class MyButtonEventHandlerClass extends EventHandler<ActionEvent>{
public void handle(ActionEvent e) {
// (some code)
}
}
My confusion is: why is JavaFX designed to require me to make an instance of the class holding the handle() method? I had thought that non-static methods are used when the instance variables of an object are used; or in other words, if you just need a method that does not need an object, then you should use a static method. In this kind of thinking, handle() sounds like it should be a static method.
Why is handle() not a static method?
The criteria for a EventHandler to work in a meaningful way in this case are:
There needs to be some way to store the information.
The information has to be stored in a way that allows more than one way of dealing with a event.
Now regardless of the handle method actually using any fields in the EventHandlerand/or enclosing classes, there needs to be a way do identify the code that should handle the event.
If handle only was a static method, there only would ever be a single handler which even worse would be determined by the JavaFX programmers, since static methods cannot be overridden. It would not be possible to fulfil condition 2. without a non-static method.
For non-static methods however it's pretty simple to deal with this. Methods can be overridden and handling the event the correct way can simply be done by invoking EventHandler.handle for the event handler object.
In java 8 however method references (or lambda expressions) could be used to shorten this a bit by using method references, which allows you to "use a method as interface instance":
public class MyClass {
public static void handleMyButtonAction(ActionEvent evt) {
// (some code)
}
}
myButton.setOnAction(MyClass::handleMyButtonAction);
Is possible to connect two FXML (JavaFX) files to one controller?
I can't do this with changing "fx:controller" in each FXML file...
Any ideas?
Yes, you can do this. Although, it can be done, I do not recommend this approach.
Don't place a fx:controller attribute in either FXML. Create a new controller and set the same controller into separate FXMLLoader instances.
CustomerDialogController dialogController =
new CustomerDialogController(param1, param2);
FXMLLoader summaryloader = new FXMLLoader(
getClass().getResource(
"customerSummary.fxml"
)
);
summaryLoader.setController(dialogController);
Pane summaryPane = (Pane) summaryLoader.load();
FXMLLoader detailsLoader = new FXMLLoader(
getClass().getResource(
"customerDetails.fxml"
)
);
detailsLoader.setController(detailsController);
Pane detailsPane = (Pane) detailsLoader.load();
SplitPane splitPane = new SplitPane(
summaryPane,
detailsPane
);
I want to create one controller, because I have problem with sending data beetwen controlers
IMO using a shared controller just to share data is not the preferred solution for this.
Instead, either share the data between multiple controllers, for examples of this see:
Passing Parameters JavaFX FXML
There is a further example here:
JavaFX8 list bindings similar to xaml
Even better, see:
Applying MVC With JavaFx
https://edencoding.com/mvc-in-javafx/
Use the fx:root construct instead of fx:controller. It is explained in the Custom Components section of the FXML docs. I have used it in this example for my students if you want a bigger code example.
Using this approach, creating views and controllers will be a lot easier and flexible. You will be able to share data between and connect controllers like you would any other objects in your application (for example: by passing data via the constructor or setter methods).
If you're using SceneBuilder you'll simply need to remove the controller reference and check the box "Use fx:root". Then rework your code as shown in the examples.
I'm using EclipseLink on GlassFish 3.1.1 and I'm trying to understand this exception:
javax.ejb.EJBException: Illegal non-business method access on no-interface view
at org.mycompany.myproject.session.__EJB31_Generated__MyBeanFacade__Intf____Bean__.getEntityManager(Unknown Source)
at org.mycompany.myproject.session.AbstractFacade.edit(AbstractFacade.java:28)
at org.mycompany.myproject.controller.EditMyBeanServlet.doPost(EditMyBeanServlet.java:199)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
Notice that the stack trace indicates that the problem is triggered in the Netbeans generated AbstractFacade.getEntityManager method.
Any idea what the heck is going on or any tips to troubleshoot? I'm guessing that either the transaction or caching state in the EJB is weird when this happens because sometimes calling the edit method works fine. I'm calling the EJB methods from a Servlet. The exception occurs when trying to save changes to an entity.
The error you get most likely indicates that your code is trying to call the protected method anyway. This is not allowed for no-interface views on an EJB. You are only allowed to call public methods.
There's a small mismatch here between the normal Java class rules and the EJB rules. For a no-interface view, a proxy is created based on the original class type (typically a dynamic sub-class of it). This thus means that protected and package private methods are visible for code in the same package, and as far as the Java compiler is concerned, your code is allowed to call those.
But as mentioned, this is not allowed by the EJB rules, and thus an exception is thrown.
You can reproduce this easily by injection a bean like the following:
#Stateless
public class FooBean {
public void callMe() {
}
protected void doNotCallMe() {
}
}
Inject this somewhere (e.g. Servlet in same package) and try to call doNotCallMe(). You'll see the same exception. Call callMe() and everything will be fine.
I think I may have found a solution and possibly a bug in third party software. It seems like GlassFish 3.1.1 / EJB 3.1 / EclipseLink can't handle method overloading correctly. I've got a method defined in my EJB named edit that overloads (not overrides) the method from the parent abstract class. There is a method named edit in the abstract parent of the EJB that takes a generic type and then I've got a method named edit in the EJB which takes a List. If I rename the method to something else so that it is no longer overloading then the exception goes away!
Code:
public abstract class AbstractFacade<T> {
protected abstract EntityManager getEntityManager();
public void edit(T entity) {
...
and
#Stateless
public class MyEntityFacade extends AbstractFacade<MyEntity> {
protected EntityManager getEntityManager() { return em; )
public void edit(List<MyEntity> entities) {
...
Note: I noticed if I make the getEntityManager method public instead of protected I'll get a TransactionRequiredException instead of an EJBException.
What is weird is i had same problme with on inner class of my EJB.
While trying to call private method of parent or accessing on injected EJB, i faced some problems.
I had visibility on most of things but finally a runtie, things goes wrong.
Finally, i decided to retrieve my parent class throught JNDI, thus i could call public method without troubles. Meanwhile i could call still private methods on my parents class, i still have to remember that it will fail.
I have a class called CommunicationManager which is responsible for communication with server.
It includes methods login() and onLoginResponse(). In case of user login the method login() has to be called and when the server responds the method onLoginResponse() is executed.
What I want to do is to bind actions with user interface. In the GUI class I created an instance of CommunicationManager called mCommunicationManager. From GUI class the login() method is simply called by the line
mCommunicationManager.login();
What I don't know how to do is binding the method from GUI class to onLoginResponse(). For example if the GUI class includes the method notifyUser() which displays the message received from theserver.
I would really appreciate if anyone could show how to bind methods in order to execute the method from GUI class (ex. GUI.notifyUser()) when the instance of the class mCommunicationManager receives the message from the server and the method CommunicationManager.onLoginResponse() is executed.
Thanks!
There's two patterns here I can see you using. One is the publish/subscribe or observer pattern mentioned by Pete. I think this is probably what you want, but seeing as the question mentions binding a method for later execution, I thought I should mention the Command pattern.
The Command pattern is basically a work-around for the fact that java does not treat methods (functions) as first class objects and it's thus impossible to pass them around. Instead, you create an interface that can be passed around and that encapsulates the necessary information about how to call the original method.
So for your example:
interface Command {
public void execute();
}
and you then pass in an instance of this command when you execute the login() function (untested, I always forget how to get anonymous classes right):
final GUI target = this;
command = new Command() {
#Override
public void execute() {
target.notifyUser();
}
};
mCommunicationManager.login(command);
And in the login() function (manager saves reference to command):
public void login() {
command.execute();
}
edit:
I should probably mention that, while this is the general explanation of how it works, in Java there is already some plumbing for this purpose, namely the ActionListener and related classes (actionPerformed() is basically the execute() in Command). These are mostly intended to be used with the AWT and/or Swing classes though, and thus have features specific to that use case.
The idiom used in Java to achieve callback behaviour is Listeners. Construct an interface with methods for the events you want, have a mechanism for registering listener object with the source of the events. When an event occurs, call the corresponding method on each registered listener. This is a common pattern for AWT and Swing events; for a randomly chosen example see FocusListener and the corresponding FocusEvent object.
Note that all the events in Java AWT and Swing inherit ultimately from EventObject, and the convention is to call the listener SomethingListener and the event SomethingEvent. Although you can get away with naming your code whatever you like, it's easier to maintain code which sticks with the conventions of the platform.
As far as I know Java does not support method binding or delegates like C# does.
You may have to implement this via Interfaces (e.g. like Command listener.).
Maybe this website will be helpful:
http://www.javaworld.com/javaworld/javatips/jw-javatip10.html
You can look at the swt-snippets (look at the listeners)
http://www.eclipse.org/swt/snippets/
or you use the runnable class , by overwritting the run method with your 'callback'-code when you create an instance