JavaFX, FXML and controllers: switching scenes, maintaining scene data - java

Hello programmers and architects!
I'm new here and... I think my english could be... terrible! :-D
So... be careful with me... please.
I have an architectural question about JavaFX, FXML and the various methods to switch scenes, mantaining data among all scenes...
I have used a personal solution and I need to know if it's an acceptabile solution or not (at the architectural level).
I'll try to explain my solution.
I have used a sort of "inverse" of Observer Pattern: instead use many observers for each observable, I've used one observer (a specific Class) and many observables (all controllers).
So, when it's time to change scene, the Controller of the current scene notifies to Observer to do that. Observer removes old scene and loads the new one.
Some details.
I have created a class named SceneObserver that implements java.util.Observer.
I use SceneObserver in order to:
register SceneObserver as observer of all my controllers
load a specifc FXML file
create a new Scene with only an AnchorPanel as root element ad use the root.getChildren().add() method to append to the root element the loaded FXML
set a specific controller for the FXMLLoader (I have NOT used "fx:controller" inside the various FXML.)
All my Controllers extend java.util.Observable (this is an example).
When a certain type of situation happens in a scene and it's necessary to switch scene, the scene notifies to SceneObserver the change (Observer Pattern), SceneObserver destroys the old scene and loads the new one.
In other words I'm using only one observer to observe all controllers (the inverse of the Observe Pattern).
All works, but I know that this is not enough!
So, the question is: speaking at the architectural level, is this one an acceptabile solution?
I know, this is not the only one and surely there are others better ways, but... what about this one?
Why have I used this solution?
Well, two reasons:
load only necessary FXML (more rapid application)
leave controllers decoupled
Thanks to all and... sorry for my english :-(

Well...
after that I've read and tested different solutions, that I recommend to read:
https://web.archive.org/web/20160316234709/
https://blogs.oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx1
https://github.com/google/guava/wiki/EventBusExplained
http://eventbus.org/
I've decided to realize my own solution, using a more simple approach: a Router Pattern.
My goal was to decouple the various controllers in my JavaFX application, leaving possibility to communicate among their.
Instead to use event handler, parameters or obsolete event-bus, it seems that a simple Router Pattern can solve the issue.
Every controller must know the Router (obviously a singleton) and Router must know every controllers. In this way I have simply trasformed a many-to-many class relation to one-to-many without nothing of "too magic" and I can send every kind of messages among controllers. In the small:
In the Router I declare one property for each controller and a set method in order to link exactly that instance of controller, like this:
public class Router {
private MainCtrl mainCtrl;
...
protected void setMainCtrl(MainCtrl mainCtrl) {
this.mainCtrl = mainCtrl;
}
}
Then, in each controller I declare a Router object (router) and in the initialize() method of each controller I write this (router must be a singleton!):
public void initialize() {
router.setMainCtrl(this);
...
}
That's all.

Related

What is a nice way to bind buttons to model-methods through a controller in Java using Swing and MVC-pattern

I have tried to adhere to the mvc pattern in the java code that I have written. I want to keep the view and model independant of the controller and from each other. I am also trying my best to use interfaces to keep things modular.
My view has JButtons that I want to "bind" to specific methods in the model through the controller. I have tried two approaches to still keep the view independent of controller:
Registered the controller as an ActionListener to the view-object. Pros: The void addListener(ActionListener listener) abstract method encapsulates this behaviour in the view interface, so more buttons can be added without changing the interface. It also decouples the controller from the view, since it does not know anything about the actual buttons in the view. It is also easier to add more views or more controllers, so it follows the open-closed principle well. Con: For the controller to know the nature of the ActionEvent, I have only been able to come up with using the ActionEvent.getActionCommaned() in a switch statement, so mapping each case to its' corresponding method in the model. This seem unsafe and prone to cause irritation, since it seems like bad practice to match strings like this.
I also came up with adding public addActionListener(ActionListener) methods for each button in the view, like addGasButtonListener(ActionListener). Then doing something like view.addGasListener(e -> model.gasVehicles(view.getGasAmount())) in the controller. Pro: This seems like it reduces the uncertainty of matching strings. Cons: It means I have to add these new methods to the view interface, and each time a new button is added I have to do the same, making it difficult to add new views that does not have anything to do with some of the methods.
Main question:
I prefer the first method since it seems better to me, but I still would like to find a way to avoid matching strings, and find some nice way to do it (more similar to the rigidity of the second way of binding buttons to methdods). Is there?
Follow-up (less important) question:
I should also mention that my controller contains an inner class TimerListener implements ActionListener, that contains the loop of the app that acts on ActionEvents from the Timer. It also acts on ActionEvents from buttons if approach number one is used, which is why my follow-up question is: how would I seperate this main loop that only cares about the timer, from the switch statement used to act on button events. Since the ActionEvent.getActionCommand() is null almost all the time, it would be nice to seperate the two. Is there a approach that would let me do that?
I don't really see the value of working with ActionListener instances in the first place.
From your own example:
view.addGasListener(e -> model.gasVehicles(view.getGasAmount()))
You don't do anything with the actual event
In case you decide to use a different UI element in the future that doesn't fire ActionEvents, you will have to change the type of the listener.
I would rather expose a custom listener/callback that the controller (or model) can register on the view:
void onGasAmountChange(double gasAmount);
That being said, you might be focusing too hard on having a model, view and controller. If you look at more complicated Swing components (JList, JTable, ...), they have a view component and a model (ListModel and TableModel).
You could do something similar and create your own model for your view, and let the view call the necessary methods on the model directly (just like it happens for those Swing components).
That avoids having to write a bunch of one-liner listeners that basically delegate to the model.

(JavaFx) Proper way represent static FXML fields (and why this is a bad idea)

I would like to have a FXML field accessible from all classes. In a perfect world, I would just do this:
public class CanvasController {
#FXML
private static final AnchorPane canvas; // This is wrong
public static AnchorPane getCanvas() {
return canvas;
}
}
However, as explained by this similar question, static fields are a "terrible idea".
I'm designing a node editor, something like this:
I want to add a node, as a child of this AnchorPane, from anywhere in my project.
Am I wrong in wanting to do this? Why are static fields a bad idea, and how should I do this instead?
(The similar question recommends using a property, but JavaFx doesn't have a NodeProperty or AnchorPaneProperty).
This question is probably too opinion-based for this forum, but I think the opinions I'm expressing here are held widely enough for this to be acceptable.
Why are static fields a bad idea
Suppose you did what you are trying to do here, and it was allowed to work. Imagine your boss comes into your office in 6 months, and says something like "The customers love the application, but they want to be able to open multiple node editors at the same time. Can you make the application so they can open new windows, each with a node editor in?"
This kind of thing happens in real life all the time.
So in theory this should be easy. You have the FXML that defines the layout, and a controller than defines the logic associated with it. So all you need to do is have an event handler (say on a menu) that creates a new Stage and a Scene, loads the FXML again, and sets the root of the scene to the root of the FXML.
Except that it doesn't work. The problem is, you make the root pane static. So when you loaded the FMXL again, it replaced the current value of canvas with the new one from the newly-loaded FXML. If you now try to add new elements to the first canvas, you can't.
So now you have to refactor the code, so that canvas is an instance variable. Worse still, you publicly exposed it via the static getCanvas() method, which might have been called anywhere in your application. So you have to track down all those invocations. And you end up at 3am trying to grep your entire codebase to figure out what you have to change.
The problem (one problem) with making things static is that you commit to only ever having one copy of that variable, and essentially you commit to that for all time (or commit to rewriting much of the application if you change your mind). That decision leaks upwards: by only ever having one canvas, you can only ever have one controller, so you can only ever have one node editor. You have essentially prevented the code you have written from being reusable.
Your underlying assumption here is wrong. The static keyword really has nothing to do with accessibility: it is about scope. A static field is scoped to the class: a non-static field is scoped to each instance of that class. You made the field accessible by defining a public getCanvas() method and making the scope of that method - the class - available (by making the class public). If canvas is an instance variable, you can make it accessible by similarly defining a public getCanvas() method and making the scope of that method -- now the CanvasController instance -- available. So you load the FXML, retrieve the controller by calling getController() on the FXMLLoader, and pass the controller instance to whoever needs access to it. Notice now you have control in the code over who has received a reference to the controller, and if you need any refactoring you at least have a path to follow to find where the controller is used.
You mention "JavaFX doesn't have a NodeProperty or an AnchorPaneProperty: it has an ObjectProperty, so you can use an ObjectProperty<Node> or an ObjectProperty<AnchorPane> if you want/need.
In general, though, I think it's also a bad idea to expose view elements (like your canvas) outside of the controller, and even to share controllers with other parts of the application. You should instead consider using a MVC-type approach. What is missing from your question is the "M": the model. So your model would use an object model with classes like Image, Scale, Composite, etc. The classes should use JavaFX properties to make them observable and use ObservableList (and similar) to store collections of these objects and relationships among them. Create a single model instance and pass it to your controller. The controller can observe the data in the model and update the view if it changes, and update the model according to user input. Then share the model instance with the other parts of the application that need access to it. This keeps things more maintainable: if you decide, for example, canvas needs to be a Pane instead of an AnchorPane, that change is now confined to your FXML and controller, and doesn't leak out over the rest of your application. A (much simpler) example of MVC (really more MVP) in JavaFX is in this question.

What is all the "housekeeping" that has to be done in a FXML app?

I'm currently trying to convert a JavaFX app to a FXML app(work requirements), and I've been running in circles for a while now. I understand the basic principle (User interface and the backend workings defined separately), but all the hoop-jumping, technicalities, workarounds, all those initialize()s, loaders, start()s, launch()s, controllers, injections and whatnot are getting a bit over my head. The app in its current state spits out a compile time error that I couldn't divine anything out of if my life depended on it, but I vaguely suspect it leads somewhere into the underlying murk of the whole FXMLLoader thing.
This is no way to work. The tutorials only explain a part of it each, and my current modus operandi is still copying over/slightly modifying bits of code I find wherever and hoping it will work somehow, rather than actually understanding the principle and taking well-reasoned steps towards a clear goal. Is there a list of everything I need to do to make a FXML app work, or some clear explanation of how it all comes together?
Here's a list of things required to do in the order they are typically done:
Define UI in an FXML file (say ui.fxml)
Write a controller class for the given FXML which contains JavaFX fields with #FXML annotation, to be injected from the above FXML.
Go back to FXML file and add fx:controller="fullpackagename.ControllerName"
Implement public void initialize() if necessary. This will be called after injection. Mind the method signature, must be exactly the same.
Write an entry point, typically SomethingApp extends Application. In the overriden start() during Scene object construction pass the following as root node to the scene - FXMLLoader.load(getClass().getResource("ui.fxml")).
Here's a short working example. The example assumes you are familiar with the Maven directory structure. If not, then all 3 files, namely App, Controller, ui.fxml must be in the same package, for FXMLLoader to be able to locate it.

Swing MVC - Event Propogation and Data Sharing

I am trying to apply MVC pattern in swing application. However I am facing two major issues given that you have nested hierarchy of panel e.g. Parent -> Child - > Grand Child -> Grand Grand Child.
Issue 1: How to transfer the data between controller and view when you have such a hierarchy? If I go and pass data from parent to child then there will be lots of duplication and if I change one child all the parents will require change. I don't want views to directly access data from db and I want the data to be transferred to views through controller only.
Issue 2: How to propagate the events from view to controller in such a hierarchy?
I am thinking of using PropertyChangeListener. View will firePropertyChange event if any action has to be taken by controller. Controller will listen for these events and perform some action. But again if I do this for hierarchy then there will be code duplication.
I have three ideas that could be useful:
To use controller for each Panel but this in this way I will end up with lots of controllers.
Use Mediator design pattern that will provide the communication between views and controller.
Use a Central Reciever & Notifier that will listen for all property change event from views and will notify controllers who are interested. but this will only solve my second issue:
Please refer to below diagram to have a picture of 3rd idea. In case of 2nd one, Mediator will come in center.
Please evaluate and let me know if anyone has implemented such issue in a better way.
I have a suggestion for your issue 1:
You can have a ViewModel that contains a property of another View Model. And on your controller method you just need to receive the parent ViewModel because the model binder will bind all properties for you.
public class GrandChildViewModel{
public Int32 SelectedDropDownItem { get; set; }
public List<Foo> ListOfFoo { get; set; }
}
public class ChildViewModel{
public String Name { get; set; }
public Int32 Age { get; set; }
}
public class FatherViewModel{
public ChildViewModel Child { get; set; }
public GrandChildViewModel GrandChild { get; set; }
}
This is an example of the hierarchy. Your View will reference FatherViewModel only. And your controllers will receive FatherViewModel also.
The modelBinder will automatic do its job, if you create the HTML like:
#Html.TextBoxFor(m => m.Child.Name)
It will render the input:
<input type="text" id="Child_Name" name="Child_Name" />
Issue 1: How to transfer the data between controller and view when you
have such a hierarchy? If I go and pass data from parent to child then
there will be lots of duplication and if I change one child all the
parents will require change. I don't want views to directly access
data from db and I want the data to be transferred to views through
controller only.
How about ignoring the hierarchy and going for a more linear approach by registering views with a relevant controller ? The data could be had through a model from where changes would be triggered through an Observer or Listener pattern.
With this you won't have any duplication occurring. Everything would be centralized in a model or a series of models. The controller, or controllers could run a notify on a list of registered views after a user action or outside event has occured.
Also, views should definitely not access the data source as you say. There should be at least one layer of abstraction here. If your controller uses the mediator pattern what I'd do is handle this by forwarding requests to an interface in an extra data layer.
Thinking further, I don't think if it would be a good idea to have registration done through the view. So I'd keep this separate. Initialize views by hand or find a way to iterate through views that you need. Perhaps get your views through a kind of factory which automate this step.
Issue 2: How to propagate the events from view to controller in such a
hierarchy? I am thinking of using PropertyChangeListener. View will
firePropertyChange event if any action has to be taken by controller.
Controller will listen for these events and perform some action. But
again if I do this for hierarchy then there will be code duplication.
Again, you could adopt a linear approach. When a view is registered the Controller could add it's listeners to it. Or you could have the view send some semantic style messages (ex: doAction("Save")) which can be handled through a dispatch mechanism. Will leave you to decide how parameters could be forwarded.
Would PropertyChangeListeners be needed ? I mean, do you need that kind of granularity ?
I have three ideas that could be useful:
To use controller for each Panel but this in this way I will end up
with lots of controllers. Use Mediator design pattern that will
provide the communication between views and controller. Use a Central
Reciever & Notifier that will listen for all property change event
from views and will notify controllers who are interested. but this
will only solve my second issue:
This sounds vaguely like HMVC. With this approach you have triads of model-view-controller for each subsystem. It's an interesting idea but could be messy and it's not clear how the hierarchy is supposed to work out and how coordination/subordination is achieved.
Perhaps you could have a fourth neutral class for each module/subsystem of your app where you could plug in a view, model and controller with an Exception thrown if one of them is missing or incorrect.
Or, following this idea of a central notifier, you could have a central Controller acting as a routing mechanism to other feature-specific controllers or more elementary actions. How a message is rerouted to these is up to you. Watch out for threading as centralization will make the design of this class essential.
Whatever you do, try to make things as simple as possible. You should be able to have a test view with model and controller up without too much fuss.
I was facing similar issue when I ended up using this HMVC Pattern. Yes you are right in the sense that there will be lots of controller. But it is also true that it will provide you clear separation of concerns in the code. You can limit number of controllers by creating some application specific, high-level composite widgets. In this case, hierarchy can be limited upto 2 or 3 level at max and controllers can be chained to delegate events to any of the parent/child.
Once you load the data from server, you could also maintain Session map to get some relief to have quick and easy access to frequently required data - however I don't favor it much.
The pattern works quite well if the developments team understands and follows it properly.

java / gwt UI coding - clean code

i've started on some basic java coding with gwt, and im getting a bit concerned about the heft of my main class.
For instance - how does one compartmentalize the keyhandlers, since they trigger a number of changes to the UI, how could i move this into a separate .class file and still be able to access all the various widgets in the main class, without having to pass everything to the handler (ie. all the widgets i manipulate after the click event).
i've googled but didnt come across any particularly good examples - know of any readily legible code-bases i could read to see how it should be done? (gwt's own tuts are pretty basic, and just kitchen-sink every thing into a single file)
thanks!
I hate to say something so unimaginative, but MVC works--it's not the ultimate, but it can start getting you organized.
EDIT: While searching on a semi-related topic, I came across this which has similar ideas to mine but goes into more detail.
What that means in terms of GWT is that you should think of just laying out your GUI components in one class, put all your event handling in a second and put your object model objects separate from the other two.
One way to accomplish this is to make most or all the controls on your GUI public members. This sounds kind of lame, but their usage is encapsulated inside the controller so it's not like you have uncontrollable access--in fact your access is clearer/better defined than if all your members were private but your view code was combined with the controller.
Specific tricks:
Have listeners be their own class. You can often reuse them-- in other words, avoid anonymous inner classes. I sometimes create a listener class and instantiate a new instance for each button/control that needs to have a similar effect when pressed. If I need it to act slightly differently for a given button, I'll pass something into the constructor of the "special" handlers so that they know to act a little differently. You can also create different handler sub-classes if necessary--I'm just saying don't forget that event handlers are classes, you can use inheritance and everything if need be.
One Very Old GUI Trick I learned a long time ago, try not to have various mini-handlers modifying the GUI in different ways, instead have all the "active" buttons and controls set a state within your GUI and then call a single method that applies that state to ALL the controls on your GUI. When you get beyond a trivial GUI this can be a life-saver. If I'm not being clear, leave a comment and I'll leave an example for you.
Property sheets:
There is a special case for GUIs--the property sheet style GUI. I've done a LOT of these and they are irritating as HELL. They tend to have dozens or hundreds of controls on them, each GUI control tends to be tied to a specific field in your model and there are just hundreds of lines of copy and paste boilerplate code connecting them, each group copied and pasted with a few items changed--at minimum it's like 3 lines of code per control (Create control, copy value in and copy value out).
I always write these with a "Smart" controller--one that can intelligently bind the control to some data without any unique code. This can get tricky and if this is your problem let me know in the comments and I can give you some general advice as to some tricks you might try. I've gone from a minimal reflective solution to a full-on XML based solution. Were I to do it again, I might consider annotation-based.
Example of MVC:
Note, this is just an example, there are a MILLION ways to do MVC.
In your MAIN:
Instantiate MyView
Instantiate MyModel
Instantiate MyController(myView, myModel)
myView.setVisible(true)
in MyView
probably extends Frame
Most components are public final (public final Button b=new Button())
If public members make you nervous, use getters--same EXACT effect as public final members with a little extra syntax.
Remember that you can set final members in your constructor.
May have general methods such as reset(), but MyController may be a better place for this.
in MyController
saves references to myView and myModel
adds listeners to myView where necessary (see advice on listeners above)
configures myView based on state of myModel
when "done" button pressed, copies state from myView to myModel
notifies myModel that it's data has been updated and destroys itself.
in MyModel:
This would be a typical model class, it would contain your business logic (mostly not used as part of the GUI, that's more like GUI logic in MyController. The controller would tend to set values in your business logic then call some method like updated() to cause some business logic to take control. It should know nothing of a GUI--this is your "pure" business class.
Sometimes the GUI might call an update() or some other method to trigger some data change and then reload the GUI controls from the Model--this is a fairly good way to integrate your business logic with your GUI without your model knowing about the GUI...
Also, as I said above, I would put more work into MyController if I was working with property sheets just due to the sheer number of lines of boilerplate that you end up with if you aren't smart about it.
Note that View and Controller are nearly always paired. You can't just replace a Swing view with a web view and expect the controller to remain unmolested--but the model should not ever change for the view or controller.
You should take a look at the best practices for GWT applications first:
http://code.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html
One of the concepts they talk about is that of MVP (not MVC) to structure your application. There's a sample project on Google Code that you can look at to understand how to structure a GWT application in this way:
http://code.google.com/p/gwt-mvp/

Categories

Resources