I'm already using Guice for the data model of my app, and so far I'm quite happy with it. However, the GUI part is about to become a Big Ball of Mud. I find it hard to use Guice here, because Swing components and models are tightly coupled, and often force a certain initialization order.
My application consists basically of a header with a lot of filters, a central and quite complex JTree component, and a lot of actions (e.g. from a JPopup), menus, dialogs, wizards etc. The main problem is that I have a lot of coupling between the components and actions (e.g. complicated validations, tree updates...). Could you give me some advice how to structure that GUI with Guice?
I'm aware of libs like GUTS, but the documentation is really thin, I'd rather avoid to add another dependency to my project and to learn another API (e.g. I don't know the Swing Application Framework).
I'd rather suggest a proper MVC, even better Presentation Model - View - Controller. Separate your code properly and Guice will fit in naturally. For example:
View classes should have a building part which draws the static content (labels, the tree, buttons, etc) and updating code which reacts to changes in the Presentation Model. All the action listeners should invoke some code on the controller. Both the Presentation Model and the controller should be injected by Guice, like all the other dependencies.
This organization would allow for easy testing with replacing the View with some testing code which will listen to changes in the Presentation Model and invoke actions on the controller.
I would advise to look at Guts-GUI.
It is a Swing UI framework based on Guice dependency injection model.
I think the problem is probably the overall architecture. You probably want to see if you can refactor the application to be simpler and more modular. Like Boris recommended, I would also suggest using the Presentation Model pattern - search for Martin Fowler and Karsten Lentzsch - and the JGoodies library.
For the problem with Actions, see how the Swing Application Framework and Netbeans Plaform handle them. For example, if an Action is used in both a view and a menu, you might want to make it available through a global map.
We have recently started on GUICE with swing. Here's what we have done which may be of help to you.
a. When you want to inject a model into a table/tree you could inject a model provider instead and do a provider.get() to get the model in the contructor.
for example
public class Mytable extends JTable {
public Mytable(Provider<MytableModel> modelProvider) {
this.setModel(modelProvider.get());
}
}
b. You could make a model generic and make use of the same model in different tables.
c. The model could have a handle to datasource which could be injected by a factory where necessary with assisted inject. Number of examples available in stack overflow.
d. Your model could be a flexible data structure which uses model to return the relevant cell/leaf/other value.
e. When you have actions, you inject actions in your component builders and attach them to relevant components.
f. Use #Singleton annotation where you have a shared object such as model injected in 2 different objects, such as action and the component.]
g. Use custom scope when you need to use number of instance sets of objects. Custom scopes are great for this as it keeps the code really clean.
Hope the above helps...
Related
I am trying to create a graphical flashcards app from scratch. I have a few questions:
a. I have used Swing to build some apps in the past, calculator app. But I felt that was a trivial application so I want to ramp up my skills as a Java developer.
b. I have been told that a gold standard is to build a small application that uses one of these: MVC, MVM, MVVM and so on.And since I am learning design patterns, I was hoping to use it in the application.
c. My classes are such:
A model: Flashcard.java(It has a list of answers, a list of
pictures, a question), A FlashCard Manager(to perform CRUD)
Different view classes: GUI interface
Controller: All the event listeners
App: To initialize the app
d. I have tried to read online examples of such a combination and what was proposed in for the Manager or DAO, was to have it connect to JDBC for the database. I am trying to simulate that by using a HashMap> for the same purpose.Is that correct or do I have to use JDBC or SQLite?
e. Also am I supposed to have a controller-view pair, that is for every JComponent that uses an event listener or a controller for windows( startup window, main application window, child windows)?
f. Also should the controller class be an interface for all these controllers?
I do not have code because I am still developing it but I just wanted to get a general idea. Thanks for answering my questions.
b. I have been told that a gold standard is to build a small application that uses one of these: MVC, MVM, MVVM and so on.And since I am learning design patterns, I was hoping to use it in the application.
This both right and wrong. Some API's simply don't support the notion of a pure MVC (or variation). Swing for example implements a form of MVC of it's own which is more like M-VC, where the model is separate, but the view and controller are bound.
Think about a JButton. Do you ever apply a controller to it? You can add listeners to it, you can even add listeners directly to it's model, but it has it's own internal control mechanism, which generates events based on keyboard and mouse interaction.
You need to beware of when a MVC might not be suitable or where the amount of work to implement a pure MVC is not worth the effort.
Having said that, you can wrap Swing UI's in another MVC layer, but you need to think about it at a different level. Instead of each controller been considered a "view", you look at the container, which might contain multiple controls and see it as the "view", which a controller then manages.
d. I have tried to read online examples of such a combination and what was proposed in for the Manager or DAO, was to have it connect to JDBC for the database. I am trying to simulate that by using a HashMap> for the same purpose.Is that correct or do I have to use JDBC or SQLite?
This is not an unreasonable idea, however, you want to ensure that the public interface remains constant. This would allow you to change the implementation at a later date to use JDBC or a web service without having to rewrite the code that depends on it
e. Also am I supposed to have a controller-view pair, that is for every JComponent that uses an event listener or a controller for windows( startup window, main application window, child windows)?
This will depend. I tend to avoid exposing individual components, as this exposes them to unwanted modifications (you may not want a controller to be able to change the text of a button for example)
As a general rule of thumb, I try to make the relationship between the controller and the view as vanilla as possible, meaning that the controller shouldn't care about how the view is implemented, only that it upholds the contract between the it subscribes to.
This generally means I have a functional view, which is contracted to produce certain events/data and allows certain interaction (from the controller)
f. Also should the controller class be an interface for all these controllers?
IMHO, yes. This allows a view/controller/model to be implemented differently, but allows the rest of the code to continue working with it without the need to be modified.
The bottom line is, implementing a MVC over Swing is not as simple as people think it is. It takes some planning and consideration, but it is doable.
For a more detailed example, have a look at Java and GUI - Where do ActionListeners belong according to MVC pattern?
I have read about MVC but am having doubts on how to implement the concept in Java with Swing. Here's what I'm going for:
The model:
ListOfThings contains a Collection of Thing objects.
The controller:
Controller instanciates ListOfThings and populates it with a "add" method (internally creates a new Thing and adds it to the Collection)
The view:
A Swing interface with a ListOfThingsPanel which will contain ThingPanel components to represent the model. Both extend JPanel. ThingPanel contains various components meant to display the data of the Thing it's linked to.
It also has a button which adds a new (empty) thing to the list.
The click event calls the Controller's addThing() method which asks ListOfThings to add a new Thing to its list. ListOfThings has an event/listener system and ListOfThingsPanel listens to it to know when it should refresh the view.
Am I properly following the MVC concept by doing it like this?
Update:
I'm still learning Java but I have coding experience and would prefer to learn the theory and attempt it by my own means before using premade frameworks. While I'm aware Swing implements the MVC pattern, I have read it does it in a specific way (View and Controller combined) which might not be the best and not applicable in other circumstances. I'm a bit wary until I can make sure "Swing MVC" is not different from "MVC", or that the differences won't impact my understanding of the underlying ideas.
One thing of import to me is to learn to really separate the model from the view to allow me to ultimately create various views of various types (Swing but also console or update to JavaFX for example) This is why I'd like to avoid anything Swing specific outside of the view part itself.
While the Swing framework already implements a form of MVC (explicit models; JXyz & UI classes = controller & view), this strict separation is rarely used on application level and looks rather weird.
To start I suggest to follow the following design:
implement the client-side business logic with POJOs
wrap the POJOs with custom Swing models where needed (ListModel, TableModel)
Use a GUI builder to design the GUI
Use the Mediator pattern to listen for events (a custom subclass of JPanel listens for events of its children and updates other children or fires own custom events if needed)
If you want to go a step further, use a RCP such as the NetBeans Platform (very recommended).
Edit:
And here is the article explaining MVC in Swing:
http://www.oracle.com/technetwork/java/architecture-142923.html
If you would like more details please let me know, or refer to the last lines of this question. I've already read a lot and I feel I'm turning something simple into something complicated and I still get stuck here and there, so maybe you can help me in those very specific points.
I'm using Netbeans IDE 7 and JDK 7, and no frameworks. The first Window is a JFrame and all other windows are JDialogs with modal=true.
Questions:
How do I correctly implement the MVC pattern with swing?
From the ideas bellow Which one is better: (A) or (B)? Or maybe another one... Why is it better?
(A)
Main:
MyModel model
MyView view(model)
MyView:
MyController(this, model)
(B)
Main:
MyModel model
MyView View
MyController controller(view, model)
when I click jbutton1 in MainFrame I need it to open the SettingsFrame for editing settings. where should I instantiate the View, the Model and the Controller of the SettingsFrame? In MainFrame Controller?
In terms of MVC organization and implementation, how should I handle more specific features that (apparently) lacks one or two of the MVC "legs" (either Model or View or Controller)? Should I create empty classes for them?
a. The implementation of a TrayIcon
b. A URL connection class (an HttpsUrlConnection which will update data in the main jframe and also upload/download files)
c. A Directory Monitor (which will update data in the main jframe and also use the urlconnection to download a file)
d. My own implementation of TableModel
e. json
How to correctly keep and use an object with settings through the whole application? I will need it's information in different places (Views, Models, Controllers) but it might be altered by user during the runtime). Is it a good idea to make this model a singleton?
What should I do when:
a. View needs some data from the Model?
What I'm doing: using the reference of Model which I keep in the View
b. View needs some data from the Controller?
What I'm doing: using the reference of Controller which I keep in the View
c. Model needs some data from the Controller?
Still didn't happen but I have no idea how to do correctly
d. Model needs some data from the View?
What I'm doing: pulling all my hair from my head...
e. Controller needs some data from the View?
What I'm doing: using the reference of the View which I keep in the Controller
f. Controller needs some data from the Model?
What I'm doing: using the reference of the Model which I keep in the Controller
g. One of FooModel, FooView or FooController needs data from one of BarModel, BarView or BarController?
What I'm doing: thinking of jumping from the highest building...
Any hints on how to know if I implemented MVC correctly? Should I process massive data in Model or Controller?
I'm also using a DAO, what I'm doing is: my model has a
ArrayList MyModel load()
method which creates an instance of the DAO and returns the ArrayList of Models returned by the DAO, and then sometimes I process this ArrayList of Models in the Model and sometimes I allow the Controller to process it. Is this a good practice or is there a better way? By Process I mean: iterate through the ArrayList and get the data from the models.
I Have a PasswordCheck jDialog to restrict access to some Views. How can I reuse it in terms of MVC, so that I can use the same PasswordCheck dialog for allowing/restricting access to different Views without doing a mess in the code?
Any other tips, hints, ideas, suggestions?
Context:
I'm required to develop a Java Swing MVC software in a short time, although by default I'm not a Java developer and not so used to implement the MVC pattern, specially in Java (I get the idea but sometimes it lacks me knowledge to implement the relationship between classes).
The applications is basically a monitor for local/online files with a JTable in the main frame to show this data. I'm using the new WatchService API to keep track of the local files and saving their info in a h2 database using a DAO, and them reload this data in the main frame jtable. I must also notify the user about new files (which for I'm using TrayIcon). For the online files monitoring/uploading/downloading I'm using HttpsUrlConnection and json. It may also allow Settings customization.
Thanks in advance for you time and help.
Have a look at Sun's (Oracle's) suggestions.
As one simplification, you could have each component (model, view, controller) register with a top-level application component to provide a single point of reference rather than individual references between each component (your A or B). The article I cite provides ideas for push and pull design; I'd recommend push as a more popular modern approach. Disclosure: I have experience with Java and MVC but not MVC in Swing per se.
where should I instantiate the View, the Model and the Controller of
the SettingsFrame?
Sure, yes, or in a top-level application component.
how should I handle more specific features that (apparently) lacks one
or two of the MVC "legs" (either Model or View or Controller)?
I would implement GUI-only pieces as your own GUI library. And purely algorithm/service pieces as a services library.
Should I process massive data in Model or Controller?
Data processing algorithms would fit nicely in a controller or even service library; your model should not do much processing at all beyond possibly data type conversion or validation.
How to correctly keep and use an object with settings through the whole application?
See my note on registration; a singleton may be appropriate.
I have a number of GUI classes that is accessing the same information object which is set from its constructor.
Each GUI class displays the gui information object in a different way.
Is it better to initialise the object each time in the constructor or just add the object to memory and use it each time a GUI class requires it ? Does either method fall into a design pattern ?
Before even reading up on specific object design patterns, a good starting place is to read up on the MVC (Model View Controller) pattern. It's probably the most commonly used architecture pattern out there, and a google search will bring up tons of good material (Wikipedia would even be a good place to start in this case)
It's used to address the problem you've hinted at, where your various display logic has to frequently access the same information holding logic. In an application which uses an MVC architecture, your code is (more or less) separated into three categories, code which displays information in a UI, code which holds (or models) information, and code which controls the flow of the application and application events. MVC applications commonly use listeners and other event design patterns, like the ones mentioned above.
Take look at dependency injection, listeners and event bus.
I would suggest dependency injection, there are a lot of frameworks out there. My favorite is guice but YMMV.
How about using a strategy pattern?. Basically just define a set of classes that inherit from the same interface such as
public interface GUIBehavior {
}
//Set of classes
public behavior1 implementse GUIBehavior...
//In the clases that display the information simply set an attribute for the behavior
private GUIBehavior myCurrentBehavior;
This is a follow up question to The MVC pattern and SWING. I am trying to implement the MVC pattern in an existing piece of code. The existing code creates a JFrame which acts as both the view and the controller. The JFrame has a table, and the table's model is an adapter to a custom data model. Whenever the user performs an action, the model would be updated by doing something like the following:
CustomDataTableModel cdtm = (CustomDataTableModel) DataTable.getModel();
CustomDataModel cdm = cdtm.getModel();
cdm.delete(1);
I've tried to visualise how it currently works, but I've also visualised how I imagine the relationships with the future controller and model should be.
Now, my question is simply whether I can continue using the model as it is now? Could I implement the following and still "adhere" to the MVC pattern?
The user selects an element in the table, and clicks on a delete button.
The view delegates the action to the controller.
The controller access the table through an accessor on the view, and performs the update.
The model, when it is updated, notifies the JTable that it has been changed.
If any other components in the view displays data from the table, then this could be solved by registering listeners on the JTable's table model.
Update 1
I've been thinking about the existing code in light of the MVC pattern, and I've redrawn the relationships a little. The point is that the controller is the behaviour of the view, thus the controller updates the model when users do stuff, and the view listens for changes in the model. However, nothing in the MVC pattern stops the view from listening to the model through a tablemodel - right?
Now, the user clicks the add button. The view notifies the controller that the add button has been clicked, and the controller takes care of creating a new item by invoking some method on the model. The view is registered as a listener on the model (through a table model) and updates its view. The controller may also be a listener on the model in case it needs to take care of disabling or locking fields. Have I not achieved what the MVC is all about; separation of concerns? As far as I can see, I've even introduced the adapter pattern to decouple the view even more from the model? It is late and I am tired, so that might be why it makes sense :-)
In the general sense, I would advise you the following:
take a look at JGoodies Binding,
it is not MVC but uses the
"PresentationModel" pattern
which is, in my opinion, better
adapted to a whole application than
MVC (which I find suitable for
individual widgets only). This should
solve your problem between your
Domanin Model and the TableModel
if your application has only tables,
then GlazedLists also makes a
lot of sense: it will also isolate
your Domain Model from your
TableModel (but it doesn't enforce
any global pattern, MVC or PM)
Regarding the current design you show, I would rather suggest that the View asks the Controller for an Action that the View will assign to the Delete button. Then the Controller can act on the Domain Model.
That gets messy and confusing fast, alas, and the code base is already confusing due to lack of separation.
I suggest instead migrating distinct components to a clean, simple MVC design. Such a component (which is currently a view, controller, and model all mixed up together) would then be separated in a clean fashion, however you will then have the difficulty of how to handle the controller and model?
As a temporary workaround, you'll be forced to designate the owner view as the controller, so the owner arguably has more responsibility. I think that this is a suitable workaround, because you will eventually separate more and more components into an MVC design, and the views that are also controllers will eventually become refactored as well.
In other words:
For a large application, identify a small component. (The low-hanging fruit).
Identify what code effectively controls that component. This is probably another 'view' class in this case.
Separate the component identified in step one into a clean design.
Explicitly configure the owner (view) identified in step to as the controller for the newly refactored component.
Repeat until there is clean separation between ALL views and controllers.
Be careful to ensure that the application is still working at the end of every 'step 4' above, otherwise, you'll find yourself in a mess that just gets longer and longer to fix. (Even if the end result is nice and clean, you may have missed your deadline).
Keep in mind that it may be difficult to extract the 'model' from the code at first - the controllers and views will be easiest to separate, but eventually, the models will become easier to separate as well. Whenever you manage to extract a model, write unit tests that test that model in isolation.
The presence of a well written suite of unit tests will help ensure that the application continues to have well-defined separation of concerns. (If concerns are not separated, then it becomes very hard to unit test), so the unit testing approach serves as a motivator.
I hope that makes sense.