Creating Objects with Complex Behavior

The behavior handled by a container and its interactors is usually more sophisticated than just a series of simple actions.

Creating such an object is developed in the topics:

Note

Remember that you can also use the Prototypes package of Views to create your own specialized objects.

Example: Creating a Slider

Let us suppose that you have written a C++ program to drive a multimedia system and you are going to use Views to create the graphical user interface for your software. You would like to incorporate the following kind of device into your GUI:

Creating a Visual Device: the Slider

You want your user to be able to change the width of the black bar by placing the cursor anywhere on the bar and dragging the mouse either to the left or to the right. And, as soon as the width of the bar is changed, a function in your C++ software changes the volume of the audio system accordingly. There are two different aspects to the behavior of the slider:

  • Visible Elements  From a purely graphic point of view, the appearance of the device is modified when the user intervenes with the mouse. The black rectangle becomes either narrower or wider, depending on the direction in which the cursor is dragged.

There is thus a modification of the shape of a geometric form. In this example, it is a black rectangle that changes its width, but you could imagine many other kinds of meters, gauges, and dials that could have this same basic behavior. For example, you might have an elliptically-shaped object that becomes either thinner or fatter depending on the direction in which the cursor is dragged.

  • Functional Elements  The real purpose of the slider, of course, is to bring about changes in a domain that is quite remote from the on-screen graphics environment; namely, the audio domain. This is the operational behavior of the slider.

To handle the operational behavior of the slider, we can imagine a function called SliderValue that returns the current value of the slider, and another function, SliderChange, that returns the positive or negative value by which the setting of the slider has just been changed. With these two values, you could establish links to the audio sections of your software, so that the volume is changed accordingly.

Associating a Behavior with Your Device

In the context of Views, we can create a special object—a behavioral object or interactor—that encapsulates the particular behavior described in the section Example: Creating a Slider. In other words, it is an instance of the basic class IlvInteractor. Once you have a behavioral object, you can associate it with various concrete things—a window, a view, a black rectangle, and a few numbers—in order to build an actual slider on the screen.

In the case of the slider, we would probably begin by using IlvInteractor to derive a class called IlvGaugeInteractor with member functions such as SliderValue and SliderChange for the operational behavior that we described above.

The member function handleEvent of this IlvGaugeInteractor class would be written in such a way that it changes the size of the rectangle (or whatever other shape is used) that indicates the current value of the slider.

Since the application domain in which we want to use our slider is rather special, we would probably then derive a subclass of IlvGaugeInteractor, called AudioSlider, with special-purpose member functions for setting the values of audio parameters in a multimedia system. So, we would then have the following class hierarchy:

IlvAudioSlider Hierarchy

Building and Extending your Device

The example that follows illustrates a typical manner in which an open-ended product such as Views can be extended:

  1. Connect your application to a display server.

  2. Create an empty top window where elements of your application can be organized and displayed.

    The following code creates a container, which is the top window located in (0, 0), with a size of 100 units wide and 35 units high.

    IlvRect viewsize(0, 0, 100, 35);

    IlvContainer* topview = new IlvContainer(display, "Audio volume",

    "Audio volume", viewsize);

    The container coordinates the storage and the display of your graphic objects.

    Since you intend to draw certain objects inside this window, and then cause one of these objects to behave in a specific manner by associating an interactor with it, you are obliged to make use of a container.

  3. Place graphic objects in the container.

    The following code places two independent objects inside the container:

    container->addObject(scale);

    container->addObject(bar);

  4. Create functional behavior.

    In this final step, you give the bar the kind of audio-volume slider behavior that is normally associated with an audio slider. Recall that this behavior was encapsulated in a class called AudioSlider. So, the behavior of the audio-volume slider can be given by means of the following lines:

    IlvInteractor* inter = new AudioSlider();

    bar->setInteractor(inter);

    where the class AudioSlider is defined as:

    class Audioslider

    : IlvGaugeInteractor {

    public:

    .../...

    virtual void doIt(IlvGauge* gauge)

    {

    setVolume(gauge->getValue());

    }

    };