I am just about done with our exam project, and when looking back at what I coded, I feel I did quite alright. Though, stuff could obviously always be alot better. But maybe that's just me.
I was in charge of coding the GUI, and coupling it with the application logic. When making the GUI I made the decision that I would make a class file for every window (e.g. LoginWnd.java), and actually build the GUI in the constructor. I would initalize everything and set all data inside this constructor.
Then in order to navigate through the application, I would set actionlisteners on the jbutton. For example, in SearchWnd, hitting the "Search" jbutton would create a new object of ResultWnd with some specified parameters.
Now i'm kinda wondering: Was this design decision bad in any way? Are there any design paradigms that I should've been aware of?
Thanks.
Your approach sounds fine overall - as long as it works you've achieved the main goal! So my comments here are more about fine-tuning / broader design aspects.
There's nothing fundamentally wrong with doing GUI construction in the constructor providing that the GUI doesn't subsequently change during program execution. The rationale here is that constructors should be reserved for "one-off" construction activities. So it's probably fine for dialog boxes and suchlike that have a pre-determined layout.
If you have a more dynamic GUI where components are frequently being added and removed throughout program execution, then I'd strongly suggest moving this to a set of methods outside the constructor so that they can be called independently of object construction. The constructor itself can still call these methods if needed to do initial setup, but subsequently you have the ability to call these methods later to add new components, refresh the layout etc.
The good news is that this stuff isn't hard to refactor if you get it wrong - it's usually trivial to pull setup code out of a constructor into separate methods later if needed.
Another thing to be aware of is the oft-repeated mantra "prefer composition to inheritance". That is to say, if you can make your GUI work by assembling existing components rather than inheriting and overriding your design will probably be better/more easy to maintain in the long run. For example, I don't think I've ever subclassed JFrame - it's almost always cleaner to just add JPanels within it that contain all the application-specific components.
Finally, be cautious of coupling your GUI components too closely to your application logic. Swing actually does a pretty good job of encoraging you to separate out your data model from the presentation code (e.g. with ListModel and friends). It's worth studying and understanding that approach. The point is that you should usually build GUI components in a way that is fairly application-agnostic, but give them application specific behaviour by connecting them to the right data model and event handlers etc.
I also initialize my GUI in the constructor, so it can't be bad :) But when it gets too long I extract parts of the code into separate GUI components.
Related
Short Question
I want to know if there is any good practice recommendation about write one listener instace for all components or an instance for each component.
Extended Question
I'm developing a java swing application.
In the same form i can have a dozen of components (with no relation between them) that use the same listener class. I write each of my listeners in their own class.
The listeners are used to make some validations over the data introduced on the component.
Should i create an instance of the listener class for each component, or should i use the same instance of the listener for all the components.
I can't find any good practice suggestion about this, except this comment, that does not point to any reference.
For the particular case of ActionListener, encapsulate the desired functionality using Action. The wide use of this class throughout Swing suggest its value. This simple example illustrates a few built-in text component actions; this more elaborate example shows how actions can be shared among menus and toolbars.
The alternative is an ever-growing and hard-to-maintain if-then-else ladder based on the event source.
Addendum: Ah, I misread your question. #Andrew's comment is about classes; your question asks about instances. For the former, a single listener tends to evolve toward a a known anti-pattern; earlier versions of the example cited illustrate the problem. For the latter, use only as many instances as required; I usually catch the most egregious violations in a trip through the profiler.
I think the best solution is the one that makes your code the cleanest possible.
Basically, if having one single instance doesn't complicate the code too much then you could create just one instance and share it across the components. Otherwise, you can have multiple instances.
You should choose one which keeps your code readable and maintainable.
If creating instances makes it simpler go ahead and do it but since the behavior remains the same; I believe single instance should work.
Your idea is really interesting........
Moveover if its Swing....then its already based on MVC architecture......
Model - Business Logic and Data
View - Representation of Output
Controller - On which the action is done.
Now i think its also better to have the Business Logic with its data together, so we can easily associate the logic and its corresponding data.
You can always have an a common listener for common EventSource, like JButton...
You can have 4 JButton, which do different works, now you can have a single ActionListener with switch statements..... quite easy to handle......
So I've been trying to see how I could best structure my code, because I have an intuitive feel that there must be a better way to achieve what I want without passing around a single object to nearly every UI class in the project.
The project I'm working on has a class RhythmWheel that extends JRootPane. The constructor then goes on to create all the components that form a RhythmWheel. For example it creates an instance of ControlPanel (which extends JPanel) and adds it to itself.
However ControlsPanel needs to have a lot of knowelgde of things that are defined in RhythmWheels like the number of wheels that are currently selected. Currently the constructor for ControlsPanel takes a RhythmWheel as an argument, and then keeps a reference to it. It uses this for things ranging for component a JFileChooser should be parented to to, and as an argument to a function that writes the revelant state of the application to an XML file.
It seems wrong to me that I'm passing around a main component across so many classes. I thought about design patterns, and figured that a singleton might be a solution to this. However I have read numerous times that singletons are evil and are an anti-pattern. I guess the MVC pattern might help, but I'm not sure how I'd implement that in Swing. And most recently I came across Dependency Injection as a possible solution.
I'm a little lost as to what I should be doing, or if I should be doing aything at all. If you'd like to glance at the code I'm working on, you can see it at https://github.com/vamega/RhythmWheels so any advice on how to proceed would be great.
if everything needs a reference to RhythmWheel then it sounds like RhythmWheel is awfully complex. maybe you can break RhythmWheel into a collection of components that (hopefully, and likely, since GUI should reflect logical structure) correspond to particular parts of the GUI?
also, why do all the GUI components keep references to the RhythmWheel (or the appropriate sub-component, if you refactor as described above)? i haven't done much spring programming, but i thought the idea was to structure things round an observer pattern. in that case, the gui components should be registering themselves as observers on the wheel components, so that they can update when the wheel changes.
and yes, this is mvc. the wheel components form your model; the gui is your view. what is less clear is what the controller is. i suspect that it is the high-level wheel.
so, in summary:
the wheel is composed of sub-components
the wheel has high-level methods that reflect what you can "do" to it
the wheel's high-level methods are what are called by actions in the view
the wheel's high-level methods make changes to the wheel's sub-components
the wheel's sub-components, when they change, inform the model, which updates
only the input parts of the view need references to the wheel; the display parts are triggered via callbacks registered with the wheel sub-components.
(to answer the original question directly, i don't see anything so bad in passing around a wheel instance, but as i suggest above, it might be better for it to "fragment" into different components as it gets "lower" into the GUI).
I don't see what's wrong with using singletons. A control panel sounds like a prime candidate for a singleton. Why would have you more than one? Same goes for the others. Anything your currently accessing in ControlPanel from RhythmWheel can be exposed through getters and setters.
Unless there's a model/view separation that you would like to decouple or a view that needs to observe model updates, I wouldn't use MVC.
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
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.
if i have a class gui and a class for the logic, is holding a reference in gui to logic and logic to gui very bad?
As a general rule it is bad to have the "logic" class having knowledge of the "gui" class. The idea behind the separation is the Model/View design pattern (or Model/View/Controller). The view will need a reference to the model. Look really closely at why the model needs a reference to the view. Usually when the model needs to send information to the view event listeners are used (see javax.swing table and list models for an example).
It should be avoided.
In your GUI, you can have a reference to your Domain Logic, but you should not have a reference to your GUI in your domain logic.
Why ?
Because otherwise, you have no advantage of splitting GUI & Domain logic up in separate files. When your Logic has a dependency to your GUI, then you cannot use your Logic with another GUI.
So, you should try to avoid this dependency from your logic to your gui, or, you should make abstraction of it.
I hope i'm making myself clear here. :)
If you can avoid it, you probably should. Otherwise you might get into a lot of problems with circular dependencies later.
Do they really have to know about each other, or could you have a third "control" concept referencing the two?
The GUI probably needs to expose some kind of interface to the logic class, to have the GUI update when the logic class changes something.
The logic should not have direct knowledge of the the GUI implementation, only its interface.
The Observer Pattern is sometimes used for this.