1 /* 2 * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt; 27 28 /** 29 * The <code>GridLayout</code> class is a layout manager that 30 * lays out a container's components in a rectangular grid. 31 * The container is divided into equal-sized rectangles, 32 * and one component is placed in each rectangle. 33 * For example, the following is an applet that lays out six buttons 34 * into three rows and two columns: 35 * <p> 36 * <hr><blockquote> 37 * <pre> 38 * import java.awt.*; 39 * import java.applet.Applet; 40 * public class ButtonGrid extends Applet { 41 * public void init() { 42 * setLayout(new GridLayout(3,2)); 43 * add(new Button("1")); 44 * add(new Button("2")); 45 * add(new Button("3")); 46 * add(new Button("4")); 47 * add(new Button("5")); 48 * add(new Button("6")); 49 * } 50 * } 51 * </pre></blockquote><hr> 52 * <p> 53 * If the container's <code>ComponentOrientation</code> property is horizontal 54 * and left-to-right, the above example produces the output shown in Figure 1. 55 * If the container's <code>ComponentOrientation</code> property is horizontal 56 * and right-to-left, the example produces the output shown in Figure 2. 57 * <p> 58 * <center><table COLS=2 WIDTH=600 summary="layout"> 59 * <tr ALIGN=CENTER> 60 * <td><img SRC="doc-files/GridLayout-1.gif" 61 * alt="Shows 6 buttons in rows of 2. Row 1 shows buttons 1 then 2. 62 * Row 2 shows buttons 3 then 4. Row 3 shows buttons 5 then 6."> 63 * </td> 64 * 65 * <td ALIGN=CENTER><img SRC="doc-files/GridLayout-2.gif" 66 * alt="Shows 6 buttons in rows of 2. Row 1 shows buttons 2 then 1. 67 * Row 2 shows buttons 4 then 3. Row 3 shows buttons 6 then 5."> 68 * </td> 69 * </tr> 70 * 71 * <tr ALIGN=CENTER> 72 * <td>Figure 1: Horizontal, Left-to-Right</td> 73 * 74 * <td>Figure 2: Horizontal, Right-to-Left</td> 75 * </tr> 76 * </table></center> 77 * <p> 78 * When both the number of rows and the number of columns have 79 * been set to non-zero values, either by a constructor or 80 * by the <tt>setRows</tt> and <tt>setColumns</tt> methods, the number of 81 * columns specified is ignored. Instead, the number of 82 * columns is determined from the specified number of rows 83 * and the total number of components in the layout. So, for 84 * example, if three rows and two columns have been specified 85 * and nine components are added to the layout, they will 86 * be displayed as three rows of three columns. Specifying 87 * the number of columns affects the layout only when the 88 * number of rows is set to zero. 89 * 90 * @author Arthur van Hoff 91 * @since JDK1.0 92 */ 93 public class GridLayout implements LayoutManager, java.io.Serializable { 94 /* 95 * serialVersionUID 96 */ 97 private static final long serialVersionUID = -7411804673224730901L; 98 99 /** 100 * This is the horizontal gap (in pixels) which specifies the space 101 * between columns. They can be changed at any time. 102 * This should be a non-negative integer. 103 * 104 * @serial 105 * @see #getHgap() 106 * @see #setHgap(int) 107 */ 108 int hgap; 109 /** 110 * This is the vertical gap (in pixels) which specifies the space 111 * between rows. They can be changed at any time. 112 * This should be a non negative integer. 113 * 114 * @serial 115 * @see #getVgap() 116 * @see #setVgap(int) 117 */ 118 int vgap; 119 /** 120 * This is the number of rows specified for the grid. The number 121 * of rows can be changed at any time. 122 * This should be a non negative integer, where '0' means 123 * 'any number' meaning that the number of Rows in that 124 * dimension depends on the other dimension. 125 * 126 * @serial 127 * @see #getRows() 128 * @see #setRows(int) 129 */ 130 int rows; 131 /** 132 * This is the number of columns specified for the grid. The number 133 * of columns can be changed at any time. 134 * This should be a non negative integer, where '0' means 135 * 'any number' meaning that the number of Columns in that 136 * dimension depends on the other dimension. 137 * 138 * @serial 139 * @see #getColumns() 140 * @see #setColumns(int) 141 */ 142 int cols; 143 144 /** 145 * Creates a grid layout with a default of one column per component, 146 * in a single row. 147 * @since JDK1.1 148 */ 149 public GridLayout() { 150 this(1, 0, 0, 0); 151 } 152 153 /** 154 * Creates a grid layout with the specified number of rows and 155 * columns. All components in the layout are given equal size. 156 * <p> 157 * One, but not both, of <code>rows</code> and <code>cols</code> can 158 * be zero, which means that any number of objects can be placed in a 159 * row or in a column. 160 * @param rows the rows, with the value zero meaning 161 * any number of rows. 162 * @param cols the columns, with the value zero meaning 163 * any number of columns. 164 */ 165 public GridLayout(int rows, int cols) { 166 this(rows, cols, 0, 0); 167 } 168 169 /** 170 * Creates a grid layout with the specified number of rows and 171 * columns. All components in the layout are given equal size. 172 * <p> 173 * In addition, the horizontal and vertical gaps are set to the 174 * specified values. Horizontal gaps are placed between each 175 * of the columns. Vertical gaps are placed between each of 176 * the rows. 177 * <p> 178 * One, but not both, of <code>rows</code> and <code>cols</code> can 179 * be zero, which means that any number of objects can be placed in a 180 * row or in a column. 181 * <p> 182 * All <code>GridLayout</code> constructors defer to this one. 183 * @param rows the rows, with the value zero meaning 184 * any number of rows 185 * @param cols the columns, with the value zero meaning 186 * any number of columns 187 * @param hgap the horizontal gap 188 * @param vgap the vertical gap 189 * @exception IllegalArgumentException if the value of both 190 * <code>rows</code> and <code>cols</code> is 191 * set to zero 192 */ 193 public GridLayout(int rows, int cols, int hgap, int vgap) { 194 if ((rows == 0) && (cols == 0)) { 195 throw new IllegalArgumentException("rows and cols cannot both be zero"); 196 } 197 this.rows = rows; 198 this.cols = cols; 199 this.hgap = hgap; 200 this.vgap = vgap; 201 } 202 203 /** 204 * Gets the number of rows in this layout. 205 * @return the number of rows in this layout 206 * @since JDK1.1 207 */ 208 public int getRows() { 209 return rows; 210 } 211 212 /** 213 * Sets the number of rows in this layout to the specified value. 214 * @param rows the number of rows in this layout 215 * @exception IllegalArgumentException if the value of both 216 * <code>rows</code> and <code>cols</code> is set to zero 217 * @since JDK1.1 218 */ 219 public void setRows(int rows) { 220 if ((rows == 0) && (this.cols == 0)) { 221 throw new IllegalArgumentException("rows and cols cannot both be zero"); 222 } 223 this.rows = rows; 224 } 225 226 /** 227 * Gets the number of columns in this layout. 228 * @return the number of columns in this layout 229 * @since JDK1.1 230 */ 231 public int getColumns() { 232 return cols; 233 } 234 235 /** 236 * Sets the number of columns in this layout to the specified value. 237 * Setting the number of columns has no affect on the layout 238 * if the number of rows specified by a constructor or by 239 * the <tt>setRows</tt> method is non-zero. In that case, the number 240 * of columns displayed in the layout is determined by the total 241 * number of components and the number of rows specified. 242 * @param cols the number of columns in this layout 243 * @exception IllegalArgumentException if the value of both 244 * <code>rows</code> and <code>cols</code> is set to zero 245 * @since JDK1.1 246 */ 247 public void setColumns(int cols) { 248 if ((cols == 0) && (this.rows == 0)) { 249 throw new IllegalArgumentException("rows and cols cannot both be zero"); 250 } 251 this.cols = cols; 252 } 253 254 /** 255 * Gets the horizontal gap between components. 256 * @return the horizontal gap between components 257 * @since JDK1.1 258 */ 259 public int getHgap() { 260 return hgap; 261 } 262 263 /** 264 * Sets the horizontal gap between components to the specified value. 265 * @param hgap the horizontal gap between components 266 * @since JDK1.1 267 */ 268 public void setHgap(int hgap) { 269 this.hgap = hgap; 270 } 271 272 /** 273 * Gets the vertical gap between components. 274 * @return the vertical gap between components 275 * @since JDK1.1 276 */ 277 public int getVgap() { 278 return vgap; 279 } 280 281 /** 282 * Sets the vertical gap between components to the specified value. 283 * @param vgap the vertical gap between components 284 * @since JDK1.1 285 */ 286 public void setVgap(int vgap) { 287 this.vgap = vgap; 288 } 289 290 /** 291 * Adds the specified component with the specified name to the layout. 292 * @param name the name of the component 293 * @param comp the component to be added 294 */ 295 public void addLayoutComponent(String name, Component comp) { 296 } 297 298 /** 299 * Removes the specified component from the layout. 300 * @param comp the component to be removed 301 */ 302 public void removeLayoutComponent(Component comp) { 303 } 304 305 /** 306 * Determines the preferred size of the container argument using 307 * this grid layout. 308 * <p> 309 * The preferred width of a grid layout is the largest preferred 310 * width of all of the components in the container times the number of 311 * columns, plus the horizontal padding times the number of columns 312 * minus one, plus the left and right insets of the target container. 313 * <p> 314 * The preferred height of a grid layout is the largest preferred 315 * height of all of the components in the container times the number of 316 * rows, plus the vertical padding times the number of rows minus one, 317 * plus the top and bottom insets of the target container. 318 * 319 * @param parent the container in which to do the layout 320 * @return the preferred dimensions to lay out the 321 * subcomponents of the specified container 322 * @see java.awt.GridLayout#minimumLayoutSize 323 * @see java.awt.Container#getPreferredSize() 324 */ 325 public Dimension preferredLayoutSize(Container parent) { 326 synchronized (parent.getTreeLock()) { 327 Insets insets = parent.getInsets(); 328 int ncomponents = parent.getComponentCount(); 329 int nrows = rows; 330 int ncols = cols; 331 332 if (nrows > 0) { 333 ncols = (ncomponents + nrows - 1) / nrows; 334 } else { 335 nrows = (ncomponents + ncols - 1) / ncols; 336 } 337 int w = 0; 338 int h = 0; 339 for (int i = 0 ; i < ncomponents ; i++) { 340 Component comp = parent.getComponent(i); 341 Dimension d = comp.getPreferredSize(); 342 if (w < d.width) { 343 w = d.width; 344 } 345 if (h < d.height) { 346 h = d.height; 347 } 348 } 349 return new Dimension(insets.left + insets.right + ncols*w + (ncols-1)*hgap, 350 insets.top + insets.bottom + nrows*h + (nrows-1)*vgap); 351 } 352 } 353 354 /** 355 * Determines the minimum size of the container argument using this 356 * grid layout. 357 * <p> 358 * The minimum width of a grid layout is the largest minimum width 359 * of all of the components in the container times the number of columns, 360 * plus the horizontal padding times the number of columns minus one, 361 * plus the left and right insets of the target container. 362 * <p> 363 * The minimum height of a grid layout is the largest minimum height 364 * of all of the components in the container times the number of rows, 365 * plus the vertical padding times the number of rows minus one, plus 366 * the top and bottom insets of the target container. 367 * 368 * @param parent the container in which to do the layout 369 * @return the minimum dimensions needed to lay out the 370 * subcomponents of the specified container 371 * @see java.awt.GridLayout#preferredLayoutSize 372 * @see java.awt.Container#doLayout 373 */ 374 public Dimension minimumLayoutSize(Container parent) { 375 synchronized (parent.getTreeLock()) { 376 Insets insets = parent.getInsets(); 377 int ncomponents = parent.getComponentCount(); 378 int nrows = rows; 379 int ncols = cols; 380 381 if (nrows > 0) { 382 ncols = (ncomponents + nrows - 1) / nrows; 383 } else { 384 nrows = (ncomponents + ncols - 1) / ncols; 385 } 386 int w = 0; 387 int h = 0; 388 for (int i = 0 ; i < ncomponents ; i++) { 389 Component comp = parent.getComponent(i); 390 Dimension d = comp.getMinimumSize(); 391 if (w < d.width) { 392 w = d.width; 393 } 394 if (h < d.height) { 395 h = d.height; 396 } 397 } 398 return new Dimension(insets.left + insets.right + ncols*w + (ncols-1)*hgap, 399 insets.top + insets.bottom + nrows*h + (nrows-1)*vgap); 400 } 401 } 402 403 /** 404 * Lays out the specified container using this layout. 405 * <p> 406 * This method reshapes the components in the specified target 407 * container in order to satisfy the constraints of the 408 * <code>GridLayout</code> object. 409 * <p> 410 * The grid layout manager determines the size of individual 411 * components by dividing the free space in the container into 412 * equal-sized portions according to the number of rows and columns 413 * in the layout. The container's free space equals the container's 414 * size minus any insets and any specified horizontal or vertical 415 * gap. All components in a grid layout are given the same size. 416 * 417 * @param parent the container in which to do the layout 418 * @see java.awt.Container 419 * @see java.awt.Container#doLayout 420 */ 421 public void layoutContainer(Container parent) { 422 synchronized (parent.getTreeLock()) { 423 Insets insets = parent.getInsets(); 424 int ncomponents = parent.getComponentCount(); 425 int nrows = rows; 426 int ncols = cols; 427 boolean ltr = parent.getComponentOrientation().isLeftToRight(); 428 429 if (ncomponents == 0) { 430 return; 431 } 432 if (nrows > 0) { 433 ncols = (ncomponents + nrows - 1) / nrows; 434 } else { 435 nrows = (ncomponents + ncols - 1) / ncols; 436 } 437 // 4370316. To position components in the center we should: 438 // 1. get an amount of extra space within Container 439 // 2. incorporate half of that value to the left/top position 440 // Note that we use trancating division for widthOnComponent 441 // The reminder goes to extraWidthAvailable 442 int totalGapsWidth = (ncols - 1) * hgap; 443 int widthWOInsets = parent.width - (insets.left + insets.right); 444 int widthOnComponent = (widthWOInsets - totalGapsWidth) / ncols; 445 int extraWidthAvailable = (widthWOInsets - (widthOnComponent * ncols + totalGapsWidth)) / 2; 446 447 int totalGapsHeight = (nrows - 1) * vgap; 448 int heightWOInsets = parent.height - (insets.top + insets.bottom); 449 int heightOnComponent = (heightWOInsets - totalGapsHeight) / nrows; 450 int extraHeightAvailable = (heightWOInsets - (heightOnComponent * nrows + totalGapsHeight)) / 2; 451 if (ltr) { 452 for (int c = 0, x = insets.left + extraWidthAvailable; c < ncols ; c++, x += widthOnComponent + hgap) { 453 for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows ; r++, y += heightOnComponent + vgap) { 454 int i = r * ncols + c; 455 if (i < ncomponents) { 456 parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent); 457 } 458 } 459 } 460 } else { 461 for (int c = 0, x = (parent.width - insets.right - widthOnComponent) - extraWidthAvailable; c < ncols ; c++, x -= widthOnComponent + hgap) { 462 for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows ; r++, y += heightOnComponent + vgap) { 463 int i = r * ncols + c; 464 if (i < ncomponents) { 465 parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent); 466 } 467 } 468 } 469 } 470 } 471 } 472 473 /** 474 * Returns the string representation of this grid layout's values. 475 * @return a string representation of this grid layout 476 */ 477 public String toString() { 478 return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + 479 ",rows=" + rows + ",cols=" + cols + "]"; 480 } 481 }