Custom functionality may also be included in the shadow classes. For
example, the window shadow will resize the window to its preferred size
and map the window when its visible attribute is set to true.
Rules for writing a shadow:
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.
Groups that are included inside other groups are called subgroups. The top-level group is called the base group. A tree of groups exists while the application is running. Messages sent by subgroups propagate up toward the top of the tree until they are handled or they reach the base group.
From an external viewpoint, a group is a single component that has a set of attributes, public methods, and messages:
Attributes
Attributes for a group are defined in the constructor and are
handled using the getOnGroup and setOnGroup methods. Support is
provided for forwarding a set of attributes to one or more children
of the group--a child being either a shadow or a subgroup.
Methods
Most methods are custom methods written by the author of the group.
There are some useful methods defined in the Group class itself, such
as the get/set attribute methods.
Messages
A group will create messages and post them to their parent groups. By
posting messages, a group does not need to have any knowledge of its
parent. Instead, the parent can listen for a particular message from
its subgroup and perform an action based on the message.
addComponentAttributes, addFrameAttributes,
and addDialogAttributes should be called in the constructor
to add a set of forwarded attributes to the group.
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.
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 pop up an error dialog box.
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.
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 you write need to handle the case of
the group not being initialized or created. This isn't 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.
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: