10.1. Creating a New Component

This section describes the general process of creating a new component. The sample class shown here is derived from SoXtRenderArea . The second half of this chapter, beginning with Section 10.2, “Creating a New Viewer”, describes creating a more specialized component, a viewer.

Overview

There are no special macros for creating new component classes. Creating a new component requires these steps:

Select a name for the new component class and determine what class it is derived from (see the section called “Overview” for a discussion of deriving new viewers).

Define a constructor for the new class. If you want other programmers to be able to derive classes from your new class, you need to define two constructors for the class, a public constructor and a protected one (see the section called “Defining the Constructor”). If no one will be deriving classes from your new class, you can simply define a public constructor.

Implement show() and hide() methods for your component (optional step). The base class, SoXtComponent , takes care of showing and hiding your new component. But if your component needs to show other components when it is shown, or hide other components when it is hidden, you need to implement these two methods for your new class (see the section called “The show() and hide() Methods”).

See the SoXtComponent.h file for additional methods you may choose to implement. Possibilities include the following:

windowCloseAction()

specifies what happens when the user closes the window using the Window Manager (for example, you could implement this method to exit the program or delete the component)

openHelpCard()

opens a help card for the component

Defining the Constructor

If you are sure that no one will need to derive classes from your new component, you can simply implement one public constructor. This constructor needs to do the following:

Build the widget (or the widget tree if your component is made up of more than one widget)

Call setBaseWidget() so that the SoXtComponent base class methods—such as show() and hide()—work properly

Defining Public and Protected Constructors

If you want to be sure that programmers can derive new classes from your class, you need to provide a protected constructor in addition to the public constructor. Here's why. The widget tree is built when the component is constructed. If you derive a component subclass, the parent class constructor is called before the constructor of the subclass. This means that the parent class widget is built before the subclass widget. The problem arises if you want the component subclass to provide a container widget for the parent class. The Xt Library requires that a parent widget be supplied when a child widget is created and provides no way to reparent a widget. A little fancy footwork is required for the subclass to provide the parent widget, and that maneuver is provided by the protected constructor.

In Inventor, every SoXtComponent class has two constructors: a public constructor and a protected constructor. The protected constructor has one additional parameter, buildNow, which is a Boolean value that specifies whether to build the widget tree now or later:

If you use the protected constructor and specify FALSE for buildNow, you can have explicit control over which widgets are built and in what order. For example, your new class may want to build a container widget such as a Motif-style form or bulletin board before it lets the parent class build its widget. In this case, your new class can call its buildWidget() method first and then later it can call the buildWidget() method of its parent class. In Inventor, the SoXtFullViewer class uses this technique. It builds a form widget with user interface trim and then has the parent class, SoXtRenderArea , later build its widget inside this form.

In Inventor, and in Examples 10-1 and 10-2, the basic constructor tasks are put into the constructorCommon() method, which is called by both constructors. Although this is a useful technique, it is not required. The constructorCommon() method is where the actual building of this widget occurs. This method checks the buildNow flag and builds the widget.

Let's analyze the constructorCommon() code in Example 10.2, “
SceneTumble.c++
” in a bit more detail. After setting up sensors, a camera, and a light for the component, the following calls are made:

The visibility-changed callback is described in the section called “Visibility-Changed Callback Function”. The setClassName() method sets the name of the class for X resource lookup, which occurs while the widget is being built. The setTitle() method sets the title used in the shell window if this is a top-level component. Although not shown here, you can also call setIconTitle() to set the title used when the component is iconified.

The constructor then checks the buildNow flag. If this flag is TRUE, it builds the widget tree. Also, note that the buildWidget() method uses getParentWidget() to obtain the parent widget, which is not necessarily the parent widget passed in to the constructor. (The parent passed in to the constructor could be NULL, or the buildInsideParent parameter could be FALSE.)

Next, the constructor calls the setBaseWidget() method, which letsSoXtComponent know what the root of the widget tree is. This widget is used for layout, and by the show() and hide() methods.

The buildWidget() Method

In Inventor, because we want to allow subclasses to have explicit control over building the widget tree, we implement a separate buildWidget() method. If you are providing only the public constructor, you can simply build the widget in the constructor and do not need to create a separate buildWidget() method. This method, called by the constructor of your new class (or by subclasses of your new class), builds the widget hierarchy and returns its topmost widget.

If your widget supports X resources, be sure to call registerWidget() immediately after you create the topmost container widget and before you build the rest of the widget hierarchy. This method associates the Motif-style widget with the Inventor component to which it belongs. When you create other widgets in the hierarchy, Inventor uses the class name of the component instead of the widget name during resource lookup. For example, the base widget of a render area is a Motif-style bulletin board. Once you have called registerWidget(), you can set the background color resource directly on the render area without affecting other bulletin board widgets in your hierarchy.

To define and retrieve your own resources, see the Open Inventor C++ Reference Manual on SoXtResource . For more information on X resources, see the Xlib Programming Manual by Adrian Nye (O'Reilly & Associates, 1990).

The show() and hide() Methods

The base class SoXtComponent will show and hide your new component automatically. However, if your component needs to show or hide other components, you must implement your own show() and hide() methods. In Inventor, if the material editor and color editor are on the screen and the program tells the material editor to hide itself, the material editor needs to tell the color editor to hide itself as well. Similarly, when a viewer hides itself, it also hides the preference sheet if it is visible.

Visibility-Changed Callback Function

Using addVisibilityChangeCallback(), your new class can register a callback function with SoXtComponent that is called when its visibility changes. A component can be shown, hidden, or iconified; whenever it changes state between visible and invisible (hidden or iconified), the visibility-changed callback function is invoked. This callback is useful, for example, if your component contains a scene with animation. When your component is hidden or iconified, it can stop the animation. Another example of using this callback is the render area, which detaches its redraw sensor when it is hidden or iconified.

Creating a Simple Component

The following examples show the header file and source code for a simple component derived from SoXtRenderArea . This component animates a camera to rotate the scene. It uses a visibility-changed callback function to stop the tumbling when the component is not visible. A slider at the bottom of the window controls the speed of tumbling.

FEI Visualization Sciences Group is the leading provider of advanced 3D visualization and analysis software tools for developers, engineers and scientists in natural resources, medical and life sciences, and engineering.