While most components integrated into Builder Xcessory are relatively primitive, the component model that Builder Xcessory follows encourages the creation of abstract classes and subclasses of existing classes. If a class's superclass has already been integrated into Builder Xcessory, then some of the work described in Chapter 8--Modifying the WML File will be reduced.
Subclasses present more of an issue for editing the component's resources. "Editing Resources On Subclass Components" describes regular resources that have set/get methods provided in the sub- or superclass. However, as described in"Managing additional constructor parameters" , some resources are used as constructor parameters, which poses a difficult problem. The CreateComponent integration method for the superclass already deals with these resources. But, because that method creates an instance of our superclass, it is a practical impossibility to call the superclass's CreateComponent method in a subclass.
Writing a new CreateComponent method
One solution to this problem is to write a new CreateComponent method for the subclass that contains all the code required to deal with the superclass's constructor resources. This results in duplication of code for the superclass's constructor resources. If the superclass is changed then all the subclass integration code will need to be modified.
Writing a routine
An alternative solution to this problem is to write a routine that is called from the creation function for both the superclass and subclass. This routine can have any prototype, but at the very least will need to take an ArgList (containing a list of resources) and a Cardinal (set to the number of items in the ArgList). This routine would scan the resource list for constructor parameters and somehow provide the values to the caller. Both the superclass and subclass creation function could then use this routine to scan for the constructor parameter and so save recoding this search for every subclass that needs it.
- char *
FindMyComponentLabel(ArgList before, Cardinal before_count,
ArgList after, Cardinal *after_count)
- // Storage for the constructor parameter value.
- char *label = NULL;
- // Scan the list for constructor parameters.
- for (int i = 0; i < before_count; i++)
- if (!strcmp("label", args[i].name))
- label = (char *)args[i].value;
- before[i].name, before[i].value);
- return label;
- extern "C" void *
CreateMyComponent(Widget parent, char *name,
ArgList args, Cardinal ac)
- // So as not to pass the constructor parameter resource
- // to the Edit function, we'll allocate a new resource
- // list and copy in only the resources not corresponding
- // to constructor parameters.
- Cardinal rsc_count = 0;
- ArgList resources = (ArgList)XtMalloc(ac*sizeof(Arg))
- // Extract the constructor parameter from the ArgList
char *label = FindMyComponentLabel(args, ac,
- // Create the component with the constructor parameter
- // and pass the remaining attributes to the Edit function.
- MyComponent *obj = new MyComponent(name, parent, label);
- EditMyComponent((void *)obj, True, resources, rsc_count);
- // Free the allocated memory.
- XtFree((char *)resources);
- // Return the new component.
- return (void *)obj;
Editing a Component (AttributeFunction)
Editing component resources
Typically, you edit object attributes in C++ with set/get method pairs. Often, classes supply only a set method. Rare does the component supply only a get method. Builder Xcessory allows you to provide a method to do the binding between ArgList items and methods on a component by providing a single method to accomplish both set and get functions. This function should check each Arg in the ArgList to see if it matches a component resource (which will be defined in the WML file), or a base widget resource. The function supplied should match the prototype:
Example Edit Method
extern "C" void
- EditMyComponent(void *object, Boolean set,
- ArgList p_args, Cardinal p_ac)
- MyComponent *obj = (MyComponent *)object;
- // A loop index variable.
- int i;
- // Allocate two argument lists --
- // one for base widget resources, used when values
- // are both set and retrieved.
- ArgList bw_args = (ArgList)XtMalloc(p_ac * sizeof(Arg));
- Cardinal bw_ac = 0;
- // and one for component level resources, used ONLY
- // when values are retrieved.
- ArgList c_args = (ArgList)XtMalloc(p_ac * sizeof(Arg));
- Cardinal c_ac = 0;
- // Loop through the parameter argument list either set or
- // get the values appropriately.
- for (i = 0; i < p_ac; i++)
- if (!strcmp("myAttribute", p_args[i].name))
- if (set)
- // p_args[i].value contains a pointer to
- // the value to set.
- MyAttributeType *val =
- (MyAttributeType *) p_args[i].value;
- // Set the value of "myAttribute" by calling
- // the corresponding method.
- // Get the current value of "myAttribute"
- // and store it in c_args[c_ac].value.
- XtSetArg(c_args[c_ac], p_args[i].name,
- // The attribute doesn't correspond to a component
- // method, so keep it to set or get on the base widget.
- XtSetArg(bw_args[bw_ac], p_args[i].name,
- // Now take care of the base widget resources.
- if (set)
- XtSetValues(obj->baseWidget(), bw_args, bw_ac);
- XtGetValues(obj->baseWidget(), bw_args, aw_ac);
- // When we get values, we need to merge all the
- // retrieved values back into the p_args ArgList.
- // First put back the values fetched from the
- // base widget.
- for (i = 0; i < bw_ac; i++)
- // Then put back the values retrieved using
- // methods of the component. Remember to start in
- // the list where we left off in the last loop.
- for (i = 0; i < c_ac; i++)
- XtSetArg(p_args[bw_ac + i], c_args[i].name,
- // Free the allocated memory.
- XtFree((char *)bw_args);
- XtFree((char *)c_args);
This function deals with one component attribute called "myAttribute". This resource will be described in the WML as a resource in standard resource format. The resource name in the WML code could be XmNmyAttribute.
- Takes in a list of arguments in the standard Xt Arg structure and cycles through them
- Builds two destination lists one for component resources (c_args), and one for base widget resources (bw_args).
The argument "set" is True. For each Arg passed into the function in
p_args, see if its name matches any of the component attributes (using
strcmp to compare
Arg.name to the attribute name). If the comparison succeeds, call the appropriate set methods to set the attribute using the value supplied in
Arg.value. If all comparisons fail, add this Arg to the list of Args for the base widget.
For each Arg passed into the function in
p_args, see if its name matches any of the component attributes. If the comparison succeeds, call the appropriate get method to retrieve the value and assign that value to the
Some component attributes may not have a set/get pair. In this case, ignore the Arg and do not assign any value to
Arg.value, or increment the counter
c_ac. It is also a good idea to use the WML construct NeverVerify = True for this resource, so that Builder Xcessory never passes it to the Edit function.
If the comparison with all component attributes fails, assign the Arg.name to the
bw_args. Once all component attributes have been retrieved, the
bw_args array will contain those resources to be retrieved from the component's base widget. Call XtGetValues to get the values for these resources.