Best Practices for managing JavaFX Screens

I tried a few approaches for managing "screens" from fxml centrally, but none was satisfactory to me. I tried implementing a dynamic registry, but searching through the classpath was too complicated for me. I tried having a public static method to load the scene, but that meant a lot of duplicated code for loading fxml and needlessly implemented methods that all do the same. My internal code quality metrics tell me that thats not a good solution either. So are there any libraries that i could look at or well known patterns that i could follow?
44 Replies
JavaBot
JavaBot2w ago
This post has been reserved for your question.
Hey @NeoCortex97! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically marked as dormant after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
stechy1
stechy12w ago
Hello, I've been trying to solve this issue for 5 years now and after that time I have come up with a custom made framework. I can post here a link but it is still in development and not sure when I will release some stable version. Most of the API I have should be stable, but from time to time I'm forced to introduce a breaking change...
NeoCortex97
NeoCortex97OP2w ago
I would be thankful if you would share a high level overview how it works.
JavaBot
JavaBot2w ago
If you are finished with your post, please close it. If you are not, please ignore this message. Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.
stechy1
stechy12w ago
I have a documentation for it, but it is also in progress... https://jfxsoft.gitlab.io/docs/getting_started/
Getting started - JFX soft - Documentation
Documentation for JFX soft framework
dan1st
dan1st2w ago
Can you elaborate on why you "need" to manage screens as opposed to creating one method capable of loading any given "screen" and calling that whenever you need that?
stechy1
stechy12w ago
From my personal experience it is simply not enough to have one simple static method for loading screens. Maybe for very simple applications with very few screens it would be enough. But for something more complex I think it makes sense to have a more robust solution...
dan1st
dan1st2w ago
What exactly is not sufficient for you I am sometimes using an abstract base class for controllers with custom init methods etc and then I more or less have static methods for loading (or in principle code generation is possible as well) but it depends on your exact requirements
stechy1
stechy12w ago
Years ago (Java 8 was new)I found a very nice tutorial on YouTube for very simple managing screens. It was able to switch one screen into another one. It was also supporting animations between transitions from one screen to another. But then I started building much more complex applications where I had screens built from other screens (single blocks) and then I realised it is not enough for me.
dan1st
dan1st2w ago
oh that's what you want to do yeah for that you need some sort of classpath scanning or code generation
stechy1
stechy12w ago
Form with a single button is not enough for business applications...
dan1st
dan1st2w ago
but you can do some very simple classpath scanning for that I assume you are using FXML for all your screens?
stechy1
stechy12w ago
Yep
dan1st
dan1st2w ago
Is it possible to create one folder (in your resources) where all of these FXML files are contained in and follow a naming convention such that no non-screen FXML files in that folder match the naming convention?
stechy1
stechy12w ago
Then I started thinking about how to separate business logic from the view. So I had to distinguish between the view controller (bound to a view) and the "form" controller which contains logic+ services for real stuff... Yeah, I have a single directory in resources for views. I went a bit further and separated views by logical part of the application Then I have prepared a lot of "standard" predefined views with some minimal logic. So for example a login dialog with validation would be quite easy to create...
dan1st
dan1st2w ago
You should be able to do something like
String folder = "/your/screens";
try(BufferedReader folderEntryReader = new BufferedReader(getClass().getClassLoader().getResourceAsStream(folder)){
List<String> fxmlResources = folderEntryReader.lines().filter(line -> line.endsWith(".fxml")).map(folderEntry -> folder+"/"+folderEntry).toList();
// ...
}
String folder = "/your/screens";
try(BufferedReader folderEntryReader = new BufferedReader(getClass().getClassLoader().getResourceAsStream(folder)){
List<String> fxmlResources = folderEntryReader.lines().filter(line -> line.endsWith(".fxml")).map(folderEntry -> folder+"/"+folderEntry).toList();
// ...
}
stechy1
stechy12w ago
And for resources, I got inspired by Android and have a plugin which discovers all resources and generates a class with paths to each resource so loading is also easy...
dan1st
dan1st2w ago
and then you can load the views and the controller with FXMLLoader normally and if you want to use some sort of dependency injection for the business logic, that's an option as well
stechy1
stechy12w ago
I could have resources placed in multiple java/maven modules so I have implemented a "discovery" process to allow load view from any module...
dan1st
dan1st2w ago
That's possible as well using things like the service loader API
stechy1
stechy12w ago
Yeah, that's what I'm using 😁
dan1st
dan1st2w ago
you can implement something where classes can register themselves and these classes then know where you can find the FXML files i.e. the classes know about the directories or just that if all modules use the same class loader
NeoCortex97
NeoCortex97OP2w ago
I need to build a framework that facilitates quickly building Applications for internal use. Our requirements are pretty specific so existing frameworks would not help too much. (Certification processes are bitches) I'll likely use Spring boot and services for it. Even if it seems overkill. But we need to evaluate spring for our backends anyways
dan1st
dan1st2w ago
What I said before still applies Also do you need to certify every single small library you are adding?
NeoCortex97
NeoCortex97OP2w ago
I likely will have to.
dan1st
dan1st2w ago
You can do simple classpath scanning without external libraries as I've shown before
NeoCortex97
NeoCortex97OP2w ago
I've tried this before, but it did not work too good.
dan1st
dan1st2w ago
What was the issue?
NeoCortex97
NeoCortex97OP2w ago
I had the problem that my library was inside it's own package and I had a registration step where I would pass a class to my library to search the entire package of that class, but only views contained in the same package like the library were found.
dan1st
dan1st2w ago
I think you called getClass() on a library object or used .class if you use .getClass().getClassLoader(), it should search from the classpath root
NeoCortex97
NeoCortex97OP2w ago
That's what I did
dan1st
dan1st2w ago
and the same should apply when the path starts with a / and that's why it happened by default, it uses the package of the class you can use getClassLoader() or start it with a /
NeoCortex97
NeoCortex97OP2w ago
Another weirdly mysterious Java detail 😅
dan1st
dan1st2w ago
it isn't that mysterious it's literally in the docs
NeoCortex97
NeoCortex97OP2w ago
I tried with getClassLoader() too, but it did not work as I expected. It showed me files that it wasn't supposed to find and did not find ones I wanted it to find. But maybe my code was shit.
dan1st
dan1st2w ago
Note: Class#getResourceAsStream doesn't work across modules I think and even for ClassLoader#getResourceAsStream, the package should be exported Are the packages exported to the library module?
NeoCortex97
NeoCortex97OP2w ago
Yes. But I would not trust my code in that case.
dan1st
dan1st2w ago
actually nvm it needs to be opened unconditionally not exports to but opens
NeoCortex97
NeoCortex97OP2w ago
Maybe that was the weird part. I exported them I'll go and try to whip something up so I can test. But I'd like to not close the thread for now.
dan1st
dan1st2w ago
otherwise if you have access to a Class, you can use the getResourceAsStream method on that Class with a leading / to accesses resources of that module that should also work without opening/exporting I think
dan1st
dan1st2w ago
Resources in named modules are subject to the encapsulation rules specified by Module.getResourceAsStream. Additionally, and except for the special case where the resource has a name ending with ".class", this method will only find resources in packages of named modules when the package is opened unconditionally (even if the caller of this method is in the same module as the resource).
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ClassLoader.html#getResource(java.lang.String)
ClassLoader (Java SE 21 & JDK 21)
declaration: module: java.base, package: java.lang, class: ClassLoader
dan1st
dan1st2w ago
actually the "opens" is also a requirement with Class#getResourceAsStream
Resources in named modules are subject to the rules for encapsulation specified in the Module getResourceAsStream method and so this method returns null when the resource is a non-".class" resource in a package that is not open to the caller's module.
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Class.html#getResourceAsStream(java.lang.String)
Class (Java SE 21 & JDK 21)
declaration: module: java.base, package: java.lang, class: Class
dan1st
dan1st2w ago
but for that, opens to is sufficient
JavaBot
JavaBot2w ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.

Did you find this page helpful?