One controller to 2 fxmls (JavaFX) - javafx

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.

Related

How to use multiple viewmodels in single fragment in Android?

Let's say I have DashboadFragment which has its own ViewModel named DashboadViewModel. I have created separate layout for AutoCompleteTextView which is included in fragment_dashboard.xml file. I have created separate ViewModel for AutoCompleteTextView which is AutoCompleteTextViewViewModel. So here I have tried to observe the data which are typing in AutoCompleteTextView into DashboardFragment but it didn't worked.
I have recently started development in MVVM Pattern.
You can pass data between Fragment using the delegate viewModels
private val viewModel: ListViewModel by viewModels({requireParentFragment()})
it does mean that you will have in your dashboardFragment a AutoCompleteTextViewViewModel.
Another solution will be to use the setFragmentResult()API
See https://developer.android.com/guide/fragments/communicate#share_data_between_a_parent_and_child_fragment
and https://developer.android.com/guide/fragments/communicate#fragment-result for more informations

Java FXML Application: unsuccessful calling method in controller class from external class

Working on a Java FXML application called EVIF VideoRouter. Main class is then VideoRouter.java and the controller class is called VideoRouterFXMLController.java.
I have a method in the VideoRouterFXMLController.java class that I need to be able to call from other external classes within the application. Based on extensive searching and reading, I altered the FXML loader code in the main VideoRouter.java class to be thus:
FXMLLoader EVIFloader = new FXMLLoader(this.getClass().getResource("VideoRouterFXML.fxml"));
Parent EVIFroot = (Parent) EVIFloader.load();
VideoRouterFXMLController EVIFcontroller = EVIFloader.getController();
Now, as I understand this process, I'm somehow supposed to create a getter in the main VideoRouter.java class that returns the EVIFcontroller instance I've created above? And then I can use that getter in other classes and call the method inside the returned instance?
If so, I'm having difficulty figuring out where exactly to place the getter. Does it go in the controller class, or the main class? In either case it doesn't seem to be able to see the controller instance in order to return it.
Again, I've searched extensively and the related posts I've found to not appear to address this specific problem I'm having. Any help?
Many thanks in advance!
You have already partly answered your problem: create VideoRouterFXMLController member variable in your VideoRouter class and a getter to expose it, then set it to the controller instance after you load the FXML like in the code snippet your provided.
Having said that, I would propose a different approach to your problem because this approach is generally not a good design due to high coupling between your classes. I would recommend Observer pattern as an alternative approach and EventBus as a library to do this.

Java: GetResource from different folder

I am trying to make 3 folders in a Javafx application. I have a Views folder which will contain my views, and I want to load an fxml file saved inside Views. I wrote this code inside start method:
Parent root = FXMLLoader.load(getClass().getResource("/Views/ProductView.fxml"));
My folders are structured as follows:
Apparently GetResources() can't find my file. What am I doing wrong?
Problem is that loader cannot find fxml file ...
So, load method can be either empty or gets Inputstream argument.
And this should work:
FXMLLoader loader = new FXMLLoader();
FileInputStream fileInputStream = new FileInputStream(new File("src/main/java/CRUD/bnkseekCRUD.fxml"));
Parent root = loader.load(fileInputStream);
At least it works for me. )))
try something like this something like this
Parent root=FXMLLoader.load(getClass().getClassloader().getResource("application/Models/Views/ProductView.fxml")

JavaFX how to assign content to a child node UI controller

I have written the following code, where I assigned the MasterNode as a new treeView.
MasterDetailPane pane = new MasterDetailPane();
pane.setMasterNode(new TreeView());
pane.setDetailNode(new PropertySheet());
pane.setDetailSide(Side.BOTTOM);
pane.setShowDetailNode(true);
Now I want to populate and manipulate that TreeView programmatically. I think I need to do a pane.getMasterNode()..., but some how I should be able to access that controller and say something like,
pane.getMasterNode().setRoot(rootNode);
But I can't figure out how to get a hold of the controller, and get it cast as the right type of object in order to assign the rootNode. How to do I access that buried controller to assign a rootNode?
Okay, so I did figure it out. I'm just getting started in javafx, so bear with me. Simply casting the node to a tree view was all that was required to get the UI class back and make it accessible.
TreeView myTree = (TreeView) pane.getMasterNode();
myTree.setRoot(rootNode);
And it works as expected.

Javafx - Can application class be the controller class

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();

Resources