HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

As Java matures, new sets of behavior added to its API allow developers and programmers to write more sophisticated programs with less difficulty. This article focuses on collections API, a new abstract data structure that will be a part of the core Java Development Kit (JDK) 1.2 API. (The collection classes are also available as an add-on package for the JDK 1.1 class libraries.)

Overview
An object-oriented application often consists of classes that need to refer to a collection of values of a given type. JavaSoft supports this capability by means of its rich set of collection classes - abstract data types for modeling "collections" of objects. Collections are a recent addition to the JDK. A collections API is a unified framework for representing and manipulating collections, allowing them to be manipulated independently of the details of their representation. Some examples of collections include:

  • Set: a mathematical set of elements with no duplication
  • List: an ordered sequence of elements
  • Map: an array of key-value pairs
  • Vector: an array of elements that can grow or shrink dynamically
Collections can be used to represent relationships among objects in a data model. These relationships may be one to one, one to many or many to many, depending on the model. While a simple array can be used to represent a one-to-one relationship, collections of objects are more appropriate for representing one-to-many and many-to-many relationships. Since the JDK 1.2 is still in beta, this article refers to the collection package released for JDK 1.1 unless explicitly stated otherwise.

Collections Framework
The collections framework in Java is used to separate the abstract notion of a collection of data from its data structure via the use of interfaces. For example, consider a List interface versus a linked-list implementation. A linked list can implement a List interface that may be used by other classes independently of how it is implemented by the class that uses it. The advantage of specifying interfaces in this fashion is that you can manipulate the collections without having to know the details of how a specific collection is implemented. The primary advantages of collections framework in Java can be summarized as follows:

  1. Interoperability between unrelated APIs: Two different applications with an underlying data structure implemented separately can exchange data using the collection interface API since they both conform to the standard collections API.
  2. Less effort in learning new APIs: If two applications exchange a list of objects, the lists can manipulate each other even if they are populated with their application-specific data objects since they both conform to the same API for manipulating lists.
  3. Easier design and implementation of APIs: Application designers using the generic API that relies on collections won't have to start the design of their applications from scratch every time.
  4. Software reuse: Programmers can implement generic, reusable data objects that conform to the standard collection interfaces. These objects can also implement algorithms that operate on collection objects independent of the details of their representation. These data objects and algorithms can be reused in different applications.
Java Collections vs JGL and ODMG Collections
The Java collection framework is not the first abstract data class library for Java. Java Generic Library (JGL) and Object Database Management Group (ODMG) collections offer similar functionality. As we focus on the advantages of the JDK collections, it might be worthwhile to compare them with the proprietary but powerful and widely used JGL and ODMG's collection interfaces. The main design goal of JGL, an already existing collection package from ObjectSpace, was consistency with the C++ Standard Template Library (STL). It has approximately 130 classes and interfaces.

The JDK collections framework, on the other hand, is meant to be simple and lightweight. The whole collections package contains about 25 classes and interfaces. So, for developers who are used to the sophisticated JGL library, switching over to JDK collections might not be very attractive. However, as the Java libraries mature, the JDK collections library is also expected to grow. In addition, the collection classes are a part of the JDK and hence do not have to be installed separately.

The JDK collection interfaces are similar to the ODMG's specifications (spec. 2.0) of Java interfaces released in May '97. The JavaSoft collection interfaces serve as the root of an interface inheritance hierarchy and the ODMG interfaces are derived from them. Again, the significant advantage of using the JDK collections is portability, as the applications using the JDK collections won't have to use any other classes or libraries outside the core JDK classes.

Collection Interfaces and Classes
The JDK Collections API consists of four core collection interfaces that represent different types of collections (such as sets, lists and maps):

  1. Core interfaces
  2. Concrete implementations (implementations for the core collection interfaces)
  3. Abstract implementations (partial implementations of core collection interfaces to facilitate custom implementations)
  4. Some basic algorithms such as sorting arrays, lists, searching arrays
Core Collection Interfaces
There are four core interfaces in the Java collections hierarchy. The collection interface is the root in the collection hierarchy. Two of the interfaces (Set and List) are children of the collection interface and add more methods to it; the last interface, Map, represents a mapping of keys to values. Each interface is described in detail below.

Figure 1
Figure 1:  New JDK collection interface hierarchy

Collection
The collection interface represents a group of objects that may or may not be ordered. The base collection is duplicate-free and mutable. This class provides the base interface that most of the interfaces in the java.util.collections package extend.

Figure 2
Figure 2:  jav.util.collections.Collection class

Set
A set is a collection in which no duplicate elements are permitted. Ordering (if any) is generally established at Set creation time.

Figure 3
Figure 3:  jav.util.collections.Set class

List
If you want to use a collection that can hold duplicate objects and have specific ordering, you need to use this interface (also known as a Sequence). With it, the caller generally has precise control over the position of each element in the list.

Figure 4
Figure 4:  jav.util.collections.List class

Map
This interface represents a mapping from keys to values. Each key can map to, at most, one value. This interface doesn't extend the collection interface.

Figure 5
Figure 5:  jav.util.collections.Map class

Concrete Implementations
Classes that provide concrete implementations for the collection interfaces can be used either directly or subclassed to add additional behavior to the collection interfaces. The important classes in this category are:

  1. HashSet: A set of classes backed by a hash table, this serves as a good, general-purpose Set implementation.
  2. TreeSet: A balanced binary tree implementation of the SortedSet interface; unlike HashSet, a TreeSet imposes ordering on its elements.
  3. ArrayList: A resizable-array implementation of the List interface (essentially an unsynchronized Vector), this class was provided in addition to Vector for consistency in naming and behavior.
  4. LinkedList: A doubly linked List; this class may provide better performance than ArrayList if elements are frequently inserted or deleted within the List. It's useful for queues and double-ended queues (deques).
  5. Vector: The new Vector class is a synchronized, resizable-array implementation of a List with additional "legacy methods" from the existing JDK1.1's java.util.Vector class. Changed from the legacy Vector class in JDK, the java.util.Vector class in JDK1.1 currently extends java.lang.Object class. The new collections-based Vector class extends java.util.collections.AbstractList class (which in turn extends from java.util.collections.AbstractCollections class) and implements java.util.collections.List interface.
  6. HashMap: A hash table implementation of the Map interface (essentially an unsynchronized Hashtable), the class is provided in addition to the Hashtable, for consistency in naming and behavior.
  7. TreeMap: A balanced binary tree implementation of the SortedMap interface; unlike HashMap, it imposes ordering on its elements.
  8. Hashtable: A synchronized hash table implementation of the Map interface with additional "legacy" methods from the existing JDK1.1 java.util.Hashtable class. Changed from the existing Hashtable class in JDK, the Hashtable class currently extends java.util.Dictionary class. The new Hashtable class implements Map interface in addition to extending the Dictionary class. Also, in the new Hashtable implementation any non-null object can be used as a key or as a value, unlike the previous implementation of Hashtable.

Anonymous Implementations
The new collections framework provides java.util.collections.Collections class, which has implementation methods accessed solely through public static factory methods. This allows any arbitrary algorithmic operations on collections.

Views
The collections framework provides users with the flexibility to work with either the actual collections (where they can perform read-write operations) or just a view of the collection (where they can perform only read operations), depending on the application needs. For example, the java.util.collections.Collections has methods like unmodifiableCollection (Collection c), which returns a view of the collection c backed by the original collection that was passed in. Other similar methods are unmodifiableCollection, unmodifiableSet, unmodifiableList, unmodifiableMap and unmodifiableSortedSet. All these methods return an unmodifiable view of a specified collection that throws an UnsupportedOperationException if the user attempts to modify.

Abstract Implementations
The classes in this category provide a skeletal implementation for the core collection interfaces to minimize the effort required to implement them. The JavaDocs API documentation for these classes describes precisely how each method is implemented so the implementers will know which methods should be overridden, given the performance of the "basic operations" of a specific implementation. Following are some of the key abstract collection classes:

  1. AbstractCollection: This class provides a skeletal implementation of the collection interface. The implementation of this class is neither a Set nor a List, but a general-purpose collection.
  2. AbstractSet and AbstractMap: This class provides a skeletal implementation of Set and Map interfaces.
  3. AbstractList: This class provides a partial implementation of a List backed by a random-access Data- Store (such as an array).
    Figure 6
    Figure 6:  AbstractList extends AbstractCollections and implements

  4. Comparator: This class represents an order relation that may be used to order a collection or sort an array. Comparator may be used instead of a Comparable type's natural ordering or to order elements of a type that does not implement a Comparable interface.
  5. SortedSet: This class represents a Set whose elements are automatically sorted, either in their natural ordering or by a Comparator provided at SortedSet creation time.
  6. SortedMap: This class represents a Map whose mappings are automatically sorted by key, either in the key's natural ordering or by a Comparator provided at SortedMap creation time.

Figure 7
Figure 7:  new Hashtable hierarchy

Algorithms
The new JDK collections package provides algorithms that operate on collections, their views and wrappers. The algorithms are provided in the java.util.collections.Collections class, which has several public static methods that operate on collections or return collections. Some of the important algorithms are described below:

  1. Collections.sort(List): Sorts a List using a merge sort algorithm that provides average-case performance comparable to a high-quality quicksort, guaranteed O(n*log n) performance (unlike quicksort) and stability (unlike quicksort). (A stable sort is one that does not reorder equal elements.)
  2. Collections.binarySearch(List): Searches for an element in an ordered List using the binary search algorithm.
  3. Collections.min(Collection)/Collections.max(Collection): Returns the minimum/maximum element in a Collection.
  4. Iterators: In addition to the Vector and Hashtable changes, one of the main changes in the JDK data structures is the collection framework's new Iterator interface, which is useful for iterating over the Collection objects. The Iterator differs from the existing Enumeration class in JDK with respect to its additional power to modify the collection while iterating over it. For example, you can remove elements from the backed collection while iterating over it. In addition, Iteration is extended to provide ListIterator interface that provides easier bidirectional iteration over lists. Enumeration will remain a part of the java.util package, mainly for the backward compatibility with the legacy JDK API.

Figure 8
Figure 8:  jav.util.collections.Collections class

The following code snippet demonstrates the use of Iterators. Vector v has already been created and populated with data objects:

Iterator i = v.iterator();
while (i.hasNext())
{
Integer intObj = (Integer)i.next();
System.out.println("Integer value: " + intObj.intValue());
// remove this element from the collection using Iterator
i.remove();
}

Another main feature of the collection framework is the synchronized collection wrappers: java.util.collections.Collections class provides methods to obtain synchronized wrappers backed by standard (typically unsynchronized) collection. This allows programs to carry out thread-safe (synchronized) operations on the collection objects.

The new JDK collection implementations are unsynchronized (with the exceptions of the Hashtable and Vector classes), but may be synchronized externally with synchronizing wrappers. All have fail-fast iterators that throw a runtime exception in response to concurrent modification of the backing collection rather than behave nondeterministically.

Sample Example Using Collections API
Listing 1 indicates how collection classes can be used to represent and manipulate data in a simple but efficient manner. This example demonstrates some of the features of the new collection-based Vector class and Comparator interface. The example creates a Vector and fills it up with integers. It then obtains an array representation of these elements by calling toArray() method, performs a sorting operation using the Comparator interface and, at the end, demonstrates how to use the Iterator to retrieve each element of the vector and how to remove elements from the collection using the Iterator.

Figure 9
Figure 9:  java.util.collections.AbstractCollections class

Here is the output obtained by running the example code in Listing 1:

$ java Demo

Given Vector before sorting:
20, 500, 400, 100, 300,

Sorted vector after modifying the array:
20, 100, 300, 400, 500,

Vector using Iterator:
20, this element has been removed from the vector
100, this element has been removed from the vector
300, 400, 500,
$

Using Collections with JDK 1.1.x and 1.2 With JDK 1.1.x
The collections framework API has been released as an add-on for the preexisting JDK 1.1 API. The collection classes in the add-on package are direct copies of JDK 1.2 counterparts and differ only in their package names. The APIs are identical with one significant exception: as they are in different packages, they are distinct Java types and cannot be cast/assigned between each other.

If required, however, source code using the 1.1 APIs can be easily (mechanically) ported to use the JDK 1.2 counterparts. The 1.1 collection classes packaged under com.sun.java.util.collections are currently available as a separate download from the core JDK 1.1 API at JavaSoft's Web site.

Figure 10
Figure 10:  java.uti.collections.Iterator class

With JDK 1.2
In JDK 1.2 the collections API framework will be part of the core Java API and packaged under java.util package. This package is available today with beta releases of JDK 1.2. This means that if you use the collection package with JDK 1.1.x, you'll be importing collection classes using import statements similar to the one used in Listing 1. When you move your application to JDK 1.2 later on, all you do is change these import statements to import java.util classes.

Providing Implementation for Collection Interfaces
If you're implementing any of the collection interfaces, keep in mind that all general-purpose collection implementation classes should provide two "standard" constructors:

  • A void (no arguments) constructor, which will create an empty collection
  • A constructor with a single argument of type Collection, which will create a new collection with the same elements as its argument
The latter constructor allows users to copy any collection, producing an equivalent collection of the desired implementation type. For example, all general-purpose Map implementations should provide a void (no arguments) constructor and a constructor that takes a single argument of type Map.

Migrating to the New Collections API Using JDK 1.1
What's the impact of changing your existing Java data structures to the new collection-based data structures? Let's see what's required to migrate your application so as to use the new collection interfaces and classes for JDK 1.1. The steps are given below:

  1. Download the new Collections.zip for the JDK 1.1.x.
  2. Add the collections.zip archive to your CLASSPATH.
  3. Replace java.util.Enumeration with com.sun.java.util.collections.Iterator.
  4. Change package names of the classes you wish to change to the new collection- based classes (e.g., replace java.util.Vector with the new com.sun.java.util.collections.Vector) and change the corresponding method calls in these classes.
  5. Applets or applications packaged as JAR files to be used in Web pages should reference or include the collections.zip archive in their packaging or CODEBASE. This will ensure that the implementation is available upon download to the browser environment.
Conclusion
Java's collections framework provides easier and more powerful use of its data structures than ever before. It greatly facilitates writing programs involving numerical calculations and algebraic operations, and as the framework matures we can expect solutions for more complex mathematical problems. Whether JavaSoft will provide any mechanism for efficiently passing collection objects using RMI in a distributed environment remains to be seen, but you can always count on JavaSoft!

Resources - URLs

  1. JavaSoft: www.javasoft.com
  2. JDK 1.1 download: Java.sun.com/products/jdk/1.1
  3. Collections API download for JDK 1.1:
    java.sun.com/beans/infobus/index.html#COLLECTIONS
  4. JDK 1.2 download: www.javasoft.com/products/jdk/1.2/index.html
  5. ODMG: www.odmg.org
  6. JGL: www.objectspace.com
About the Author
Bhaven Shah, a member of the technical staff at i2 Technologies in Dallas, Texas, has a BS and an MS in computer science. His four years of programming experience include two years of Java and CORBA development. His focus is on GUI, client/server and distributed software development. Bhaven can be reached at [email protected]

	

Listing 1.
 
public static final String EAST = "East"; 
public static final String WEST = "West"; 
public static final String NORTH = "North"; 
public static final String SOUTH = "South"; 
public static final String CENTER = "Center"; 
public static final String NORTHEAST = "NorthEast"; 
public static final String NORTHWEST = "NorthWest"; 
public static final String SOUTHEAST = "SouthEast"; 
public static final String SOUTHWEST = "SouthWest"; 

protected Hashtable table = new Hashtable(); 

private static final int PREFERRED = 1; 
private static final int MINIMUM = 0; 

private Component getComponent(String name) 
{ 
if (!table.containsKey(name)) name = CENTER; 
return (Component)table.get(name); 
} 

private boolean isVisible(String name) 
{ 
if (!table.containsKey(name)) return false; 
return getComponent(name).isVisible(); 
} 

private void setBounds(String name, 
int x, int y, int w, int h) 
{ 
if (!isVisible(name)) return; 
getComponent(name).setBounds(x, y, w, h); 
} 

private Dimension getSize(int type, String name) 
{ 
if (!isVisible(name)) return new Dimension(0, 0); 
if (type == PREFERRED) 
return getComponent(name).getPreferredSize(); 
if (type == MINIMUM) 
return getComponent(name).getMinimumSize(); 
return new Dimension(0, 0); 
} 

Listing 2
 
private Insets calculateLayoutSize(int type) 
{ 
Dimension size = new Dimension(0, 0); 

int northHeight = 0; 
int southHeight = 0; 
int eastWidth = 0; 
int westWidth = 0; 

size = getSize(type, NORTH); 
northHeight = Math.max(northHeight, size.height); 

size = getSize(type, SOUTH); 
southHeight = Math.max(southHeight, size.height); 

size = getSize(type, EAST); 
eastWidth = Math.max(eastWidth, size.width); 

size = getSize(type, WEST); 
westWidth = Math.max(westWidth, size.width); 

size = getSize(type, NORTHWEST); 
northHeight = Math.max(northHeight, size.height); 
westWidth = Math.max(westWidth, size.width); 

size = getSize(type, SOUTHWEST); 
southHeight = Math.max(southHeight, size.height); 
westWidth = Math.max(westWidth,size.width); 

size = getSize(type, NORTHEAST); 
northHeight = Math.max(northHeight, size.height); 
eastWidth = Math.max(eastWidth, size.width); 

size = getSize(type, SOUTHEAST); 
southHeight = Math.max(southHeight, size.height); 
eastWidth = Math.max(eastWidth, size.width); 

return new Insets(northHeight, 
westWidth, southHeight, eastWidth); 
} 

public Dimension preferredLayoutSize(Container target) 
{ 
Dimension size, dim = new Dimension(0, 0); 
size = getSize(PREFERRED, CENTER); 
dim.width += size.width; 
dim.height += size.height; 

Insets edge = calculateLayoutSize(PREFERRED); 
dim.width += edge.right + hgap; 
dim.width += edge.left + hgap; 
dim.height += edge.top + hgap; 
dim.height += edge.bottom + hgap; 

Insets insets = target.getInsets(); 
dim.width += insets.left + insets.right; 
dim.height += insets.top + insets.bottom; 
return dim; 
} 

Listing 3.
 
public void layoutContainer(Container target) 
{ 
Insets insets = target.getInsets(); 
Insets edge = calculateLayoutSize(PREFERRED); 

int top = insets.top; 
int bottom = target.getSize().height - insets.bottom; 
int left = insets.left; 
int right = target.getSize().width - insets.right; 

setBounds(NORTH, 
left + edge.left + hgap, top, 
right - edge.left - hgap - edge.right - hgap, 
edge.top); 
setBounds(SOUTH, 
left + edge.left + hgap, bottom - edge.bottom, 
right - edge.left - hgap - edge.right - hgap, 
edge.bottom); 
setBounds(EAST, 
right - edge.right, top + edge.top + vgap, edge.right, 
bottom - edge.top - vgap - edge.bottom - vgap); 
setBounds(WEST, 
left, top + edge.top + vgap, edge.left, 
bottom - edge.top - vgap - edge.bottom - vgap); 
setBounds(NORTHWEST, 
left, top, edge.left, edge.top); 
setBounds(SOUTHWEST, 
left, bottom - edge.bottom, 
edge.left, edge.bottom); 
setBounds(NORTHEAST, 
right - edge.right, top, 
edge.right, edge.top); 
setBounds(SOUTHEAST, 
right - edge.right, bottom - edge.bottom, 
edge.right, edge.bottom); 

top += edge.top + vgap; 
bottom -= edge.bottom + vgap; 
left += edge.left + hgap; 
right -= edge.right + hgap; 
setBounds(CENTER, 
left, top, right - left, bottom - top); 
} 

Listing 4.
 
public void setRows(int rows) 
{ 
if (rows == 0) 
{ 
throw new IllegalArgumentException( 
"rows cannot set to zero"); 
} 
iRows = new int[rows]; 
for (int i = 0; i < rows; i++) 
{ 
iRows[i] = 1; 
} 
setRows(iRows); 
} 

public void setRows(int[] rows) 
{ 
if ((rows == null) || (rows.length == 0)) 
{ 
throw new IllegalArgumentException( 
"rows cannot be null or zero length"); 
} 
float total = 0; 
for (int i = 0; i < rows.length; i++) 
{ 
total += rows[i]; 
} 
iRows = rows; 
fRows = new float[rows.length]; 
for (int i = 0; i < rows.length; i++) 
{ 
fRows[i] = (float)iRows[i] / total; 
} 
} 

Listing 5.
 
public Dimension preferredLayoutSize(Container parent) 
{ 
Insets insets = parent.getInsets(); 
int ncomponents = parent.getComponentCount(); 
int nrows = iRows.length; 
int ncols = iCols.length; 

Dimension dim; 
Component comp; 
int count = 0; 
float xUnit = 0; 
float yUnit = 0; 
float unit; 

for (int row = 0; row < nrows; row++) 
{ 
for (int col = 0; col < ncols; col++) 
{ 
if (count > ncomponents) break; 
else 
{ 
comp = parent.getComponent(count); 
dim = comp.getPreferredSize(); 
unit = (float)dim.width / (float)iCols[col]; 
if (unit > xUnit) xUnit = unit; 
unit = (float)dim.height / (float)iRows[row]; 
if (unit > yUnit) yUnit = unit; 
count++; 
} 
} 
} 
int height = 0; 
for (int row = 0; row < nrows; row++) 
{ 
height += yUnit * iRows[row]; 
} 
int width = 0; 
for (int col = 0; col < ncols; col++) 
{ 
width += xUnit * iCols[col]; 
} 

return new Dimension( 
insets.left + insets.right + width, 
insets.top + insets.bottom + height); 
} 

Listing 6.
 
public void layoutContainer(Container parent) 
{ 
int ncomponents = parent.getComponentCount(); 
if (ncomponents == 0) return; 

Insets insets = parent.getInsets(); 
int nrows = iRows.length; 
int ncols = iCols.length; 
int w = parent.getSize().width - 
(insets.left + insets.right); 
int h = parent.getSize().height - 
(insets.top + insets.bottom); 

int x = insets.left; 
for (int c = 0; c < ncols; c++) 
{ 
int ww = (int)((float)w * fCols[c]) - hgap; 
int y = insets.top; 
for (int r = 0; r < nrows; r++) 
{ 
int i = r * ncols + c; 
int hh = (int)((float)h * fRows[r]) - vgap; 
if (i < ncomponents) 
{ 
parent.getComponent(i).setBounds(x, y, ww, hh); 
} 
y += hh + vgap; 
} 
x += ww + hgap; 
} 
} 

Listing 7.
 
public void addLayoutComponent(Component comp, Object rect) 
{ 
if (!(rect instanceof Rectangle)) 
{ 
throw new IllegalArgumentException( 
"constraint object must be a Rectangle"); 
} 
table.put(comp, rect); 
} 

public void removeLayoutComponent(Component comp) 
{ 
table.remove(comp); 
} 

Listing 8.
 
public Dimension preferredLayoutSize(Container parent) 
{ 
Insets insets = parent.getInsets(); 
int ncomponents = parent.getComponentCount(); 
int nrows = rows; 
int ncols = cols; 

Dimension dim; 
Component comp; 
int count = 0; 
float xUnit = 0; 
float yUnit = 0; 
float unit; 

int w = 0; 
int h = 0; 
for (int i = 0; i < ncomponents; i++) 
{ 
comp = parent.getComponent(count); 
dim = comp.getPreferredSize(); 
Rectangle rect = (Rectangle)table.get(comp); 
unit = (float)dim.width / (float)rect.width; 
if (unit > xUnit) xUnit = unit; 
unit = (float)dim.height / (float)rect.height; 
if (unit > yUnit) yUnit = unit; 
count++; 
} 

int height = (int)(yUnit * nrows); 
int width = (int)(xUnit * ncols); 

return new Dimension( 
insets.left + insets.right + width, 
insets.top + insets.bottom + height); 
} 

Listing 9.
 
public void layoutContainer(Container parent) 
{ 
Insets insets = parent.getInsets(); 
int ncomponents = parent.getComponentCount(); 
int nrows = rows; 
int ncols = cols; 

if (ncomponents == 0) return; 

int w = parent.getSize().width - 
(insets.left + insets.right); 
int h = parent.getSize().height - 
(insets.top + insets.bottom); 
float ww = (float)(w - (ncols - 1) * hgap) / (float)ncols; 
float hh = (float)(h - (nrows - 1) * vgap) / (float)nrows; 

int left = insets.left; 
int top = insets.top; 
Component comp; 
Rectangle rect; 
int x, y, width, height; 

for (int i = 0; i < ncomponents; i++) 
{ 
comp = parent.getComponent(i); 
rect = (Rectangle)table.get(comp); 
x = (int)(ww * (float)rect.x) + left; 
y = (int)(hh * (float)rect.y) + top; 
// Calculate by substraction to a void rounding errors 
width = (int)(ww * (float)(rect.x + rect.width)) - x; 
height = (int)(hh * (float)(rect.y + rect.height)) - y; 
comp.setBounds(new Rectangle(x, y, width, height)); 
} 
} 
  
      
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.