Help needed - what are the Pros and Cons?

Hi Swing masters! :)

I was told that I should post this Q here and that Camickr and a few other might have some more specific answers.

I'm new to Java and programming and trying to establish some good habits from the beginning. Therefore I'm very interested in knowing the Pros and Cons for each end every of the following approaches.

What is good, what is bad, should some of them be avoided etc?

I hope someone with Swing experience can answer these questions. Thanks. :)

Kind regards,

Stefan

class ExperimentGUI

{

void ExperimentGUI()// Example A

{

JFrame content =new JFrame();

JTextArea textView =new JTextArea();

textView.setPreferredSize(new Dimension(300,300));

content.add(textView, BorderLayout.CENTER);

content.pack();

content.setLocationRelativeTo(null);

content.setVisible(true);

}

}

class ExperimentGUIextends JFrame

{

void ExperimentGUI()// Example B

{

JTextArea textView =new JTextArea();

textView.setPreferredSize(new Dimension(300,300));

add(textView, BorderLayout.CENTER);

pack();

setLocationRelativeTo(null);

setVisible(true);

}

}

class ExperimentGUI

{

ExperimentGUI()// Example C

{

JFrame content =new JFrame();

JPanel pane =new JPanel(new BorderLayout());

JTextArea textView =new JTextArea();

textView.setPreferredSize(new Dimension(300,300));

pane.add(textView, BorderLayout.CENTER);

content.setContentPane(pane);

content.pack();

content.setLocationRelativeTo(null);

content.setVisible(true);

}

}

class ExperimentGUIextends JFrame

{

ExperimentGUI()// Example D

{

JPanel content =new JPanel(new BorderLayout());

JTextArea textView =new JTextArea();

textView.setPreferredSize(new Dimension(300,300));

content.add(textView, BorderLayout.CENTER);

setContentPane(content);

pack();

setLocationRelativeTo(null);

setVisible(true);

}

}

class ExperimentGUIextends JFrame

{

ExperimentGUI()// Example E

{

MyPanel pane =new MyPanel();

setContentPane(pane);

pack();

setLocationRelativeTo(null);

setVisible(true);

}

}

class MyPanelextends JPanel

{

public MyPanel(){

setLayout(new BorderLayout());

JTextArea textView =new JTextArea();

textView.setPreferredSize(new Dimension(300,300));

add(textView, BorderLayout.CENTER);

}

}

class ExperimentGUIextends JFrame

{

ExperimentGUI()// Example F

{

MyPanel pane =new MyPanel();

add(pane);

pack();

setLocationRelativeTo(null);

setVisible(true);

}

}

class MyPanelextends JPanel

{

public MyPanel(){

setLayout(new BorderLayout());

JTextArea textView =new JTextArea();

textView.setPreferredSize(new Dimension(300,300));

add(textView, BorderLayout.CENTER);

}

}

[5991 byte] By [StefanHansena] at [2007-11-26 20:58:27]
# 1

you can forget B and D - composition if preferable to inheritance

A and C, the only difference seems to be setContentPane Vs contentPane.add

I prefer contentPane.add, but I've not seen any arguments either way

E and F (forgetting similarity to B and D), extending JPanel appears to add no

additional functionality to JPanel (as in paintComponent() etc), so the better

approach would be to convert the extended JPanel class to a method that

returns a JPanel

class ExperimentGUI extends JFrame

{

ExperimentGUI() // Example F

{

//MyPanel pane = new MyPanel();

//add(pane);

add(getPanel());//<--

pack();

setLocationRelativeTo(null);

setVisible(true);

}

public JPanel getPanel()

{

JPanel p = new JPanel();

p.setLayout(new BorderLayout());

JTextArea textView = new JTextArea();

textView.setPreferredSize(new Dimension(300,300));

p.add(textView, BorderLayout.CENTER);

return p;

}

}

Michael_Dunna at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 2
My goodness - more possibilities! WHY not B or D? A lot of people seem to prefer this. Regards, Stefan
StefanHansena at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 3
> WHY not B or D? A lot of people seem to prefer this. not the people that count
Michael_Dunna at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 4
How am I (someone with one month of programming "experience" in my bag") supposed to use an answer like that?
StefanHansena at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 5

> How am I ... supposed to use an answer like that?

well, who are the people that prefer inheritance?

are they professional developers?

are they forum members who have posted a problem (with code example)?

if so, do they indicate they are relatively new to java/programming (by where the posts are)?

etc, etc

google "composition vs inheritance", you'll most likely find some good reads

Michael_Dunna at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 6

Well, in most of the examples I've seen on the net people use "...extends JFrame" and so does a friend of mine who has been a professional programmer for something like 25 years.

But I'm interested in other viewpoints - therefore I post my Q here.

I like the idea of having JPanels as methods to keep things separated. Extending JFrame or not... I'm not yet(!) convinced. :)

StefanHansena at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 7

> Well, in most of the examples I've seen on the net people use "...extends JFrame"

Well, I'm probably one of the bigest offenders (in this forum at least)

> google "composition vs inheritance", you'll most likely find some good reads

Not know the difference between the two (I'm a problem solver, not a designer), I figured I should take up the challenge.

So one of the first links I read said:

Object composition and inheritance are two techniques for reusing functionality in object-oriented systems

So I'm thinking how do you reuse a JFrame? Maybe if you build the frame with a menu bar or toolbar you could reuse some of the components but you don't reuse the entire frame. So it seems to me that the reuse aspect of inheritance or composition doesn't apply.

Next link I read said:

Make sure inheritance models the is-a relationship

Now this makes sense to me. Lets say I'm creating a MineSweeper Game. Lets create a class with the following signature:

public class MineSweeper extends JFrame

This obviously does not follow the is-a relationship rule. MineSweeper is-a Game, not a JFrame.

So, I guess I'll have to update all my examples to use composition, so I don't mislead others on the forum.

camickra at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 8
Camickr, you are being ironic - right? If I understand you correctly you use "... extends JFrame" with succes. No need to change anything if it works great. What is your point of view? ( without the irony :)
StefanHansena at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 9

If you keep an eye on this forum you'll see a number of posts along the lines of "how to convert my Swing app to an applet?" or otherwise converting some hacked-together JFrame extension to suit another purpose.

These people discover why inheritance should only be used where polymorphism is specifically required, not as a way of saving a few lines of code. Cook things into a JFrame and all you've got is a JFrame. Want to display that in a web page? You're stuffed. Want to display it in a dialog? You're stuffed.

It never fails to anger me that every reference book I've ever seen teaches Swing by extending JFrame - even the better books like Thinking in Java do it. It's a really bad idea. In fact the whole GUI arena seems to be largely unenlightened in terms of the fact that inheritance isn't smart. It's not just JFrame, it's rife.

The idea of "no need to change anything if it works great" is great if you're in a classroom. In the real world requirements change, rewriting code costs money, and using composition over inheritance will save you a lot of grief when the design changes or you want to reuse a component.

I've never once encountered a justifiable real world case for extending JFrame.

itchyscratchya at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 10

And for what it's worth I don't like any of your examples. A and C are close but I'm troubled by the idea of a constructor which pops up a frame, and I'm not keen on the fact that A makes an assumption of a BorderLayout being in place.

I would suggest something like the following class as a basic application class:

public class Application

{

public static void main(String[] args)

{

new Application().start();

}

protected void start()

{

SwingUtilities.invokeLater(new Launcher());

}

protected abstract JComponent createUI()

{

return new MyMainUIComponent();

}

private static class Launcher implements Runnable

{

public void run()

{

JFrame f = new JFrame();

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setContentPane(createUI());

f.pack();

// plus some code to stop the frame exceeding the available screen space

f.setLocationRelativeTo(null);

f.setVisible(true);

}

}

}

itchyscratchya at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 11
Thanks itchy...! That is something I can use. :)
StefanHansena at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 12
.invokelater and Runnable - more stuff to learn, oh no.
StefanHansena at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 13

So I'm thinking how do you reuse a JFrame? Maybe if you build the frame with a menu bar or toolbar you could reuse some of the components but you don't reuse the entire frame. So it seems to me that the reuse aspect of inheritance or composition doesn't apply.

It's reuse in the sense of reusing the library code in JFrame rather than reusing your own specific setup (though you could do that too) - you can do that by inheritance (ie "Foo extends JFrame") or by composition (ie "JFrame f = new JFrame(); f.setContentPane(new Foo());")

The latter retains maximum flexibility, since you can now put a Foo in any part of a UI.

itchyscratchya at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 14
.invokelater and Runnable - more stuff to learn, oh no.Absolutely fundamental to writing Swing apps. Go to Google, type "java swing threading" and hit I'm feeling lucky...
itchyscratchya at 2007-7-10 2:27:58 > top of Java-index,Desktop,Core GUI APIs...
# 15
Brilliant.
StefanHansena at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 16
> and I'm> not keen on the fact that A makes an assumption of a> BorderLayout being in place.Why not? It should be okay, I think... "Lastly, after seven years, we've made jFrame.add equivalent to jFrame.getContentPane().add()." - Sun
StefanHansena at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 17

"Lastly, after seven years, we've made jFrame.add equivalent to jFrame.getContentPane().add()."

That's nothing to do with it - it's a case of what default LayoutManager is installed. Though to be fair I've just checked the API and it does say that it will be BorderLayout.

I still prefer to adopt the general approach of not trusting other classes to do things which aren't explicit from their API, though. This particular one is highly unlikely to change, but it's good practice to avoid the case where you make an assumption that implementations of certain classes won't change in the future.

DefaultTreeCellRenderer illustrates my point (a bit) - it extends JLabel (inheritance over composition again - gack) but nowhere in its API does it explicitly say that it returns itself as the renderer. It would be quite within its rights to return any other component as the cell renderer. That's not going to happen via a Sun change but you could get unstuck by making assumptions: let's say you create an extension which normally returns itself but in the case of certain cells it returns a JPanel instead. Now anything which tests for "instanceof DefaultTreeCellRenderer" might assume that the component it supplies is always a JLabel, but that's no longer the case. Bottom line: there's no contractual obligation to return anything other than a Component, so that's all that should be relied upon.

itchyscratchya at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 18

> And for what it's worth I don't like any of your

> examples. A and C are close but I'm troubled by the

> idea of a constructor which pops up a frame, and I'm

> not keen on the fact that A makes an assumption of a

> BorderLayout being in place.

>

> I would suggest something like the following class as

> a basic application class:

>

> public class Application

> {

>public static void main(String[] args)

> {

> new Application().start();

>

>protected void start()

> {

> SwingUtilities.invokeLater(new Launcher());

>

>protected abstract JComponent createUI()

> {

> return new MyMainUIComponent();

>

> private static class Launcher implements

> Runnable

>{

>public void run()

>{

> JFrame f = new JFrame();

>f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

> f.setContentPane(createUI());

>f.pack();

> // plus some code to stop the frame

> exceeding the available screen space

>f.setLocationRelativeTo(null);

> f.setVisible(true);

>}

> }

Wow. in terms of reusebility, this is a pretty complex way to archieve something simnple.

I would not prefer that. If the maintainance programmer is not that faimilar with swing he would have less problems understanding the extends/custructor orientated way. they are obvious to everyone with basic OO knowledge.

It really depends on who might reuse your code...

jEti182a at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 19

Wow. in terms of reusebility, this is a pretty complex way to archieve something simnple.

I would not prefer that. If the maintainance programmer is not that faimilar with swing he would have less problems understanding the extends/custructor orientated way. they are obvious to everyone with basic OO knowledge.

I'm not sure I see the argument here. No, check that, I'm sure I don't see an argument here.

This class has ten lines of code. It is not complex. It uses the invokeLater() mechanism because not doing so would risk deadlocking the application. It uses all the code that would be required by an inheritance model except that it includes a line which constructs a JFrame in place of an "extends" keyword. There is nothing in that class which is not both required and obvious to anyone with basic OO knowledge. If you wanted to compact it a bit you could ditch the inner class and make the Application expose the Runnable interface, but that's it.

Are you suggesting that it would be wise to ditch writing good reusable code simply to save one line of code and allow maintenance staff to somehow not understand what "new JFrame()" does, despite knowing how "extends" works?

Sorry, but if you have Java maintenance staff who cannot understand that class then you have a serious problem. I appreciate that the "invokeLater()" usage won't be familiar to anyone with no knowledge of Swing, but that doesn't mean it should be dropped, because doing so risks deadlock. You wouldn't adopt a policy of never using keywords like "synchronized" or "transient" just because one of your support guys might not understand the implications.

itchyscratchya at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 20

No, im not suggesting something like that.

You're definately right.

All i wantet to say is, that it depends on who will use your code.

And if you have a java "maintainance staff" your lucky anyway :)

If someone not knowing Java at all is forced to use your code he would be thankful if things were kept simple.

Of course sou should not write bad but simple code :)

Java is often used for teaching OO concepts and there for things like extending JFrame helps understandingthe language and OO.

But if it comes to serious programming you are right of course.

i'm usually not using invokeLater for for creating frames... when can it deadlock?

jEti182a at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 21

Java is often used for teaching OO concepts and there for things like extending JFrame helps understandingthe language and OO.

My opinion on this is that the practices that are introduced when learning tend to get stuck in people's methodologies. Teaching bad ideas is counter-productive, even if they make other things slightly easier - if the idea is to teach OO then the teaching should explain the "inheritance bad, composition good" guideline, rather than needlessly violate it from day one.

In all honesty I don't believe it's to make examples easier to understand. I believe it's done to make examples a very few lines of code shorter.

I believe people would only think it's harder to understand because the "wrong way" is more familiar to them. From any other starting point, it really is no more complex.

i'm usually not using invokeLater for for creating frames... when can it deadlock?

In practice I doubt that creating the first frame of an application will deadlock if called off the EDT. However, once the event thread is up and running and being hit with events, there is the risk of thread conflict if any Swing code is called from outside the EDT. So, it's just not worth taking the risk - and again, it's a case of being in the habit of Good Practice rather than not taking care.

itchyscratchya at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 22

@itchyscratchy

I fully agree with your arguments.

When you say you were a little troubled by the constructor that pops up a JFrame, I would go further : that one really made my eyes bleed. What's next ? Why not doing the same with a modal JDialog and have the constructor hang until the dialog is disposed ? This is definitely NOT what constructors are supposed to do.

weebiba at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 23
Okay, I know this. But I thought I this way could post less code so you guys didn't have to spend to much time answering my Q. The question was mostly about using "extends JFrame" or not. My mistake.
StefanHansena at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 24

Actually, you were not the only target of this comment ;) . I've seen that so many times that I've started to suspect that this must be present in some swing tutorial out there.

On more general grounds, I tend to dislike constructors that do more than their basic purpose, that is initializing the different members.

weebiba at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 25
Well, you did ask "What is good, what is bad, should some of them be avoided etc?" which seemed to leave the floor fairly open ;o)
itchyscratchya at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 26
On more general grounds, I tend to dislike constructors that do more than their basic purpose, that is initializing the different members.Agreed.
itchyscratchya at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 27

Sorry guys, I don't always deal with "abstract" concepts very well. I need "concrete" examples to explain a design pattern. The original question was about extending JFrame:

So I'll ask my question with a simple concrete example. Lets build a simple MineSweeper game. The game has two basic components

a) a JMenuBar so you can replay the game

b) a GameComponent where you actually play the game.

Now we want to make our class "reusable" so it can be used in a JFrame a JApplet or whatever, so we build the class something like this:

public class MineSweeperUI

{

public JMenuBar getMenuBar()

{

return new JMenuBar();

}

public JComponent getGameComponent()

{

return new JPanel();

}

}

Now when we decide we want to play MineSweeper in a JFrame we need to create another class, so we do something like this:

public class MineSweeperFrame extends JFrame

{

public MineSweeperFrame()

{

MineSweeperUI ms = new MineSweeperUI();

setJMenBar( ms.getMenuBar() );

getContentPane().add( ms.getGameComponent() );

setDefaultCloseOperation( EXIT_ON_CLOSE );

pack();

}

public static void main(String[] args)

{

new MineSweeperFrame().setVisible(true);

}

}

Since the sole purpose of this class is to play MineSweeper in a JFrame what is wrong with extending JFrame, since this class is truly meant to be a JFrame?

Is it fair to say:

a) that if you want to use inheritance, then you need to break your application up into multiple classes, something like my simple example

b) that if you want to use composition, then you would use the approach provided by itchyscratchy in reply 10.

c) that you should never use a single class and implement inheritance.

camickra at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 28
Great - a concrete example! With some Q's that I'm NOT the one to answer. ;)
StefanHansena at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 29

> [...]

> Since the sole purpose of this class is to play

> MineSweeper in a JFrame what is wrong with extending

> JFrame, since this class is truly meant to be a

> JFrame?

I don't think there is anything wrong.

On the other hand, for what it's worth, I would have coded something like this :public class MineSweeperFactory {

public JFrame createMineSweeperFrame() {

MineSweeperUI ms = new MineSweeperUI();

JFrame frame = new JFrame("Minesweeper");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setJMenuBar(ms.getMenuBar());

frame.setContentPane(ms.getGameComponent());

frame.pack();

return frame;

}

public JDialog createMineSweeperDialog(JFrame aParentFrame, boolean isModal) {

MineSweeperUI ms = new MineSweeperUI();

JDialog dialog = new JDialog(aParentFrame, "Minesweeper", isModal);

dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);

dialog.setJMenuBar(ms.getMenuBar());

dialog.setContentPane(ms.getGameComponent());

dialog.pack();

return dialog;

}

}

> Is it fair to say:

>

> a) that if you want to use inheritance, then you need

> to break your application up into multiple classes,

> something like my simple example

Yes

> b) that if you want to use composition, then you

> would use the approach provided by itchyscratchy in

> reply 10.

Yes

> c) that you should never use a single class and

> implement inheritance.

Definitely.

weebiba at 2007-7-21 18:07:46 > top of Java-index,Desktop,Core GUI APIs...
# 30

> On the other hand, for what it's worth, I would have coded something like this :

Interesting, you seem to be going to a lot of trouble to avoid extending a JFrame.

So I go back to the orginal pseudo requirement of supporting an applet. How would you support a JApplet using this approach?

Using my approach the code would be something like:

public class MineSweeperApplet extends JApplet

{

public void init()

{

MineSweeperUI ms = new MineSweeperUI();

setJMenBar( ms.getMenuBar() );

getContentPane().add( ms.getGameComponent() );

setDefaultCloseOperation( EXIT_ON_CLOSE );

pack();

}

}

Given, that you need to override the init() method for an applet, I don't see how this can be done in the MineSweeperFactory without creating an InnerClass or something. This seems to me to be a lot of work to simply avoid extending JApplet.

camickra at 2007-7-21 18:07:50 > top of Java-index,Desktop,Core GUI APIs...
# 31

> > On the other hand, for what it's worth, I would

> have coded something like this :

>

> Interesting, you seem to be going to a lot of trouble

> to avoid extending a JFrame.

I personally don't see where the trouble is (both versions are about the same length).

I told you honestly what I would do in such a case. Since I started coding java, as far as I can remember, I've never extended JFrame. If you don't want to believe me, there's not much I can do.

As far as the JApplet is concerned :

- I've never used any;

- should I use one, of course I would subclass it since it's required.

weebiba at 2007-7-21 18:07:50 > top of Java-index,Desktop,Core GUI APIs...
# 32

Ditto weebib :o) ...except I have used JApplet, and yes, you have to extend it, naturally.

@camickr: Extending JFrame in that "lightweight" way you suggest - I don't see any problem with that either, but I'm also of the opinion that there's no real difference between the two in terms of length and complexity, and my preference would also be the non-extension way simply because it sticks to the guideline of "don't extend unless you need polymorphism." I agree with your three points.

itchyscratchya at 2007-7-21 18:07:50 > top of Java-index,Desktop,Core GUI APIs...