Please support my sponors and make this site possible!!!
Please support our sponsors!

 

Home > Core Java FAQ > Abstract Window Toolkit FAQ
Abstract Window Toolkit
Components, Containers, and Peers(20)   *  Windows, Frames, and Dialogs (19)  *  Miscellaneous (31)
 
Q . What are the Component and Container classes?

Ans : 

Component and Container are the two fundamental classes in the Abstract Window Toolkit (AWT); Component instances (components) represent individual user-interface elements, and Container instances (containers) represent groups of components.

     Component is the abstract base class for all AWT user-interface elements except menu components. A component can be presented on screen, relocated, resized, or hidden; it can be drawn or printed; and it can receive, handle, and deliver events. Components can also be grouped and formatted in containers.
     Container is an abstract subclass of Component with the added property of containing a group of components. Containers can also contain other containers, which can contain other containers, and so on to arbitrary depth. The term containment hierarchy refers to this nested arrangement of containers and components (sometimes also called a window hierarchy). Another useful bit of terminology is to refer to a container as the parent of each component that it contains.
     It is important when learning to use components and containers not to confuse the containment hierarchy with the inheritance hierarchy.

Besides handling the normal component tasks, a container also manages the components it contains. A container can add components, remove components, and (with the help of a layout manager) control the layout of its components.
     The Component and Container classes constitute the backbone of the Java™ Abstract Window Toolkit—you'll want to get to know these classes and their methods well.

Q . How do I control the positioning of my interface components?

Ans : 

Assign an appropriate layout manager to each container in your interface, or let the AWT assign default layout managers for you; the layout manager automatically calculates layout positions for the container's components.

     In the AWT, a container tracks the components  that belong to it, but calls on a LayoutManager object to control their layout. LayoutManager is an interface. The objects serving as layout managers come from classes that implement the LayoutManager interface. (Starting with the JDK 1.1, the LayoutManager2 interface extends LayoutManager to provide better support for constraint-based layout managers.) By setting the layout manager for a container, you are telling the container what strategy to use when laying out its components.
     A layout manager is responsible for calculating the sizes and locations of the components in a container. Different layout managers use different strategies for this. A BorderLayout, for example, allocates five distinct regions ("North", "South", "West", "East", and "Center") within a rectangle and allows one component in each region. A GridLayout handles any number of components by arranging them as a grid of equal-sized cells. The number of rows and columns in the grid can be set when the GridLayout instance is created. A FlowLayout arranges its components much like the flow of words in a paragraph: all in a single row if space permits, otherwise wrapped around to one or more additional rows.
     You can choose a layout manager for each container. If you don't, the AWT assigns a default layout manager depending on the class of your container. Window and Window subclasses (such as Frame and Dialog) use a BorderLayout by default; Panel and Panel subclasses (including Applet) use a FlowLayout by default. Typical steps for laying out components are:

  • creating your components and containers
  • setting the layout manager for each container (or use the default)
  • adding components to the appropriate containers
     You can also define your own layout manager by implementing the LayoutManager or LayoutManager2 interface. This is a nontrivial undertaking, though, and requires a strong, detailed understanding of existing layout managers. A rule of thumb is that you should feel you understand 98 percent of the code in the existing JDK 1.1 layout managers (excluding, perhaps, GridBagLayout) before writing your own.
Q . What are inset values, and how do I set them?

Ans :  

Inset values specify how much of a container's space is reserved for a border, inside of which the container's components are arranged; you set these values by overriding getInsets (or insets in JDK 1.0.2) in your own Container subclasses.

     Each container, for example a Frame instance, Panel instance, or Applet instance, provides a rectangular space in which to position the container's components. In the default case, the components in a container can occupy the full space of the container. Inset values, represented as an instance of the Insets class, allow you to specify an amount of space at one or more margins—a boundary inside which all components must be placed. For example, a top inset of 10 means that a component's top edge can be placed no higher than 10 units (the space covered by 10 pixels) from the top of the container.
     Inset values are useful for containers that have border material surrounding their content area. The Frame class, for instance, provides top-level windows that have a title bar. The space for the title bar is figured into the Insets instance, so that any components placed in the Frame instance will neither overlap nor lie underneath the title bar. Layout managers in general take into account a container's inset values when calculating where to place components.
     You can specify inset values only for a Container subclass that you define. This is because containers have no setInsets method; instead, your subclass must override the getInsets method (or insets in JDK 1.0.2) to return the inset values you desire. For example:

     /* using JDK 1.1: */
     public class myApplet extends java.applet.Applet {
           // ...
           public Insets getInsets() {
               return new Insets(10, 6, 15, 3);
           }
     }

This code defines an Applet subclass with the following inset values: top 10, left 6, bottom 15, and right 3.
     Note: You shouldn't override the inset values for Frame and Dialog objects. These values are set by the native toolkit to ensure that native border material, such as the title bar, does not cover any content you place in the frame or dialog.

Q . How do I change the thickness of the line?

Ans : Java 1.1 and earlier only support 1 pixel wide lines. There's no easy way around this. You can, however, draw multiple, parallel lines offset from each other by one pixel:

public void paint(Graphics g) {
  int x1=5;
  int x2=278;
  int y1=8;
  int y2=93;
   // Draw a ten pixel thick line
   for (int i = -5; i < 5; i++) {
       g.drawLine(x1+i,y1+i,x2+i,y2+i);
   }
}

This isn't perfect. The ends of the line are excessively tapered. You really need to take the slope of the line into account when incrementing x and y, but this should give you the idea. If you're doing a lot of this, you can write a class or method to do it for you. 
There are other hacks you can use. For example, a thick line is essentially a filled rectangle. Therefore you can calculate the endpoints of the rectangle and use fillPolygon() to draw it.

The real solution is going to have to wait for a more complete graphics API for Java, possibly in Java 1.2.

Q . Can I exert complete control over the size and placement of components in my interface?

Ans :  

Yes, you can—but please don't.

     The AWT is designed to let layout managers handle layout details so that resizing is handled automatically, and layouts behave consistently across platforms. This is a central objective of Java technology: writing applications once and running them anywhere.
     You can, however, handle all your layout work manually by not using any layout manager for your container. To do so, set the container's layout manager to null. For example:

     myPanel.setLayout(null);

     It is then up to you to choose sizes and locations for all the components, right down to the last pixel in your container.
     Note: hand-done layouts are strongly discouraged. What works on one specific hardware-software platform can fail gracelessly on another. Differences in native toolkits, font dimensions, and local language preference can change a finely hand-tuned layout on one platform into a mishmash of misalignments and overlaps on another.

Q . What do the invalidate and validate methods do?


Ans :

The invalidate and validate methods control when a container lays out its components.

     Component layouts in the AWT are dynamic. A change in one container, such as resizing a text field or adding a button, can spread up the containment hierarchy and trigger layout adjustments in many other containers. For efficiency, the AWT splits the process into two independently controllable parts:

  1. marking the containers whose layouts are no longer valid
  2. redoing the layout of containers marked as invalid
     The invalidate method handles the first step. It marks containers as needing a new layout but doesn't perform that layout itself. If a text field is resized, for instance, the AWT will invoke invalidate on the text field and on the text field's parent. When needed, the AWT propagates invalidate calls up through the containment hierarchy.
     All the real action happens in validate. Invoking validate on a container checks whether that container is marked as invalid, that is, in need of a new layout. If the container is invalid, validate invokes the dolayout method on it (or Layout in the JDK 1.0.2), and then repeats this process on any components in the container. The relayout process triggered by validate is thus recursive, and can descend arbitrarily far down a containment hierarchy.
     If you plan to override validate or layout in your own Container subclasses, be careful of the following two implementation details. First, although the effects of validate descend the containment hierarchy, you cannot count on the validate method itself being invoked on every container along the way. Second, validate code, including calls to dolayout (or layout in the JDK 1.0.2), executes within an AWT synchronization lock. To avoid the risk of deadlock, you should not acquire any further synchronization locks in your validate or layout code (which, admittedly, is not always easy to ensure).
     For reference, Table 5.1 lists the most common cases in which the AWT invokes invalidate or validate on your behalf. Note that this table presents implementation details of the JDK (1.0.2 and 1.1) that may change in future releases, but these are useful to know nevertheless.

 

Table 5.1: AWT Invocations of invalidate and validate
Class Method Invokes
Container add invalidate
Container remove invalidate
Window pack validate
Window show validate
Q . Can I add new AWT components to objects already visible on the screen?

Ans :  

Yes, you can change your program's interface as the program is running.

     Like other Java objects, AWT components can be created on the fly and connected to existing objects. To appear on screen, the component must be added to a container that is already on screen. You also need to invoke validate on the container so that it activates its layout manager to take the new component into account. The validate method lets you control when layouts are recalculated .
    

Following is a code fragment that adds or removes a button from a panel named centerPanel:

    int buttonCount = 0;
     Panel centerPanel = new Panel();
     void addButton() {
           ++buttonCount;
           centerPanel.add(new Button("button " + buttonCount));
           centerPanel.validate();
     }
Q . How can I tab between components?

Ans :  In JDK 1.0, you have to read the key press, and program it explicitly. JDK 1.1 supports tab and shift-tab (previous field) automatically. The tab order is the order that the components were added to the container.

Q . Can I add the same component to more than one container?

Ans : 

No; adding a component to a container automatically removes it from any previous parent (container).

     The AWT automatically maintains the strict rule that a component can have only one parent. (This ensures that containment structures are always trees, in graph theory terms. Trees are easier to understand and easier to compute with than less-constrained graphs.) The JDK (1.0.2 and 1.1) source code for adding a component to a container includes the following lines:

     /* in Container.java (JDK 1.0.2 and 1.1): */
     // ... comp refers to the component being added
     if (comp.parent != null) {
         comp.parent.remove(comp);
     }

It is an easy mistake to add a component to more than one container, and then be left wondering why the original container is behaving strangely.

Q . When I start a mouse drag inside a Component, and go outside the Component, still dragging, the mouse events still get sent to the Component, even though I am outside it. Is this a bug?

Ans : No, it is the specified behavior. The Java API documentation says: "... Mouse drag events continue to get sent to this component even when the mouse has left the bounds of the component. The drag events continue until a mouse up event occurs...." It is done for the convenience and ease of the application programmer. It allows you to handle all drags from the place of origin. If you don't want this, simply look at the coordinates of the mouseDrag Event, and if they are outside the Component, ignore them.

Q . I use add(Component) to add Components to the Container. Is there any way to explicitly set the z-order of these Components?

Ans : JDK 1.0 has no way to explicitly set the z-order of components. You can try it heuristically, based on the browser you're using, or you can use CardLayoutManager to ensure the panel you want is at the front.

In JDK 1.1, the z-order of components ("z-order" means "front-to-back" order, i.e. which window is in front of which) can be controlled by using the the method add(Component comp, int index). By default,
components are added 0 to N. The method paint of class Container paints its visible components from N to 0.

Q . How can I get the dimensions and resolution of the screen?

Ans : 
In contrast, if you want to keep a counter variable that you increment repeatedly, by all means use an int: 
int count;
// ...
++count;

Finally, the Integer class lets you translate back and forth between Integer and int representations of the same value: 

int i = 5;
Integer myInteger = new Integer(i);
int j = myInteger.intValue();

Note: The extra effort required to convert between int and Integer can be a nuisance, but is consistent with Java's emphasis on type safety.

Q . How can I place an outline around a group of components to show explicitly how the components are grouped?

Ans : 

You can write your own Panel subclass that draws an outline and specifies appropriate inset values to ensure that the panel's components stay inside the outline.

     Panel, as a subclass of Component, includes a paint method that draws the panel on the screen. Panels typically just draw a background color on which their components are placed, but you can define your own paint method to draw whatever you like in the panel. The drawRect method in the Graphics class provides a very simple means to draw an outline. The following paint method, for example, uses drawRect to provide a blue outline:

     /* using JDK 1.1: */
     public void paint(Graphics g) {
    	Dimension size = getSize();
    	g.setColor(Color.blue);
    	g.drawRect(2, 2,
            	      size.width - 5, size.height - 5);
     }

     Anything you draw on a panel using paint, however, can be covered by components contained in the panel. Therefore, you need to inform the panel's layout manager that space at the margins should be left free for the outline. To do this, override the getInsets method to provide the necessary space, such as:

     /* using JDK 1.1: */
     public Insets getInsets() {
           return new Insets(5, 5, 5, 5);
     }

To run in the JDK 1.0.2, these code samples would use the method names size and insets in place of getSize and getInsets.

Q . What are those preferredSize() and minimumSize() methods in Component?

Ans : Those methods allow a LayoutManager to calculate the preferred and minimum sizes of the Components it is arranging. You can control the values that the LayoutManager gets by creating subclasses of the Components you are using and overriding these methods. You don't call them; you override them and they are called on your behalf.

Q . Why isn't my component showing up at all? Or in some cases not until I resize the main window?

Ans  : The initial sizes of components are not always exactly what the programmer would expect. When a component doesn't show up, often it is getting added to its parent, but with a size of 0x0. Even when
getPreferredSize gives a non-zero value. If this seems to be what's happening, try calling setSize(getPreferredSize()). If that doesn't seem to be the problem, look into your layout manager.

Q . When I change some component (e.g. a new label on a button) I don't see the change on the screen immediately even if I repaint().

Ans : You need to add a call to the paintImmediately(x,y,w,h) method of JComponent. That repaints the component completely before continuing execution. On pre-JDK 1.2 systems, use:

invalidate();
validate();

They cause the component hierarchy to be marked as needing to be laid out again, and the validate causes that to be done. It may be expensive, but is a way of getting the peers to recalculate size and to
do what is needed to bring the display up to date. It has limitations:
it doesn't cause an immediate screen update when invoked from an event handler, where paintImmediately() does.

Q . Clipping.. How tod do?

Ans :  java.awt.Graphics.clipRect(int, int, int, int) and related methods are hopelessly flawed, at least as of 1.0. Ignore them completely. 
Instead if you need to do clipping, create separate offscreen Images for each clipping region. Each Image should be the size of the clipping region you desire. Draw into those offscreen images, and then copy them onto the appropriate section of the of your applet window using java.awt.Graphics.drawImage(). Some coordinate conversion will almost certainly be necessary.

If the background image isn't a simple color then you'll first need to copy the appropriate part of that image to your offscreen clipping Image. You can do this by drawing your background Image into your offscreen region with Graphics.drawImage() and a suitable shifting of coordinates.

This all works for rectangular regions only since all Images are rectangular. More complicated geometries can be faked if all but one section contains only simple colors. 

Q . What are AWT peers?

Ans : 

Peers are native-platform on-screen counterparts to AWT components.

     The AWT provides a cross-platform Application Programming Interface (API) for managing user-interface elements and behaviors. To provide a native look and feel, though, the AWT components rely on user-interface elements from the native-platform toolkits to draw themselves on screen and to provide an initial layer of event processing. These native counterparts are called peers. The java.awt.peer package defines interfaces through which Java components can control and otherwise communicate with their peers.
     The AWT peer interfaces are implemented by platform-specific peer classes that access the platform's own toolkit using native methods (that is, methods implemented in a language other than Java). For example, an AWT button has three Javalanguage layers:

  • Button, a class in the java.awt package
  • ButtonPeer, an interface in the java.awt.peer package
  • a platform-specific button peer class containing native methods
     When you write a Java program, you typically only concern yourself with the AWT classes or your own subclasses of them. When the program is run, the AWT selects the appropriate peer objects and hooks them up to your AWT objects. This is the way that your Java program can create and control a Motif button when run on Solaris, a Win32 button when run on Microsoft Windows NT/95, or a Macintosh button when run on MacOS.
     Java programmers should rarely have to deal directly with AWT peer objects, but knowing about them helps to avoid some subtle pitfalls:
  • Some AWT components depend on their peer objects for information such as minimum and preferred sizes. In general, you should make sure a peer exists before you try to get size information about your component.
  • Layout operations check component sizes; hence, they depend on peers.
  • Some methods, such as getGraphics in the Component class, return null if the component doesn't yet have a peer.
Q . What are peer "classes"?

Ans : Peer classes exist mainly for the convenience of the people who wrote the Java environment. They help in translating between the AWT user interface and the native (Windows, OpenWindows, Mac etc.) interfaces. Unless you're porting Java to a new platform you shouldn't have to use them.

Q . When are peers created and destroyed?

Ans :

The creation and destruction of peers is in general triggered by add and remove methods in class Container; but there are further complications.

     Creating an AWT component does not automatically create a peer for that component. Instead, the creation of peers waits until a component is rooted in a containment hierarchy that reaches up to a top-level window (more specifically, a Frame instance). This is necessary for some native toolkits—such as Motif—that require their interface components to be traceable to a top-level window. The AWT builds two well-formed component trees side by side—an AWT component tree and a peer component tree—and the AWT respects the constraints on both sides in the process.
     There are two stages at which peers can be created. On the one hand, a component's peer can be created as soon as the component is added to a container, provided that the container itself already has a peer. This is the case where a peer tree descending from a frame (or other top-level window) already exists and is thus ready to grow further. The top-level window itself will get a peer when either pack or show is invoked on it. (The creation of peers is somewhat of a side effect of pack and show. Window's pack method resizes a window to the preferred size determined by the window's layout manager. Window's how method brings a window on screen if it wasn't visible, or brings the window to the front of other windows if the window is already on screen.)
     Alternatively, a component can be contained, possibly many layers deep, in a Panel instance or other container that isn't yet linked into a frame. In this case, a whole subtree of AWT components exists without a corresponding peer subtree. This subtree is then subject to the first pattern described. As soon as it is added to a container with a peer, it will recursively descend through itself to create peers for all the subtree components.
     The destruction of peers is simpler: a component's peer is destroyed when the component is removed from its container.
     Note: The lifetime of AWT components is separate from that of any peers. For example, you can add and remove a component from a container several times, but each time you do, you create and destroy a separate peer.

Copyright © 2000 javafaq.com. All rights reserved