bb.gui
Class ComponentUtil

java.lang.Object
  extended by bb.gui.ComponentUtil

public class ComponentUtil
extends Object

Provides static utility methods that deal with Components.

Like typical Java GUI code, this class is not multithread safe: it expects to only be called by EventQueue's dispatch thread. This threading limitation is checked in every public method.

Author:
Brent Boyer

Constructor Summary
private ComponentUtil()
          This sole private constructor suppresses the default (public) constructor, ensuring non-instantiability outside of this class.
 
Method Summary
private static void appendComponentTree(Component component, Set<Component> set)
           
static Set<Component> getComponentTree(Component component)
          Drills depth first down the Component tree rooted at component, returning a Set of all the Components that were encountered.
static Window getParentWindow(Component component)
          Returns component itself if it is a Window, or the first (should only be one?)
static LinePanel label(String labelText, Component component)
          "Labels" component.
static void paintComponentTree(Component component, Graphics g)
          Drills depth first down the Component tree rooted at component.
static void setHeightMaxToPref(Component component)
          Sets just the maximum height of component to its preferred height; the maximum width is left unchanged.
static void setWidthMaxToPref(Component component)
          Sets just the maximum width of component to its preferred height; the maximum height is left unchanged.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

ComponentUtil

private ComponentUtil()
This sole private constructor suppresses the default (public) constructor, ensuring non-instantiability outside of this class.

Method Detail

getComponentTree

public static Set<Component> getComponentTree(Component component)
                                       throws IllegalArgumentException,
                                              IllegalStateException
Drills depth first down the Component tree rooted at component, returning a Set of all the Components that were encountered.

The result is based off of an IdentityHashMap, so reference-equality semantics are used instead of equals. Thus, a Component is always added to the result, unless that exact same reference has already been encountered in the tree. (It is possible in theory, if unlikely in practice, that the Component tree contains a given Component more than once. For example, a JLabel instance could be added to more than one JPanel.)

Altho each Component is added to the result in the order that it is encountered during the search, the iteration order of the result is essentially random as per the behavior of IdentityHashMap.

Contract: the result is never null, and always contains at least component itself.

Throws:
IllegalArgumentException
IllegalStateException

appendComponentTree

private static void appendComponentTree(Component component,
                                        Set<Component> set)
                                 throws IllegalArgumentException,
                                        IllegalStateException
Throws:
IllegalArgumentException
IllegalStateException

paintComponentTree

public static void paintComponentTree(Component component,
                                      Graphics g)
                               throws IllegalArgumentException,
                                      IllegalStateException
Drills depth first down the Component tree rooted at component. At each Component node in that tree, paints the edges of that rectangle which describes the location and size of the node.

Motivation: this method can be invaluable in debugging complex form layouts, as it can show what components (especially normally invisible ones like Panels or other Containers) are taking up a lot of space.

To see how this method can be used, suppose that a Displayer instance is being used to show the GUI. Then the user could subclass Displayer like below to override its paint method to additionally call this method:


                public class Displayer2 extends Displayer {

                        private static final long serialVersionUID = 0;

                        public Displayer2(JComponent jcomponent, String title, String prefsName) throws IllegalArgumentException, IllegalStateException {
                                super(jcomponent, title, prefsName);
                        }

                        @Override public void paint(Graphics g) throws IllegalArgumentException, IllegalStateException {
                                super.paint(g);
                                ComponentUtil.paintComponentTree(this, g);      // CRITICAL: do this last, since do not want other painting events to overpaint the Component outlines done here
                        }

                }
 
The code above will ensure that the bounds of every Component in the GUI is drawn, because it gets the Component tree from a top level window.

A top level window need not be used: a lower level Component in the tree could also be supplied to this method. In this case, the outlines of only those Components inside the supplied one will be drawn. Unfortunately, there could be subsequent painting events which overpaint these outlines. For that reason, using the top level window, as in the code above, may work best.

Throws:
IllegalArgumentException
IllegalStateException

getParentWindow

public static Window getParentWindow(Component component)
                              throws IllegalArgumentException,
                                     IllegalStateException
Returns component itself if it is a Window, or the first (should only be one?) parent Window which contains component if it is inside a Window, or null if it is not inside a Window.

Throws:
IllegalArgumentException - if component == null
IllegalStateException - if calling thread is not EventQueue's dispatch thread

label

public static LinePanel label(String labelText,
                              Component component)
                       throws IllegalArgumentException,
                              IllegalStateException
"Labels" component. In particular, returns a new LinePanel which contains a single row of children: a new JLabel with labelText on the left, followed by component on the right.

Motivation: this method was originally written make the labelling of JTextFields, a typical requirement in GUI forms, be very convenient.

Warning: this method is unsuitable for complex forms, because these typically need inter-row alignment among the labels to visually look right. For situations like these, more complex techniques must be used (e.g. GroupLayout, TableLayout).

Throws:
IllegalArgumentException - if labelText is blank; component == null
IllegalStateException - if calling thread is not EventQueue's dispatch thread

setHeightMaxToPref

public static void setHeightMaxToPref(Component component)
                               throws IllegalArgumentException,
                                      IllegalStateException
Sets just the maximum height of component to its preferred height; the maximum width is left unchanged.

A great example of where this method is needed is JTextField: for some strange reason, the designer of this widget did not make its height rigid (e.g. like a JLabel). Consequently, when placed into certain forms and with certain layout managers, JTextFields can be vertically stretched. This is bad because it deceitfully makes them look like a JTextArea, and also causes them to eat up valuable free space that might be more usefully devoted to another component that could actually use the space (e.g. a JTextArea).

Throws:
IllegalArgumentException - if component == null
IllegalStateException - if calling thread is not EventQueue's dispatch thread

setWidthMaxToPref

public static void setWidthMaxToPref(Component component)
                              throws IllegalArgumentException,
                                     IllegalStateException
Sets just the maximum width of component to its preferred height; the maximum height is left unchanged.

Throws:
IllegalArgumentException - if component == null
IllegalStateException - if calling thread is not EventQueue's dispatch thread