What's the rule of thumb regarding Swing component extension? - java

When dedicating a class to a particular Swing component, is it better to extend that particular component, or construct it internally and provide a reference?
public class Foo extends JComponent{
}
OR
public class Foo{
public JComponent getComponent(){
}
}
EDIT
This is what I mean by dedicating
public class Foo{
private static Foo INSTANCE;
public static Foo getInstance(){
if(INSTANCE == null){
INSTANCE = new Foo();
}
}
public void createAndShowComponent(){
//do stuff
}
}
Inside createAndShowComponent(), I create a JComponent with all its components and their respective listeners without exposing the internals of the component I just created.

+1 for Composition over extension. It makes the API much cleaner since you only expose what methods are important for your new component

I agree with jzd it all depends.
Technically speaking, if you are dealing with GUI in my opinion it is best to build components when you need them, by extending for example JComponent. This way you can simply reuse them.
Personally I would never use the 2nd option in my class. I would only have a class return another component only if there is a very good reason for doing so, e.g. to enable user to modify a button look in your complex calendar component.
For a very simple reason each component class should know what it has this component for, and it should control the view accordingly to what is happening. Thus you would have appropriate methods.

I would say extending it would be better. Being able to use all its properties and using it like it is that object makes it a lot simpler to use. Just my personal Opinion. Both ways are good.
If you are dedicating the entire class to it. Might as well make it that by inheritence.

If your object IS a component, than extend it. If not, then use composition.

It really depends on what you are doing. If you want to include your new class on a JPanel for example, you will need to extend the component. If your code can add the component to the correct place on the GUI, then you don't have to extend it.

I would say none of them. Swing components are very (very) rich and can be customized for visualisation (L&F) and behaviour (events) in any manner. Another point is to create a group of different components and lay them out in a JPanel.

Related

Editing nested JDialog in Netbeans' Design mode

Say I have the following code:
public class MainDialog extends javax.swing.JFrame
{
static class SubDialog extends javax.swing.JDialog
{
}
}
If I open 'MainDialog.java' in design mode, I can only edit the GUI of the MainDialog class. Is there anyway to edit the SubDialog class in design mode?
Thanks
To even be "close" to been acceptable, the inner dialog would need to be public and static as Netbeans needs a way to create an instance of the dialog.
Most developers will create separate, single based class, based forms which are then configurable in some way (via setters and getters), passing references of what they need backwards and forwards between them.
Personally, I tend to hand code most my UIs and only rely on the form editor when time a is pressure or the layout is especially complex

Syntax of establishing JFrame. Which is correct?

I'm fairly new to programming and definitely new to Java. I'm teaching myself before I begin courses this fall in computer science and I have a curiosity about syntax that I have seen from two different authors.
In one book, a JFrame is usually established by making the class an extension of JFrame
public class MyClass extends JFrame {
etc
However, another author, and also questions on this site usually establish a frame inside of the class as such:
public class MyClass {
JFrame frame = new JFrame();
Firstly, what are the advantages of one over the other?
It seems to me, and I'm hardly an expert, that making a class an extension of JFrame would make it easier to set parameters of the frame and also to add components to it.
IE in the extension format, you simply say
add(component);
However, in the other format, on must type:
frame.getContentPane().add(component);
which seems more tedious.
Can someone please explain succinctly the reason behind this or if it is simply a matter of preference. I have looked into this and have been unable to get a straight forward answer.
There are philosophical and practical reasons many (including I) prefer the latter:
Prefer composition over inheritance in general.
Only extend a class if you plan to alter its innate behavior (i.e., override one or more of its methods).
By not extending JFrame, it is easier to create classes that maximize cohesion and minimize coupling, and to write clean MVC-based code. A more important example of this concept is to avoid having your GUI code (your view code) implement any listener interfaces (your control code). It's OK for baby programs, but not for grown-up code that has the potential of getting complex.
By not extending a large and complex class such as JFrame, you reduce the risk of difficult to debug hidden override malbehaviors. Try extending JFrame or JPanel and giving the class a getX() and getY() method to see what I mean!
If you're using an IDE that gives suggestions of methods available to objects of your class, you greatly reduce the number (and complexity) of possible suggested methods if you don't override a huge complex class such as JFrame.
By gearing your Swing GUI's to create JPanels rather than override JFrame, you greatly increase the flexibility of how that GUI can be used. Now it can be placed in a JDialog, JOptionPane, a JApplet, inside of another JPanel as part of a more complex GUI or as part of a CardLayout view swap.... and I can go on and on.
On the same token as above, many of my GUI's do just that, create JPanels, that I can test in isolation by putting them in JFrames in small test programs before adding them to the greater whole of the application.
Traditionally you're not creating a special type of frame, so you shouldn't extend JFrame.
You're creating a JFrame and putting content in it, so the latter method is preferrable.
I.e. it's from an object oriented point of view it's cleaner to USE a JFrame, instead of extending one.

Java Swing and the Observer Pattern

I'm looking for a way to cleanly organize my UI code in Swing.
Let's say my UI-code is structured in the following way:
class MainWindow extends JFrame {
// SomePanel panel is added here
}
class SomePanel extends JPanel {
// buttons, checkboxes and so on are added here
}
Lets say I'm instantiating a MainWindow-object inside my main method:
MainWindow frame = new MainWindow("I am an App");
What is the best practice for listening to ActionEvents of buttons (which are declared inside SomePanel, which is declared inside MainWindow) from within my main-method?
Thank you very much for your help!
Use a PropertyChangeEvent, seen here and here, to communicate results from one container to another. Other ways to implement the observer pattern are mentioned here.
Addendum: You're suggesting writing custom ActionEvents?
EventListenerList is another way to implement the observer pattern. Such a list is common to every JComponent, and it is appropriate when more than one event type must be managed. JFreeChart is another popular example that uses diverse events to update chart subcomponents when the data model is changed.

JFrame child cannot see parent widgits

I have a JFrame application with some variables and a number of SWING widgets. In it I create an instance of another class and pass the JFrame to the child in the constructor. From the child, I can reference the variables, but not the widgets. Why?
// My JFrame
public class Prot2Prom extends JFrame {
// My Child
public Prot2Prom() {
super( "Protocol To PROM" );
Child child = new Child(this);
In the Child class my constructor does
Prot2Prom frame = null;
public Child(Prot2Prom gui) {
frame = gui;
}
The following works:
frame.<parent variable>=x;
The following does not:
frame.textArea.append("Hello");
The textArea cannot be resolved. There were all added with "new". Why can't I see them?
Some notes and recommendations:
This has nothing to do with "widgets" or Swing and all to do with visibility of variables. I'm guessing that textArea is not a public field of the Prot2Prom class.
If variables are public outside classes can "see" them, access them, modify them.
A possible solution is to in fact make the variables that you want other classes to see, public.
In general you really don't want to do this.
Instead much better is to give a class public methods that allow other classes to call and by doing so alter the original class's behavior. In other words, your Swing GUI classes should adhere to good OOPs principles just as any Java class should.
Later you'll want to read up on the MVC or Model, View, Control design pattern as a way of separating out behaviors of your code into separate logical entities, which can make your code much more flexible and powerful.
Edit 1
Regarding your comment:
The "widgets" are all created by WindowsBuilder Pro. I am trying to use the textArea to create my Eclipse Console for a stand alone (jar) application. How can I print to it from a class instantiated by the Frame?
You'll want to give the class that holds the textArea variable a public method:
public void appendTextAreaText(String text) {
textArea.append(text);
}
Then your other classes can append text to the JTextArea. Why is this important? One reason is that if the class that holds textArea will at some times not want to allow other classes the ability to append to this widget, it can have the logic to control this in the method. Thus it gives much more control over the widget to the class that holds it.
e.g.,
public void appendTextAreaText(String text) {
if (allowTextAreaAppend) { // a class boolean field
textArea.append(text);
}
}
As an aside, I also recommend that you put the code generation tool to the side and instead create your Swing GUI's by hand for a bit until you get a firm grasp of Swing and Java fundamentals. This will make your future use of the Swing code generation tool much better and productive.
The textArea cannot be resolved
This message indicates that there is no member class variable called textArea in Prot2Prom. This is possibly a typo. Perhaps the variable is called textarea or defined only locally in the constructor scope.
To work your class would look something like this
public class Prot2Prom extends JFrame {
JTextArea textArea = new JTextArea();
...
A better approach to updating text in a parent component is to create a method to Prot2Prom like so:
public void addText(String text) {
textArea.append(text);
}
This provides more control over how text is added to the JTextArea.

Standards for using inner classes for GUI?

I'm wondering about the standard practice with inner classes (in Java but I suppose it applies to all OO languages).
So I have a JFrame subclass ControllerWindow that contains a JPanel subclass MapPanel which I draw onto (so it needs to overwrite paintComponent method) and which needs to implement a mouse listener. My current solution which works is to have MapPanel in a seperate class implementing MouseListener but when I showed this to the guy who runs my course the other day he seemed to think (we have a bit of a language barrier) this should be in an inner class in ControllerWindow or at least the MouseListener should be an inner class.
So my question is what would be the standard solution here, to put a MouseListener in the inner class, the JPanel in a different inner class or still in its seperate class? The JPanel implementing MouseListener in one inner class? And why?
The most important thing to me is that it works but I'd like to know about and understand the standard practices behind these things if possible.
EDIT: Very simplified version of current code below.
class ControllerWindow extends JFrame{
...
MapPanel drawPanel = new MapPanel();
...
}
and a separate class:
class MapPanel extends JPanel implements MouseListener{
...
public void paintComponent(Graphics g){
...//fillRects etc.
}
//MouseListener methods
public void mouseReleased(MouseEvent e){
requestFocus();
...
repaint()
...
}
public void mousePressed(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
}
Also could this be a situation where it would be acceptable to put both classes in the same file? I don't envisage using MapPanel for anything other than ControllerWindow.
It is common to use anonymous inner classes as event listeners because the code is usually quite simple (so a separate class may be overkill) and keeping the handler code "close" to the code that registers the listener can improve readability for people trying to understand your code, since all code related to the event is in one place.
EDIT: This is particularly true for classes that implement only one listener method. Perhaps less true for multi-method interfaces like MouseListener, since a class that implements the full interface will be more verbose.
I think it's somewhat arbitrary how you go about it (as Tom Hawtin commented, GUI standards=mud), since you're trading off complexity in the number of classes versus complexity in a single class. If you want to produce code simply for a demonstration, a single file might be easiest. If you want code that you're going to put into production and modify/maintain over time, abstracting out into different classes is almost certainly the way you want to go.
For example, if you embed MapPanel as an inner class in ControllerWindow, and then later want to replace it with a different type of MapPanel, you've got a massive update to ControllerWindow rather than just swapping out MapPanel for a different component type.
With the MouseListener, I'd be inclined to include it in MapPanel if it's handling events specifically for that component (that is, if only the MapPanel "knows" what a click means, it should be the one to process that click). I definitely wouldn't put it in ControllerWindow, since then you're "leaking" implementation detail from MapPanel. (The only case I can think of: in addition to your MapPanel, you have multiple panels type that all need to respond to clicks in the same way, so rather than implementing in each panel you could have the ControllerWindow do it. But even then, I'm not sure the code should be in ControllerWindow).
Whether MapPanel's mouse listener is an inner class implementation of MouseListener, or whether MapPanel implements it (as in your code above) probably comes down to a question of which style you prefer.
inner class would be better if it has a simpler syntax.
button1.click( function(event){ do something x... } );
button2.click( function(event){ do something y... } );
radio2.check ( function(event){ do something z... } );
java 7 may give us something like that and change the whole situation. as it is now, using a lot of annonymous inner classes can mess up the code and make it impossible to read. you should choose whichever style that makes your code beautiful and legible.
Because of multiple event handling requirement anonymous inner classes are required. Anonymous class can be written anywhere like in a class, in a method, in the argument. Therefore to abstain from creating many classes for each listener anonymous is preferred.
I found this article useful:
http://www.retrologic.com/innerclasses.doc3.html
In general, when you need to use a method pointer; extend adapter classes as inner classes to simplify your code.

Categories