[Top] [Prev] [Next] [Index]
Page 17 out of 116 total pages , Page 6 out of 6 pages in this chapter

Deriving Subclasses to Create New Components

This section demonstrates how to use the VkComponent class to create new components. It includes guidelines to follow when creating new components, an example of creating a new component, and an example of subclassing that component to create yet another component class.

Subclassing Summary

The following is a summary of guidelines for writing components based on the VkComponent class:

Creating a New Component

To illustrate many of the features of the VkComponent base class, this chapter has shown how to build a simple class called StartStopPanel, which implements a control panel containing two buttons. Figure 4. shows the default appearance of a StartStopPanel object.

Figure 4. Default Appearance of a StartStopPanel Component

Example 8. A Simple User-Defined Component

The following code section lists the full implementation of this class.

Code

//////////////////////////////////////////////////////////////
// StartStopPanel.h
//////////////////////////////////////////////////////////////
#ifndef _STARTSTOPPANEL_H
#define _STARTSTOPPANEL_H
#include <Vk/VkComponent.h>
enum PanelAction { START, STOP };
class StartStopPanel : public VkComponent {
  public:
    StartStopPanel (const char *, Widget);
    ~StartStopPanel();
    virtual const char *className();
    static const char *const actionCallback;
  protected:
    virtual void start(Widget, XtPointer);
    virtual void stop(Widget, XtPointer);
    Widget _startButton;
    Widget _stopButton;
  private:
    static void startCallback(Widget, XtPointer, XtPointer);
    static void stopCallback(Widget, XtPointer, XtPointer);
    static String _defaultResources[];
};
#endif
/////////////////////////////////////////////////////////////
// StartStopPanel.C
/////////////////////////////////////////////////////////////
#include "StartStopPanel.h"
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
// These are default resources for widgets in objects of this class
// All resources will be prefixed by *<name> at instantiation,
// where <name> is the name of the specific instance, as well as the
// name of the baseWidget. These are only defaults, and may be
// overriden in a resource file by providing a more specific resource
// name
String StartStopPanel::_defaultResources[] = {
  "*start.labelString:  Start",
  "*stop.labelString:   Stop",
  NULL
};
const char *const StartStopPanel::actionCallback = "actionCallback";
StartStopPanel::StartStopPanel(const char *name, Widget parent) :                                                       VkComponent(name)
{
  // Load class-default resources for this object before creating base widget
  setDefaultResources(parent, _defaultResources );
  // Create an XmRowColumn widget as the component's base widget
  // to contain the buttons. Assign the widget to the _baseWidget
  // data member.
  _baseWidget = XmCreateRowColumn ( parent, _name, NULL, 0 );
  // Set up callback to handle widget destruction
  installDestroyHandler();
  XtVaSetValues(_baseWidget, XmNorientation, XmHORIZONTAL, NULL);
  // Create all other widgets as children of the base widget.
  // Manage all child widgets.
  _startButton = XmCreatePushButton ( _baseWidget, "start", NULL, 0);
  _stopButton = XmCreatePushButton ( _baseWidget, "stop", NULL, 0);
  XtManageChild(_startButton);
  XtManageChild(_stopButton);
  // Install static member functions as callbacks for the buttons
  XtAddCallback(_startButton, XmNactivateCallback,
                &StartStopPanel::startCallback, (XtPointer) this );
  XtAddCallback(_stopButton, XmNactivateCallback,
                &StartStopPanel::stopCallback, (XtPointer) this );
}
StartStopPanel::~StartStopPanel()
{
  // Empty
}
const char* StartStopPanel::className()
{
  return "StartStopPanel";
}
void StartStopPanel::startCallback(Widget w, XtPointer clientData,
                                   XtPointer callData)
{
  StartStopPanel *obj = ( StartStopPanel * ) clientData;
  obj->start(w, callData);
}
void StartStopPanel::stopCallback(Widget w, XtPointer clientData,
                                  XtPointer callData)
{
  StartStopPanel *obj = ( StartStopPanel * ) clientData;
  obj->stop(w, callData);
}
void StartStopPanel::start(Widget, XtPointer)
{
  callCallbacks(actionCallback, (void *) START);
}
void StartStopPanel::stop(Widget, XtPointer)
{
  callCallbacks(actionCallback, (void *) STOP);
}

Examples of Using and Subclassing a Component Class

Example 8. slightly changes the StartStopPanel class from previous examples by declaring the member function StartStopPanel::start() and StartStopPanel::stop() as virtual functions. This allows you to use the StartStopPanel in two different ways: using the component directly and subclassing the component.

Using a Component Class Directly

The simplest way to use the StartStopPanel class is to register callbacks with StartStopPanel::actionCallback. To do so, instantiate a StartStopPanel object in your application and register as a callback a member function that tests the value of the call data and performs some operation based on the value. This option avoids the additional work required to create a subclass of StartStopPanel. This technique of using a component class is most appropriate if the class already has all the functionality you require.

Example 9. shows a simple example of using the StartStopPanel directly. The PanelWindow class is a simple subclass of the VkSimpleWindow class, which is discussed in Chapter 4--ViewKit Windows. It performs the following activities in its constructor:

  1. It instantiates a StartStopPanel object named "controlPanel" and assigns it to the _controlPanel variable.
  2. It specifies a vertical orientation for the StartStopPanel object.
  3. It installs PanelWindow::statusChanged() as an ObjectPak callback function to be called whenever StartStopPanel::actionCallback triggers. In this example, PanelWindow::statusChanged() simply prints a status message to standard output whenever it is called.
  4. It installs the _controlPanel object as the window's "view." Showing the PanelWindow object will now display the _controlPanel object. ("Creating the Window Interface" describes how to create window interfaces.)

Example 9. Using a Component Directly

Code

//////////////////////////////////////////////////////////////
// PanelWindow.h
//////////////////////////////////////////////////////////////
#ifndef _PANELWINDOW_H
#define _PANELWINDOW_H
#include "StartStopPanel.h"
#include <Vk/VkSimpleWindow.h>
// Define a top-level window class
class PanelWindow: public VkSimpleWindow {
  public:
    PanelWindow(const char *name);
    ~PanelWindow();
    virtual const char* className();
  protected:
    void statusChanged(VkCallbackObject *, void *, void *);
    StartStopPanel * _controlPanel;
};
#endif
//////////////////////////////////////////////////////////////
// PanelWindow.C
//////////////////////////////////////////////////////////////
#include "PanelWindow.h"
#include <iostream.h>
PanelWindow::PanelWindow(const char *name) : VkSimpleWindow (name) 
{
    _controlPanel = new StartStopPanel( "controlPanel",
                                        mainWindowWidget() );
    XtVaSetValues(_controlPanel->baseWidget(),
                  XmNorientation, XmVERTICAL, NULL);
    _controlPanel->addCallback( StartStopPanel::actionCallback, this,
                         (VkCallbackMethod) &PanelWindow::statusChanged );
    addView(_controlPanel);
}
const char * PanelWindow::className()
{
    return "PanelWindow";
}      
PanelWindow::~PanelWindow()
{
    // Empty
}
void PanelWindow::statusChanged(VkCallbackObject *obj,
                                void *, void *callData)
{
    StartStopPanel * panel = (StartStopPanel *) obj;
    PanelAction action = (PanelAction) callData;
    switch (action) {
        case START:
            cout << "Process started\n" << flush;
            break;
        case STOP:
            cout << "Process stopped\n" << flush;
            break;
        default:
            cout << "Undefined state\n" << flush;
    }
}

The following simple program displays the resulting PanelWindow object (Refer to Chapter 3--Application Class for more information about the VkApp:

//////////////////////////////////////////////////////////////
// PanelTest.C
//////////////////////////////////////////////////////////////
#include <Vk/VkApp.h>
#include "PanelWindow.h"
// Main driver. Just instantiate a VkApp and the PanelWindow,
// "show" the window and then "run" the application.
void main ( int argc, char **argv )
{
    VkApp        *panelApp = new VkApp("panelApp", &argc, argv);
    PanelWindow  *panelWin = new PanelWindow("panelWin");
    panelWin->show();
    panelApp->run();
}

Figure 5. shows the resulting PanelWindow window displayed by this program.

Figure 5. Resulting PanelWindow Window

Using a Component Class by Subclassing

Another way to use the StartStopPanel class is to derive a subclass and override the StartStopPanel::start() and StartStopPanel::stop() functions. This technique of using a component class is most appropriate if you need to expand or modify a component's action in some way.

Example 10. creates ControlPanel, a subclass of StartStopPanel that incorporates the features implemented in the PanelWindow class shown in Example 9.

Example 10. Subclassing a Component

Code

//////////////////////////////////////////////////////////////
// ControlPanel.h
//////////////////////////////////////////////////////////////
#ifndef _CONTROLPANEL_H
#define _CONTROLPANEL_H
#include "StartStopPanel.h"
class ControlPanel : public StartStopPanel {
  public:
    ControlPanel (const char *, Widget);
    ~ControlPanel();
    virtual const char *className();
  protected:
    virtual void start(Widget, XtPointer);
    virtual void stop(Widget, XtPointer);
};
#endif
//////////////////////////////////////////////////////////////
// ControlPanel.C
//////////////////////////////////////////////////////////////
#include "ControlPanel.h"
#include <iostream.h>
ControlPanel::ControlPanel (const char *name , Widget parent) :
                                             StartStopPanel (name, parent)
{
    XtVaSetValues(_baseWidget, XmNorientation, XmVERTICAL, NULL);
}
ControlPanel::~ControlPanel()
{
    // Empty
}
const char* ControlPanel::className()
{
    return "ControlPanel";
}
void ControlPanel::start(Widget w, XtPointer callData)
{
    cout << "Process started\n" << flush;
    StartStopPanel::start(w, callData);
}
void ControlPanel::stop(Widget w, XtPointer callData)
{
    cout << "Process stopped\n" << flush;
    StartStopPanel::stop(w, callData);
}

The ControlPanel constructor uses the StartStopPanel constructor to initialize the component, creating the widgets and initializing the component's data members. Then, the ControlPanel constructor sets the orientation resource of the RowColumn widget, which is the component's base widget, to VERTICAL.

The ControlPanel class also overrides the virtual functions start() and stop() to perform the actions handled previously by the PanelWindow class. After performing these actions, the ControlPanel::start() and ControlPanel::stop() functions call StartStopPanel::start() and StartStopPanel::stop() respectively. While this may seem unnecessary for an example this simple, it helps preserve the encapsulation of the classes. You could now change the implementation of the StartStopPanel class, perhaps adding a status indicator to the component that the StartStopPanel::start() and StartStopPanel::stop() functions would update, and you would not have to change the start() and stop() function definitions in derived classes such as ControlPanel.

The following simple example creates a VkSimpleWindow object, adds a ControlPanel as the window's view, and then displays the window:

Code

//////////////////////////////////////////////////////////////
// PanelTest2.C
//////////////////////////////////////////////////////////////
#include <Vk/VkApp.h>
#include <Vk/VkSimpleWindow.h>
#include "ControlPanel.h"
// Main driver. Instantiate a VkApp, a VkSimpleWindow, and a
// ControlPanel, add the ControlPanel as the SimpleWindow's view,
// "show" the window and then "run" the application.
void main ( int argc, char **argv )
{
    VkApp *panelApp = new VkApp("panel2App", &argc, argv);
    VkSimpleWindow *panelWin = new VkSimpleWindow("panelWin");
    ControlPanel *control = new ControlPanel("control",
                                             panelWin->mainWindowWidget() );
    panelWin->addView(control);
    panelWin->show();
    panelApp->run();
}


[Top] [Prev] [Next] [Index]
Page 17 out of 116 total pages , Page 6 out of 6 pages in this chapter

info@ics.com
Copyright © 1998, Integrated Computer Solutions, Inc. All rights reserved.