KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > BoxLayout


1 /*
2  * @(#)BoxLayout.java 1.34 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7  
8
9 package javax.swing;
10
11 import java.awt.*;
12 import java.io.Serializable JavaDoc;
13 import java.io.PrintStream JavaDoc;
14
15 /**
16  * A layout manager that allows multiple components to be laid out either
17  * vertically or horizontally. The components will not wrap so, for
18  * example, a vertical arrangement of components will stay vertically
19  * arranged when the frame is resized.
20  * <TABLE ALIGN="RIGHT" BORDER="0" SUMMARY="layout">
21  * <TR>
22  * <TD ALIGN="CENTER">
23  * <P ALIGN="CENTER"><IMG SRC="doc-files/BoxLayout-1.gif"
24  * alt="The following text describes this graphic."
25  * WIDTH="191" HEIGHT="201" ALIGN="BOTTOM" BORDER="0">
26  * </TD>
27  * </TR>
28  * </TABLE>
29  * <p>
30  * Nesting multiple panels with different combinations of horizontal and
31  * vertical gives an effect similar to GridBagLayout, without the
32  * complexity. The diagram shows two panels arranged horizontally, each
33  * of which contains 3 components arranged vertically.
34  *
35  * <p> The BoxLayout manager is constructed with an axis parameter that
36  * specifies the type of layout that will be done. There are four choices:
37  *
38  * <blockquote><b><tt>X_AXIS</tt></b> - Components are laid out horizontally
39  * from left to right.</blockquote>
40  *
41  * <blockquote><b><tt>Y_AXIS</tt></b> - Components are laid out vertically
42  * from top to bottom.</blockquote>
43  *
44  * <blockquote><b><tt>LINE_AXIS</tt></b> - Components are laid out the way
45  * words are laid out in a line, based on the container's
46  * <tt>ComponentOrientation</tt> property. If the container's
47  * <tt>ComponentOrientation</tt> is horizontal then components are laid out
48  * horizontally, otherwise they are laid out vertically. For horizontal
49  * orientations, if the container's <tt>ComponentOrientation</tt> is left to
50  * right then components are laid out left to right, otherwise they are laid
51  * out right to left. For vertical orientations components are always laid out
52  * from top to bottom.</blockquote>
53  *
54  * <blockquote><b><tt>PAGE_AXIS</tt></b> - Components are laid out the way
55  * text lines are laid out on a page, based on the container's
56  * <tt>ComponentOrientation</tt> property. If the container's
57  * <tt>ComponentOrientation</tt> is horizontal then components are laid out
58  * vertically, otherwise they are laid out horizontally. For horizontal
59  * orientations, if the container's <tt>ComponentOrientation</tt> is left to
60  * right then components are laid out left to right, otherwise they are laid
61  * out right to left.&nbsp; For vertical orientations components are always
62  * laid out from top to bottom.</blockquote>
63  * <p>
64  * For all directions, components are arranged in the same order as they were
65  * added to the container.
66  * <p>
67  * BoxLayout attempts to arrange components
68  * at their preferred widths (for horizontal layout)
69  * or heights (for vertical layout).
70  * For a horizontal layout,
71  * if not all the components are the same height,
72  * BoxLayout attempts to make all the components
73  * as high as the highest component.
74  * If that's not possible for a particular component,
75  * then BoxLayout aligns that component vertically,
76  * according to the component's Y alignment.
77  * By default, a component has a Y alignment of 0.5,
78  * which means that the vertical center of the component
79  * should have the same Y coordinate as
80  * the vertical centers of other components with 0.5 Y alignment.
81  * <p>
82  * Similarly, for a vertical layout,
83  * BoxLayout attempts to make all components in the column
84  * as wide as the widest component.
85  * If that fails, it aligns them horizontally
86  * according to their X alignments. For <code>PAGE_AXIS</code> layout,
87  * horizontal alignment is done based on the leading edge of the component.
88  * In other words, an X alignment value of 0.0 means the left edge of a
89  * component if the container's <code>ComponentOrientation</code> is left to
90  * right and it means the right edge of the component otherwise.
91  * <p>
92  * Instead of using BoxLayout directly, many programs use the Box class.
93  * The Box class is a lightweight container that uses a BoxLayout.
94  * It also provides handy methods to help you use BoxLayout well.
95  * Adding components to multiple nested boxes is a powerful way to get
96  * the arrangement you want.
97  * <p>
98  * For further information and examples see
99  * <a
100  href="http://java.sun.com/docs/books/tutorial/uiswing/layout/box.html">How to Use BoxLayout</a>,
101  * a section in <em>The Java Tutorial.</em>
102  * <p>
103  * <strong>Warning:</strong>
104  * Serialized objects of this class will not be compatible with
105  * future Swing releases. The current serialization support is
106  * appropriate for short term storage or RMI between applications running
107  * the same version of Swing. As of 1.4, support for long term storage
108  * of all JavaBeans<sup><font size="-2">TM</font></sup>
109  * has been added to the <code>java.beans</code> package.
110  * Please see {@link java.beans.XMLEncoder}.
111  *
112  * @see Box
113  * @see java.awt.ComponentOrientation
114  * @see JComponent#getAlignmentX
115  * @see JComponent#getAlignmentY
116  *
117  * @author Timothy Prinzing
118  * @version 1.34 12/19/03
119  */

120 public class BoxLayout implements LayoutManager2, Serializable JavaDoc {
121
122     /**
123      * Specifies that components should be laid out left to right.
124      */

125     public static final int X_AXIS = 0;
126     
127     /**
128      * Specifies that components should be laid out top to bottom.
129      */

130     public static final int Y_AXIS = 1;
131
132     /**
133      * Specifies that components should be laid out in the direction of
134      * a line of text as determined by the target container's
135      * <code>ComponentOrientation</code> property.
136      */

137     public static final int LINE_AXIS = 2;
138
139     /**
140      * Specifies that components should be laid out in the direction that
141      * lines flow across a page as determined by the target container's
142      * <code>ComponentOrientation</code> property.
143      */

144     public static final int PAGE_AXIS = 3;
145
146     /**
147      * Creates a layout manager that will lay out components along the
148      * given axis.
149      *
150      * @param target the container that needs to be laid out
151      * @param axis the axis to lay out components along. Can be one of:
152      * <code>BoxLayout.X_AXIS</code>,
153      * <code>BoxLayout.Y_AXIS</code>,
154      * <code>BoxLayout.LINE_AXIS</code> or
155      * <code>BoxLayout.PAGE_AXIS</code>
156      *
157      * @exception AWTError if the value of <code>axis</code> is invalid
158      */

159     public BoxLayout(Container target, int axis) {
160         if (axis != X_AXIS && axis != Y_AXIS &&
161             axis != LINE_AXIS && axis != PAGE_AXIS) {
162             throw new AWTError("Invalid axis");
163         }
164         this.axis = axis;
165         this.target = target;
166     }
167
168     /**
169      * Constructs a BoxLayout that
170      * produces debugging messages.
171      *
172      * @param target the container that needs to be laid out
173      * @param axis the axis to lay out components along. Can be one of:
174      * <code>BoxLayout.X_AXIS</code>,
175      * <code>BoxLayout.Y_AXIS</code>,
176      * <code>BoxLayout.LINE_AXIS</code> or
177      * <code>BoxLayout.PAGE_AXIS</code>
178      *
179      * @param dbg the stream to which debugging messages should be sent,
180      * null if none
181      */

182     BoxLayout(Container target, int axis, PrintStream JavaDoc dbg) {
183         this(target, axis);
184         this.dbg = dbg;
185     }
186
187     /**
188      * Indicates that a child has changed its layout related information,
189      * and thus any cached calculations should be flushed.
190      * <p>
191      * This method is called by AWT when the invalidate method is called
192      * on the Container. Since the invalidate method may be called
193      * asynchronously to the event thread, this method may be called
194      * asynchronously.
195      *
196      * @param target the affected container
197      *
198      * @exception AWTError if the target isn't the container specified to the
199      * BoxLayout constructor
200      */

201     public synchronized void invalidateLayout(Container target) {
202         checkContainer(target);
203         xChildren = null;
204         yChildren = null;
205         xTotal = null;
206         yTotal = null;
207     }
208
209     /**
210      * Not used by this class.
211      *
212      * @param name the name of the component
213      * @param comp the component
214      */

215     public void addLayoutComponent(String JavaDoc name, Component comp) {
216     }
217
218     /**
219      * Not used by this class.
220      *
221      * @param comp the component
222      */

223     public void removeLayoutComponent(Component comp) {
224     }
225
226     /**
227      * Not used by this class.
228      *
229      * @param comp the component
230      * @param constraints constraints
231      */

232     public void addLayoutComponent(Component comp, Object JavaDoc constraints) {
233     }
234
235     /**
236      * Returns the preferred dimensions for this layout, given the components
237      * in the specified target container.
238      *
239      * @param target the container that needs to be laid out
240      * @return the dimensions >= 0 && <= Integer.MAX_VALUE
241      * @exception AWTError if the target isn't the container specified to the
242      * BoxLayout constructor
243      * @see Container
244      * @see #minimumLayoutSize
245      * @see #maximumLayoutSize
246      */

247     public Dimension preferredLayoutSize(Container target) {
248     Dimension size;
249     synchronized(this) {
250         checkContainer(target);
251         checkRequests();
252         size = new Dimension(xTotal.preferred, yTotal.preferred);
253     }
254
255         Insets insets = target.getInsets();
256         size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
257         size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
258         return size;
259     }
260
261     /**
262      * Returns the minimum dimensions needed to lay out the components
263      * contained in the specified target container.
264      *
265      * @param target the container that needs to be laid out
266      * @return the dimensions >= 0 && <= Integer.MAX_VALUE
267      * @exception AWTError if the target isn't the container specified to the
268      * BoxLayout constructor
269      * @see #preferredLayoutSize
270      * @see #maximumLayoutSize
271      */

272     public Dimension minimumLayoutSize(Container target) {
273     Dimension size;
274     synchronized(this) {
275         checkContainer(target);
276         checkRequests();
277         size = new Dimension(xTotal.minimum, yTotal.minimum);
278     }
279
280         Insets insets = target.getInsets();
281         size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
282         size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
283         return size;
284     }
285
286     /**
287      * Returns the maximum dimensions the target container can use
288      * to lay out the components it contains.
289      *
290      * @param target the container that needs to be laid out
291      * @return the dimenions >= 0 && <= Integer.MAX_VALUE
292      * @exception AWTError if the target isn't the container specified to the
293      * BoxLayout constructor
294      * @see #preferredLayoutSize
295      * @see #minimumLayoutSize
296      */

297     public Dimension maximumLayoutSize(Container target) {
298     Dimension size;
299     synchronized(this) {
300         checkContainer(target);
301         checkRequests();
302         size = new Dimension(xTotal.maximum, yTotal.maximum);
303     }
304
305         Insets insets = target.getInsets();
306         size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
307         size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
308         return size;
309     }
310
311     /**
312      * Returns the alignment along the X axis for the container.
313      * If the box is horizontal, the default
314      * alignment will be returned. Otherwise, the alignment needed
315      * to place the children along the X axis will be returned.
316      *
317      * @param target the container
318      * @return the alignment >= 0.0f && <= 1.0f
319      * @exception AWTError if the target isn't the container specified to the
320      * BoxLayout constructor
321      */

322     public synchronized float getLayoutAlignmentX(Container target) {
323         checkContainer(target);
324         checkRequests();
325         return xTotal.alignment;
326     }
327
328     /**
329      * Returns the alignment along the Y axis for the container.
330      * If the box is vertical, the default
331      * alignment will be returned. Otherwise, the alignment needed
332      * to place the children along the Y axis will be returned.
333      *
334      * @param target the container
335      * @return the alignment >= 0.0f && <= 1.0f
336      * @exception AWTError if the target isn't the container specified to the
337      * BoxLayout constructor
338      */

339     public synchronized float getLayoutAlignmentY(Container target) {
340         checkContainer(target);
341         checkRequests();
342         return yTotal.alignment;
343     }
344
345     /**
346      * Called by the AWT <!-- XXX CHECK! --> when the specified container
347      * needs to be laid out.
348      *
349      * @param target the container to lay out
350      *
351      * @exception AWTError if the target isn't the container specified to the
352      * BoxLayout constructor
353      */

354     public void layoutContainer(Container target) {
355     checkContainer(target);
356     int nChildren = target.getComponentCount();
357     int[] xOffsets = new int[nChildren];
358     int[] xSpans = new int[nChildren];
359     int[] yOffsets = new int[nChildren];
360     int[] ySpans = new int[nChildren];
361         
362     Dimension alloc = target.getSize();
363     Insets in = target.getInsets();
364     alloc.width -= in.left + in.right;
365     alloc.height -= in.top + in.bottom;
366
367         // Resolve axis to an absolute value (either X_AXIS or Y_AXIS)
368
ComponentOrientation o = target.getComponentOrientation();
369         int absoluteAxis = resolveAxis( axis, o );
370         boolean ltr = (absoluteAxis != axis) ? o.isLeftToRight() : true;
371
372
373     // determine the child placements
374
synchronized(this) {
375         checkRequests();
376         
377         if (absoluteAxis == X_AXIS) {
378         SizeRequirements.calculateTiledPositions(alloc.width, xTotal,
379                              xChildren, xOffsets,
380                              xSpans, ltr);
381         SizeRequirements.calculateAlignedPositions(alloc.height, yTotal,
382                                yChildren, yOffsets,
383                                ySpans);
384         } else {
385         SizeRequirements.calculateAlignedPositions(alloc.width, xTotal,
386                                xChildren, xOffsets,
387                                xSpans, ltr);
388         SizeRequirements.calculateTiledPositions(alloc.height, yTotal,
389                              yChildren, yOffsets,
390                              ySpans);
391         }
392     }
393
394         // flush changes to the container
395
for (int i = 0; i < nChildren; i++) {
396             Component c = target.getComponent(i);
397             c.setBounds((int) Math.min((long) in.left + (long) xOffsets[i], Integer.MAX_VALUE),
398                         (int) Math.min((long) in.top + (long) yOffsets[i], Integer.MAX_VALUE),
399                         xSpans[i], ySpans[i]);
400
401         }
402         if (dbg != null) {
403             for (int i = 0; i < nChildren; i++) {
404                 Component c = target.getComponent(i);
405                 dbg.println(c.toString());
406                 dbg.println("X: " + xChildren[i]);
407                 dbg.println("Y: " + yChildren[i]);
408             }
409         }
410             
411     }
412
413     void checkContainer(Container target) {
414         if (this.target != target) {
415             throw new AWTError("BoxLayout can't be shared");
416         }
417     }
418     
419     void checkRequests() {
420         if (xChildren == null || yChildren == null) {
421             // The requests have been invalidated... recalculate
422
// the request information.
423
int n = target.getComponentCount();
424             xChildren = new SizeRequirements JavaDoc[n];
425             yChildren = new SizeRequirements JavaDoc[n];
426             for (int i = 0; i < n; i++) {
427                 Component c = target.getComponent(i);
428         if (!c.isVisible()) {
429             xChildren[i] = new SizeRequirements JavaDoc(0,0,0, c.getAlignmentX());
430             yChildren[i] = new SizeRequirements JavaDoc(0,0,0, c.getAlignmentY());
431             continue;
432         }
433                 Dimension min = c.getMinimumSize();
434                 Dimension typ = c.getPreferredSize();
435                 Dimension max = c.getMaximumSize();
436                 xChildren[i] = new SizeRequirements JavaDoc(min.width, typ.width,
437                                                     max.width,
438                                                     c.getAlignmentX());
439                 yChildren[i] = new SizeRequirements JavaDoc(min.height, typ.height,
440                                                     max.height,
441                                                     c.getAlignmentY());
442             }
443             
444             // Resolve axis to an absolute value (either X_AXIS or Y_AXIS)
445
int absoluteAxis = resolveAxis(axis,target.getComponentOrientation());
446
447             if (absoluteAxis == X_AXIS) {
448                 xTotal = SizeRequirements.getTiledSizeRequirements(xChildren);
449                 yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
450             } else {
451                 xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
452                 yTotal = SizeRequirements.getTiledSizeRequirements(yChildren);
453             }
454         }
455     }
456      
457     /**
458      * Given one of the 4 axis values, resolve it to an absolute axis.
459      * The relative axis values, PAGE_AXIS and LINE_AXIS are converted
460      * to their absolute couterpart given the target's ComponentOrientation
461      * value. The absolute axes, X_AXIS and Y_AXIS are returned unmodified.
462      *
463      * @param axis the axis to resolve
464      * @param o the ComponentOrientation to resolve against
465      * @return the resolved axis
466      */

467     private int resolveAxis( int axis, ComponentOrientation o ) {
468         int absoluteAxis;
469         if( axis == LINE_AXIS ) {
470             absoluteAxis = o.isHorizontal() ? X_AXIS : Y_AXIS;
471         } else if( axis == PAGE_AXIS ) {
472             absoluteAxis = o.isHorizontal() ? Y_AXIS : X_AXIS;
473         } else {
474             absoluteAxis = axis;
475         }
476         return absoluteAxis;
477    }
478
479
480     private int axis;
481     private Container target;
482
483     private transient SizeRequirements JavaDoc[] xChildren;
484     private transient SizeRequirements JavaDoc[] yChildren;
485     private transient SizeRequirements JavaDoc xTotal;
486     private transient SizeRequirements JavaDoc yTotal;
487     
488     private transient PrintStream JavaDoc dbg;
489 }
490
491
Popular Tags