# More on Groups and Shadows

This is a continuation of the groups and shadows discussion.

## Groups

The primary purpose of GUI builder is to help you create groups. To be considered a group, a class must be a subclass of the Group class.

### Rules for Writing a Group

- All attributes must be defined in the constructor. The helper methods `addComponentAttributes`, `addFrameAttributes`, and `addDialogAttributes` should be called in the constructor to add a set of forwarded attributes to the group.
- In general, all attributes defined in the group should be handled in method overrides of `getOnGroup` and `setOnGroup`. Any attributes that are not handled should be passed up using a call to super.

  You may call `super.setOnGroup` with an attribute, even if the attribute is already being handled by your `setOnGroup` method. This will cause the attribute value to be stored in the group's list of attributes. Then, the `getOnGroup` method will automatically look up this attribute's value from the list.

  So make sure that any attributes that are handled in `setOnGroup` without calling super are also handled in the `getOnGroup` method.

- `initRoot` must be overridden to initialize the root of the application. The root contains all the children that are contained by the group. The default generated group contains an `initRoot` method that does the right thing.
- The `startGroup` and `stopGroup` methods can be overridden to get notification when the applet starts and stops. Also `startGroup` will be called when standalone applications are completely done initializing. This can be useful if, for example, you want to do something that may cause an error, and you want to immediately display an error dialog box.
- The `handleMessage` and `handleEvent` methods should be overridden to receive AWT events from the root children. For AWT events, the target of the message is the shadow corresponding to the AWT component that sent the event. The target of the AWT event is (of course) the AWT component itself.

  For AWT components that do not have a shadow, the target of the message will be set to the AWT component itself.

- You need to be careful about delayed instantiation. The `setOnGroup` and `getOnGroup` methods will not be invoked until the group has been initialized. When the group is initialized, `setOnGroup` will be invoked for all the attributes.

  However, any custom methods that you write need to handle the case of the group not being initialized or created. This is not a problem if the user of the group is careful not to call the group's methods until it is initialized-but better safe than sorry. Dealing with the group not being initialized almost always consists of doing a null check on the `gui` instance variable.

## Shadows

To import a custom AWT component into the GUI builder's palette, you must write a shadow class for it. GUI builder includes shadow classes for all the standard AWT components.

### Rules for Writing a Shadow

- All attributes must be declared in the constructor. Attributes should only be added or removed in the constructor.
- All attributes must be handled by the `getOnBody` and `setOnBody` methods in the shadow class where they are declared (attributes flagged with `NONBODY` are the exception to this rule).
- `getOnBody` and `setOnBody` should invoke super for all attributes that aren't handled in that particular shadow class.
- The default value of an attribute can be overridden by a shadow class. Overriding the default value does require handling of the attribute by the overriding shadow. The attribute can be handled by the class in which it was originally declared.
- In general, attributes do not need any flags. If you use an attribute flag, be sure that you know what it does.

Both shadows and groups can be imported into the palette of GUI builder. For information on how this can be done, see Accessing AWT Methods for Shadows Classes.

### Putting AWT Components That Do Not Have a Shadow Inside a Group

If an AWT component does not have a shadow, add it as a child of an existing panel or frame that is already inside the group. The events from the AWT component will be delivered to the group. The message target will be the same as the AWT event target. Normally the message target is set to the shadow corresponding to the AWT event target, but in this case there is no corresponding shadow.

Another method for adding an AWT component is to use the Generic Component. The Generic Component is a special component that you can use to import any custom AWT component class that you write. See Adding Custom Components and Windows for a discussion of Generic Component.

### How to Use Groups Without the Generated Main

The following examples show how to use groups without the generated main.

Main

      // Construct the group

      Group group = new MyFancyGroup();

      // Set the group environment.  The "args" are command
      // line arguments.

      group.setEnvironmentInfo(null, args);

      // Initialize the group

      group.initialize();

      // Set the top level on the group

      WindowShadow win = (WindowShadow)group.getWindow();
      if (win instanceof FrameShadow) {
        win.createBody();
        group.setTopLevel((Frame)win.getBody());
      }
      else {
        group.setTopLevel(/* Pass in an existing frame window
    			 from your application */);
      }

      // Create the group

      group.create();

      // If the group is a panel group, add it in the
      // hierarchy somewhere

      if (group.getPanel() != null) {
        myApplicationFrame.add((Panel)group.getPanel().getBody());
      }

      // Start the group

      group.start();

Applet

      // Construct the group

      Group group = new MyFancyGroup();

      // Set the group environment.  The "applet" must be available here.

      group.setEnvironmentInfo(myApplet, null);

      // Initialize the group

      group.initialize();

      // Set the top level on the group

      WindowShadow win = (WindowShadow)group.getWindow();
      if (win instanceof FrameShadow) {
        win.createBody();
        group.setTopLevel((Frame)win.getBody());
      }
      else {
        // Figure out the applet's frame

        Component comp = applet;
        while (comp != null && !(comp instanceof Frame))
          comp = comp.getParent();
        group.setTopLevel((Frame)comp);
      }

      // Create the group

      group.create();

      // If the group is a panel group, add it in the
      // hierarchy somewhere

      if (group.getPanel() != null) {
        myApplet.add((Panel)group.getPanel().getBody());
      }

The start, stop, and destroy methods should be forwarded from the applet to the group:

      group.start();
      group.stop();
      group.destroy();

See also:

  What Are Groups and Shadows?
  Generating Java Source Code
  Adding Operations to Components
  GUI Builder Runtime Classes
  Adding Operations to Menus
  Importing Components

  Visual Java API Documentation
    Visual Java GUI Builder Runtime Packages
    Class Hierarchy
    Index of All Fields and Methods