I have been asked to revamp an existing JDialog that is a child container of an in-house Swing app. I will be re-writing the dialog from scratch and have been asked to lead the charge towards making the Swing app resemble a true MVC/MVP architecture (so my JDialog revamp will be the first of many pro-MVC changes to the app itself).
I understand MVC/MVP as it pertains to web apps:
Controller - is what the web app framework dispatches to handle HTTP requests; typically consists of multiple methods, where each "controller method" handles the request for a slightly different URL
Model - the DAO or POJO/bean representing call-specific data; controller fetches the Model from the DB and injects it into the View
View - the mechanism that ultimately produces HTML/JSP that will be sent back to the client/requester
This is not how all MVC/MVP web frameworks operate, but is the general idea.
But I'm struggling trying to determine how to translate this to a Swing app. In the Swing app, you have:
The JDialog itself
All the UI widgets (JButtons, JTextFields, etc.) that make up the "view" of the dialog
The action/event listeners for all the UI widgets which collectively make up the "business logic" for how the dialog will operate when the user interacts with the view
All the other "UI glue code" (setting which widgets will be enabled/disabled, setting their sizes and positions on screen, setting their tooltip texts, etc.)
Plus a lot of other stuff
So I ask: how do I organize all the code necessary for a functioning JDialog using an MVC/MVP architectural pattern? Also, if there are any articles, tutorials, or existing open souce projects that showcase MVC/MVP Swing apps, I am interested in them as well. Thanks in advance!
As discussed here, Swing MVC hinges on the observer pattern used to propagate model changes back to any listening view(s). As a result, much depends on the components in your JDialog. If your dialog must be modeless, the examples here and here may be helpful.
Since there are many valid recipes out there, I'll only discuss what I use: a modified MVP design which also borrows ideas from The Humble Dialog Box.
Basically, create your GUI with as little application logic as possible (zero is the goal). Create "presenter" classes (similar to Controllers) that have a handle to the GUI and inject the appropriate listeners onto the UI.
Some benefits:
Since all application code is out of the UI, your code is now 100% testable.
You can quickly prototype your GUI without having to launch your app everytime, which can be a big time-saver.
Separation of concerns makes code easier to read/maintain.
Your GUI code will be Swing only. A new team member who isn't familiar with your app but is familiar with Swing can jump right in.
With regard to Swing's implementation of MVC, we actually don't care. That's Swing's business. We assume Swing works (which it usually does). True, we need to know these sorts of things for writing custom renders, editors, models, etc., but those are details that the application framework (which is what I think you're asking about) doesn't need to know or care about, for the most part.
I would do like this:
MyModel model = engine.getDataFromDatabase();
myController.displayDataOnMyCustomView(myPresenter, model);
And at controller side, probably will remove a lot of listeners, set the data based on model, set sizes, locations and any other state representing stuff and finally re-add the listeners.
The myPresenter should be a custom JDialog with various basic ui elements (Component)on his UI tree.
Related
I'm creating my first "bigger" application in Java. As MVC is only pattern I know, I decided to use it. But there's something wrong with this concept.
For example. I need an Action (or generally event) fired from 2 places (from Button in frame and MenuItem). It has to do changes in at least 2 places and in the model.
I've got some ideas, but they seem wrong:
Pass the controller object to every view element, so newly created actions could use controller's methods to modify rest of the application.
Make controller static (for same reasons)
Make controller only model listener
Please tell me how to build it. Or give me some links to some easy to analyse applications.
Source of my project is here, if anyone wants to have a look: https://github.com/Arrvi/ColorExtractor
You are correct to use Action to encapsulate functionality for use by disparate components such as menus and buttons. A spectrum of examples is cited here. As regards MVC, recall that Swing uses a separable model architecture, examined here. In effect, the user is the controller, and not every interaction needs to pass through your application's controller.
Please excuse the verbosity of this question, as in writing it I am attempting to think through my design problem!
I have inherited a Swing application which requires re-architecting into an RMI application. The customer requires the Swing GUI to run locally and communicate via RMI to a remote Server process, which encompasses a Controller class which directs calls to sections of business logic and back end database persistence when stimulated by EventListeners, which bridge the gap between the Swing Client and the Controller.
I am to implement an MVC design to allow for new Views to be developed for use with the server.
Currently, the Swing Client GUI contains a JTree which is populated using a DefaultTreeModel. This Model is constructed using DefaultMutableTreeNode objects which are populated with Business Object state via a BusinessObject mapper that sits between these objects and my Data Source.
I have no problem understanding how the Client and the TreeModel are linked: I have established a TreeModelListener to look out for changes to the TreeModel. If the TreeModel object changes, I redraw the JTree by calling its treeHasChanged() method.
However, I am having a headache trying to picture what process would stimulate the TreeModel, so that its contents are repopulated with the latest data in the database, which would in turn invoke my TreeModelListener to update my GUI's Jtree. Who should "own" the TreeModel? Should it be a Class in the model which makes up a piece of the Controller's state? Should the Actions in the Controller by the GUI's EventListeners make a hard call to run a routine to refresh the TreeModel?
Or alternatively is the TreeModel an extension of the GUI Widget, in which case it is a View component? If so, what would be the proper manner in which to invoke a refresh of the state of this object?
I should probably note that I have been thinking in terms of Observers and Listeners in recent days, so I am probably guilty of trying to invoke behaviour to occur off the back of an observer firing.
Yours, very confused!
I'm not sure if you decribed about AbstractTreeModel or DefaultTreeModel, I think that this article Understanding the TreeModel is still best around, and link to the JTree tutorial
for reall help you have to edit your question and post image of your headache in the SSCCE form, here are tons of good bases for creating SSCCE
In addition to #mKorbel's informative links and #Shakedown's comment, consider using SwingWorker to periodically rendevous with your middle tier and update your TreeModel, perhaps in response to a Timer. There's a related example here; note that the GUI remains responsive as the query runs. Of course, it's up to your application how often the update needs to run and how frequently you update the GUI.
I got my head around the problem.
I have decided it is a bad idea for Swing API to be present in the Model of my application, since my application is one which can take many different types of UI's (Headless, Swing, Web).
Thus I have decided that the correct approach is for the TreeModel object to live in the View, and be populated by a View Helper which provides access to a generic presentation of the Model tier to any interested UI.
UPDATE: I'm using Netbeans and Matise and it's possible that it could be Matise causing the problems I describe below.
UPDATE 2: Thanks to those who offered constructive suggestions. After rewriting the code without Matise's help, the answer offered by ignis worked as he described. I'm still not sure how the code the Netbeans code generator interfered.
Though I've been programming in Java for awhile I've never done any GUI programming until now. I would like to control a certain part of my program externally (updating a jTextArea field with output from an external source) without requiring any user action to trigger the display of this output in the jTextArea.
Specifically, I want this output to begin displaying on startup and to start and stop depending on external conditions that have nothing to do with the GUI or what the user is doing. From what I understand so far you can trigger such events through action listeners, but these action listeners assume they are listening for user activity. If I must use action listeners, is there a way to trick the GUI into thinking user interaction has happened or is there a more straightforward way to achieve what I want to do?
Also, I'd really like to know more about best practices for separating GUI code from the application logic. From the docs I've come across, it seems that GUI development demands more of a messy integration of logic and user interface than, say, a web application where one can achieve complete separation. I'd be very interested in any leads in this area.
There is no need to use listeners. GUI objects are just like any other objects in the program, so actually
you can use the listener pattern in any part of the program, even if it is unrelated to the GUI
you can invoke methods of objects of the GUI whenever you want during the program execution, even if you do not attach any listeners to the objects in the GUI.
The main "rule" you must follow is that every method invocation performed on objects of the GUI must be run on the AWT Event Dispatch Thread (yes, that's true for Swing also).
http://download.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
So you must wrap code accessing the GUI objects, into either
javax.swing.SwingUtilities.invokeLater( new Runnable() { ... } )
or
javax.swing.SwingUtilities.invokeAndWait( new Runnable() { ... } )
http://download.oracle.com/javase/6/docs/api/javax/swing/SwingUtilities.html
About "separating GUI code from the application logic": google "MVC" or "model view controller". This is the "standard" way of separating these things. It consists in making the GUI code (the "view") just a "facade" for the contents (the "model"). Another part of the application (the "controller") creates and invokes the model and the view as needed (it "controls" program execution, or it should do that, so it is named "controller"), and connects them with each other.
http://download.oracle.com/javase/tutorial/uiswing/components/model.html
For example, a JFoo class in the javax.swing package, that defines a Swing component, acts as the view for one or more FooModel class or interface defined either under javax.swing or one of its subpackages. You program will be the "controller" which instantiates the view and an implementation of the model properly (which may be one of the default implementations found under those packages I mentioned, or a custom implementation defined among your custom packages in the program).
http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/package-summary.html
That's a really good question, IMHO... one I asked a couple of years ago on Sun's Java Forums (now basically defunct, thanx to Oracle, the half-witted pack of febrile fiscal fascists).
On the front of bringing order to kaos that is your typical "first cut" of an GUI, Google for Swing MVC. The first article I read on the topic was JavaWorld's "MVC meets Swing". I got lucky, because it explains the PROBLEMS as well as proposes sane solutions (with examples). Read through it, and google yourself for "extended reading" and hit us with any specific questions arrising from that.
On the "simulated user activity" front you've got nothing to worry about really... you need only observe your external conditions, say you detect that a local-file has been updated (for instance) and in turn "raise" a notification to registered listener(s)... the only difference being that in this case you're implementing both the "talker" and the "listener". Swings Listener interface may be re-used for the messaging (or not, at your distretion). Nothing tricky here.
"Raising" an "event" is totally straight forward. Basically you'd just invoke the "EventHappened" method on each of the listeners which is currently registered. The only tricky bit is dealing with "multithreaded-ness" innate to all non-trivial Swing apps... otherwise they'd run like three-legged-dogs, coz the EDT (google it) is constantly off doing everything, instead of just painting and message brokering (i.e. what it was designed for). (As said earlier by Ignis) The SwingUtilies class exposes a couple of handy invoke methods for "raising events" on the EDT.
There's nothing really special about Swing apps... Swing just has a pretty steep learning curve, that's all, especially multithreading... a topic which I had previously avoided like the plague, as "too complicated for a humble brain like mine". Needless to say that turned out to be a baseless fear. Even an old idiot like myself can understand it... it just takes longer, that's all.
Cheers. Keith.
This doesn't exactly answer your question, but you might be interested in using Netbeans for Java GUI development. You can use GUI in Netbeans to do Java GUI development.
Here's a good place to get started -
http://netbeans.org/kb/trails/matisse.html
I would like to ask whether from a design pattern point of view whether it would be better to place listeners for GUI within the "view" or the "controller". A colleague believes that the "view" is the most natural place, but i'm not so sure.
If you are talking about Swing then, as previously discussed, MVC in Java is not a clear and simple as the pattern suggests. To answer your question, then, depends on how you define "view" and "controller" with respect to a specific application, and what you mean by "placing listeners" in one or the other.
I take the view the listeners are part of the controller mechanism - they provide a loose(ish) coupling between the view (that displays the current state) and the model (that maintains the current state), and provide a way for the two to interact. However, most Swing listeners are very tightly bound to UI events - mouse buttons being clicked, items being selected from lists, etc. - and so you may want to create an additional layer of abstraction which takes these UI events, which are captured by listeners, and translates them into something more general to the domain of your application. An EJB, for example, can provide a common interface for some business logic which may be triggered by a Swing UI or an API call via a web service. The controller, then, is the EJB, and the Swing event listener that triggers a call to that EJB is in the view.
Is there a resource where GUI design for swing is explained? Like best practices and such.
Design guidelines aren't exactly followed much anymore because Swing works on so many different platforms. Sun wrote up some a long time ago, and never changed them so I'd say read it if you think it will help. Here is some practical knowledge about doing swing development.
Never use GridBagLayout. Grab TableLayout. It radically simplifies layout for you Swing UI. GridBagLayout is the devil.
Don't over embed components just to get a layout right (i.e. embedded BoxLayout, etc). See point 1 for how to do this. There are performance issues having components on the screen.
Separate your program along MVC lines. Swing has View and Model separation, but in large programs the View (i.e. what subclasses a Swing Component) turns into a psuedo View/Controller only making things complicated to reuse and maintain. It turns into spaghetti code fast. Break the habit and create a Controller class that DOES NOT extend Swing. Same goes for the Model (no swing). Controller instantiates high level view classes, and wires itself as a listener to views.
Simplify popup dialogs using simple panels only. Don't subclass JDialog. Create a reusable dialog class that wraps a panel that can be used something like JOptionPane. Your panels will not be tied to dialogs only and can be reused. It's very easy when you work this way.
Avoid actionlistener/command. This is old junk and not very reusable. Use AbstractAction (anon classes are your choice I don't have a problem with them). AbstractAction encapsulates text, icon, mneumonics, accelerators, reusable in buttons, popups, menus, handles toggling enabled/disabled states, can be shared among multiple components, it also is the basis for InputMap/ActionMaps for mapping keyboard strokes to actions. ActionMaps give you loads of power for reuse.
It's best to have to view dispatch events to the controller. I'm not talking about mouse/keyboard junk, but high level events. Like NewUserEvent, AddUserEvent, DeleteUserEvent, etc. Have your controller listen for these high-level business events. This will promote encapsulation by keeping the concerns of the view (should I use a table, list, tree, or something else?) separated from the flow of the application. The controller doesn't care if the user clicked a button, menu, or checkbox.
Events are not just for the Controller. Swing is event programming. Your model will be doing things off the SwingThread or in the background. Dispatching events back to the controller is a very easy way to have it respond to things going on in the model layer that might be using threads to do work.
Understand Swing's Threading rules! You'd be surprised how few people actually understand that Swing is single threaded and what that means for multi-threaded applications.
Understand what SwingUtilities.invokeLater() does.
Never* ever use SwingUtilities.invokeAndWait(). You're doing it wrong. Don't try and write synchronous code in event programming. (* There are some corner cases where invokeAndWait() is acceptable, but 99% of the time you don't need invokeAndWait() ).
If you're starting a fresh project from scratch skip Swing. It's old, and it's over. Sun never really cared for the client like it did the server. Swing has been maintained poorly and not much progress has taken place since it was first written. JavaFX is not yet there, and suffers from lots of Swing's sins. I'd say look at Apache Pivot. Lots of new ideas and better design and an active community.
I have written a list of recommendations here.
In larger swing projects I do partinioning of the app like that:
Have one class per GUI element like JPanel,JDialog etc.
Use a separate package for each screen, especially if you have to implement customized TableModels or other complex data structures
Don't use anonymous and inner classes, implement instead an ActionListener and check ActionEvent.getActionCommand() in there.
EDIT: If you're rather looking for a tutorial or introduction you could start here
Maybe not exactly what your looking for but it won't hurt to take a peek at Java Look and Feel Design Guidelines
You can check the ideas behind FEST - a swing testing framework. It's main site is here and the project is hosted here
You can find some of best practices in chapter 4 of Professional Java JDK6 Edition
I have some guidelines too:
1) Use Maven and seperate your application into modules (view, controller, service, persistence, utils, model). Be sure you put your Swing components and dependencies only in view package, so if you want to change view framework some day, you can just reimplement view module but you can leave your business logic, controllers, etc... intact.
2) Use GridBagLayout because its very flexible and most configurable
3) Use a SwingTemplate (i can give you an example if you want)
4) Create a SwingFactory that creates components so you can reduces the amount of lines of codes since JFrames orso intend to be very large classes...
5) Let the view (JFrame, JDialog, etc...) have a dependency on controllers. Only do validation input on JFrames but then pass parameters to controllers. They will decide which business logic (service, processors, etc...) will be triggered.
6) Use lots of enumerations
7) Always think how your application can change or how it can be maintained. Therefore, use always code against interfaces or abstract classes. (Think abstract)
8) Use design patterns in your application because they provide confort and maintainability of your code. Make for instance all your controllers, services, dao's singleton classes. Make factories (swingfactory, ...) so you have to write less code over and over again.... Use observers so actions can be processed automatically.
9) Test your appliction: Make a choice between: TDD (Test Driven Design) or DDT (Design Driven Testing)
10) Never put any business logic on JFrames, because it is ugly and its not very Model-View-Controller design. JFrames are not interrested on how the data has been processed.
Hope that helps.