The Java Specialists' Newsletter [Issue 041] - Placing components
on each other
Author: Dr. Heinz M. Kabutz
JDK version:
Category: GUI
You can subscribe from our home page:
http://www.javaspecialists.co.za (which also hosts all previous issues,
available free of charge
Welcome to the 41th (or is it 41st?) edition of The Java(tm) Specialists'
Newsletter, sent to 2690 Java experts in over 74 countries. This newsletter
is for those that want to be able to stump their interviewer when they get tough
Java interview questions. e.g. "Will this compile?"
public class FastString extends java.lang.String {
private int hash = 0;
public FastString(char[] value) {
super(value);
}
public int hashCode() {
if (hash == 0) {
hash = super.hashCode();
}
return hash;
}
}
Normal Java programmers would answer: "No.", but ardent followers of this
newsletter will answer: "Have the JDK classes been modified in any way? With an
unmodified JDK this would not compile, but if you made String non-final it would
compile. You would also have to make it non-final in the runtime; otherwise you
would get a runtime error. However, since JDK 1.3, it has not been necessary to
cache the hash code in a subclass of String as that is done already inside
String." This will so amaze the interviewer that you will have that hot job
doing Java development in no time!
Right now, I should've been in Mauritius presenting my Java course, and next
week would've been my Design Patterns course. Of all the obstacles that courses
face, this time we faced a French-style bureaucracy in Mauritius Everything
was organised: we had enough attendants, the hotel was booked, my flight was
booked. However, we could not get the correct government approval in time, so I
will have to wait a bit longer before I can go "teach in the sun" again. In the
meantime I'm trying to learn that strange "sport" that all the sales people play
- golf. (OK, I admit - I've been playing golf instead of writing newsletters
*blush*)
Placing components on each other
Two weeks ago, I was presenting my course Design Patterns - The Timeless
Way of Coding to some experienced Java developers, and we spent quite a bit
of time arguing about the Composite pattern. To refresh your memory, the
book on OO Design Patterns by Erich Gamma et al, contains the following classes
in the structure section on Composite:
public abstract class Component {
public void add(Component c) {}
public void remove(Component c) {}
public abstract void operation();
}
public class Leaf extends Component {
public void operation() { /* do something */ }
}
public class Composite {
private java.util.List children = new java.util.LinkedList();
public void add(Component c) { children.add(c); }
public void remove(Component c) { children.remove(c); }
public void operation() {
// or my cool VisitingIterator from last week
java.util.Iterator it = children.iterator();
while(it.hasNext()) {
((Component)it.next()).operation();
}
}
}
The question we were kicking around was: "Why are the add() and
remove() methods in the top-level Component class?"
For an excellent discussion around this question, have a look at the Pattern
Hatching column by John Vlissides in the September 2001 edition of
Java Report.
Hoping to have whet your appetite, I will not pursue that discussion further
here, but instead jump over to the JDK. A few years ago, I was looking at the
Composite pattern and comparing it to the java.awt.Component. I
found it interesting that java.awt.Component did not contain the
add() and remove() methods, those were contained in
the subclass java.awt.Container. However, when I looked at
javax.swing.JComponent I noticed that it extended
java.awt.Container and therefore contained the methods add()
and remove().
The big question is: Why? Was it done like this because Java does not
have multiple inheritance or was it done to more closely follow the
Composite pattern? My bet is on multiple inheritance being the reason, but if
you have reliable information (not speculation) I'd love to hear from you.
So, how do you put this to use?
Multi-lined button
Say for example you want to have a JButton with multiple lines of labels on
it. One way is to use HTML text, but then the default font is different to the
normal JButton font. An answer is to stick a few JLabels on top of a JButton
(remember that JButton extends AbstractButton extends JComponent extends
Container). You can make such a button by doing the following:
import javax.swing.*;
import java.awt.*;
public class MultilineButton {
public static void main(String[] args) {
JButton button = new JButton();
// It is important to set the layout manager of the button
button.setLayout(new GridLayout(0, 1));
// Then we simply add components to it!
button.add(new JLabel("This is a", JLabel.CENTER));
button.add(new JLabel("multiline", JLabel.CENTER));
button.add(new JLabel("button.", JLabel.CENTER));
JFrame f = new JFrame("Multi-line Button");
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(button);
f.setSize(100,100);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.show();
}
}
This will produce a button with several lines on it. The problem with that
example is that the focus of the button is not shown.
Checkbox on a Button
What we can also do is put a JCheckBox (or any Component for that matter) on
top of a JButton. This can be used to make really confusing user
interfaces. Please don't actually do this, I'm just illustrating something
here...
import javax.swing.*;
import java.awt.*;
public class CheckBoxOnButton {
public static void main(String[] args) {
JButton records = new JButton();
records.setLayout(new BorderLayout());
records.add(new JLabel("Show Records"), BorderLayout.NORTH);
records.add(new JCheckBox("autoscroll"), BorderLayout.CENTER);
JFrame f = new JFrame("CheckBox on Button");
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(records);
f.setSize(200,200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.show();
}
}
Not very useful? You've seen nothing yet!
Why not a Tree on a Button?
Of course, if we can add a JCheckBox to a JButton, why can we not add a JTree
to a JButton? Here's an example of how you can do that:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
public class TreeOnButton {
public static void main(String[] args) {
JButton button = new JButton();
button.setLayout(new BorderLayout());
final JLabel buttonText = new JLabel("Press me",
JLabel.CENTER);
button.add(buttonText, BorderLayout.NORTH);
JTree tree = new JTree();
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
buttonText.setText("Press for " +
e.getPath().getLastPathComponent());
}
});
button.add(tree, BorderLayout.CENTER);
JFrame f = new JFrame("Tree on Button");
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(button);
f.setSize(500,500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.show();
}
}
Well, there you go. I have not found any IDE's which support this
functionality directly, and I would be surprised if there was such an IDE. You
should not really add complex components to each other, as it will confuse your
users. Imagine trying to write a user manual for buttons containing trees and
check boxes!
This was again one of the funnest newsletters to write, I'm looking forward
to your feedback
Kind regards
Heinz
Copyright 2000-2004 Maximum Solutions, South Africa
Reprint Rights. Copyright subsists in all the material included
in this email, but you may freely share the entire email with anyone you feel
may be interested, and you may reprint excerpts both online and offline provided
that you acknowledge the source as follows: This material from The Java(tm)
Specialists' Newsletter by Maximum Solutions (South Africa). Please contact
Maximum Solutions for more
information.
Java and Sun are trademarks or registered trademarks of Sun Microsystems,
Inc. in the United States and other countries. Maximum Solutions is independent
of Sun Microsystems, Inc.
9185 bytes more | comments? | | Score: 4
|