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

Deriving Window Subclasses

This section summarizes how to create subclasses from the ViewKit ObjectPak window classes. It describes additional virtual functions and data members not covered in previous sections, provides a window creation checklist, and shows an example of deriving a window subclass.

Additional Virtual Functions and Data Members

In addition to the functions described in previous sections, the ObjectPak window classes provide a number of virtual functions and data members that you can access from window subclasses. These functions and data allow you to perform the following tasks:

Providing a "safe quit" mechanism

The VkComponent class provides the virtual function okToQuit() to support "safe quit" mechanisms:

virtual Boolean okToQuit()

A component's okToQuit() function returns TRUE if it is "safe" for the application to quit. For example, you might want okToQuit() to return FALSE if a component is in the process of updating a file. By default, okToQuit() always returns TRUE; you must override okToQuit() for all components that you want to perform a check before quitting. Usually, only VkSimpleWindow and its subclasses use okToQuit().

When you call VkApp::quitYourself(), VkApp calls the okToQuit() function for all registered windows before quitting. If the okToQuit() function for any window returns FALSE, the application does not exit. ("Exiting ViewKit ObjectPak Applications" describes VkApp::quitYourself().)

Also, the window's handleWmDeleteMessage() function calls okToQuit() when the window receives a WM_DELETE_WINDOW message from the window manager. This determines whether it is safe to delete the window. ("Window Properties and Shell Resources" describes handleWmDeleteMessage().)

To perform a test to see whether it is safe to delete a window, override the window's okToQuit() function. If you want to check one or more components contained within a window, you can override the window's okToQuit() function so that it calls the okToQuit() functions for all the desired components. You can then override the okToQuit() functions for the other components so you can perform whatever checks or shutdown actions are necessary. For example, you could post a blocking dialog asking whether the user wants to save data before quitting. ( Chapter 7--Using Dialogs describes how to use ViewKit ObjectPak dialogs.)

Determining window states

The ObjectPak window classes provide the following protected data members for determining the current states of a window:

IconState _iconState Contains an enumerated constant of type IconState that describes the current iconification state of the window. This variable contains OPEN if the window is not iconified, CLOSED if it is iconified, and ICON_UNKNOWN if it is in an unknown state. (Typically, the unknown state is used only internally to the VkSimpleWindow class.)

VisibleState _visibleState Contains an enumerated constant of type VisibleState that describes the current visibility state of the window. This variable contains VISIBLE if the window is visible, HIDDEN if it is not visible, and VISIBLE_UNKNOWN if it is in an unknown state. (Typically, the unknown state occurs only before you add a view to your window.)

StackingState _stackingState Contains an enumerated constant of type StackingState that describes the current stacking state of the window relative to the application. This variable contains RAISED if the window is at the top of the application's window stack, LOWERED if it is at the bottom of the window stack, and STACKING_UNKNOWN if it is in an unknown state (the state before you make any calls to raise() or lower() on this window).

If you need to perform any operations when your window changes its iconification state, you can override stateChanged():

virtual void stateChanged(IconState newState)

stateChanged() is called whenever the window's iconification state changes, whether programmatically (by calls to iconify() and open()) or through window manager interaction. Because this function is responsible for maintaining the window's state information, if you override this function in a subclass you should call the base class's stateChanged() function before performing any additional operations.

Performing actions after realizing a window

To perform certain actions only after a window exists, you can override the afterRealizeHook() function inherited from VkComponent:

virtual void afterRealizeHook()


Note: Use setUpWindowProperties() to set window properties instead of afterRealizeHook(). The difference between afterRealizeHook() and setUpWindowProperties() is that setUpWindowProperties() is guaranteed to be called before the window manager is notified of the window's existence. Because of race conditions, this might not be true of afterRealizeHook(), which is appropriate for performing actions that do not affect the window's interaction with the window manager.


Handling raw events

Handle events not normally handled by the Xt dispatch mechanism by overriding the window's handleRawEvent() function:

virtual void handleRawEvent(XEvent *event)

As described in "ViewKit ObjectPak Event Handling" , VkApp::run() supports events not normally handled by the Xt dispatch mechanism. For example, VkApp::run() can handle client messages and events registered for non-widgets (such as a PropertyNotify event on the root window).

When run() receives an event not handled by the Xt dispatch mechanism, it calls the virtual function VkApp::handleRawEvent(), which passes the event to the handleRawEvent() function of each instance of VkSimpleWindow (or subclass) in the application. By default, these member functions are empty.

If you want a window to handle events through this mechanism, call XSelectInput(3) to select the events that you want to receive, and override handleRawEvent() in the VkSimpleWindow subclass to implement your event processing.

Additional Data Members

The ObjectPak window classes also provide the protected data member _mainWindowWidget:

Widget _mainWindowWidget

_mainWindowWidget contains the XmMainWindow widget created by the window constructor. In a subclass, you can use this data member instead of calling mainWindowWidget(), although this is not recommended.

Window Creation Summary

The following lists a summary of guidelines for creating subclasses of the ObjectPak window classes:

Window Subclassing Example

The program in Example 22. creates ColorWindow, a VkSimpleWindow subclass that implements a simple utility for determining the results of mixing primary ink colors when printing. The user can use toggles to select any of the three primary colors--cyan, magenta, and yellow--and the window reports the resulting color.

Figure 14. shows the widget hierarchy of the ColorWindow subclass. The VkSimpleWindow constructor creates the window's popup shell and XmMainWindow widget. The ColorWindow constructor creates a Form widget to serve as the window's view. The constructor adds a VkCheckBox component as a child of the Form to provide the toggle buttons.

The constructor then adds a Frame widget as a child of the Form widget, and creates two Label gadgets as children of the Frame:

The constructor manages all of these widgets except for the top-level Form widget. (The constructor manages the VkCheckBox component by calling its show() member function.)

Figure 14. Widget Hierarchy of ColorWindow Subclass

This example illustrates a number of object-oriented techniques that you should follow when programming in ViewKit ObjectPak.


Note: All data and utility functions used by the window are declared as members of the ColorWindow class. ColorWindow uses resources to set all the text that it displays, including a set of default values. You can override these values in a resource file (for example, to provide German-language equivalents for all the strings).


Example 22. Creating a Window Subclass

Code

///////////////////////////
// ColorWindow.h
///////////////////////////
#include <Vk/VkSimpleWindow.h>
#include <Vk/VkCheckBox.h>
class ColorWindow: public VkSimpleWindow {
  public:
    ColorWindow (const char *);
    ~ColorWindow();
    virtual const char* className();
  private:
    void displayColor(char *);
    void colorChanged(VkCallbackObject *, void *, void *);
    static String _defaultResources[]; // Default resource values
    static String _colors[];           // Array of possible resulting colors
    Widget _resultColor;               // Label to display resulting color
    VkCheckBox *_primaries;            // Checkbox for setting colors
    int _colorStatus;                  // Bit-wise color status variable
                                       //     Bit 0: Cyan
                                       //     Bit 1: Magenta
                                       //     Bit 2: Yellow
                                       //   Also used as index into _colors[]
};
///////////////////////////
// ColorWindow.C
///////////////////////////
#include "ColorWindow.h"
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>
#include <Xm/LabelG.h>
#include <Vk/VkCheckBox.h>
#include <Vk/VkResource.h>
// Default ColorWindow class resource values.
String ColorWindow::_defaultResources[] = {
    "*windowTitle:                  Color Mixer",
    "*iconTitle:                    Color Mixer",
    "*primaries*label*labelString:  Primary Colors",
    "*cyan.labelString:             Cyan",
    "*magenta.labelString:          Magenta",
    "*yellow.labelString:           Yellow",
    "*resultLabel.labelString:      Resulting Color",
    "*cyan:                         Cyan",
    "*magenta:                      Magenta",
    "*yellow:                       Yellow",
    "*blue:                         Blue",
    "*red:                          Red",
    "*green:                        Green",
    "*white:                        White",
    "*black:                        Black",
    NULL };
// Set _colors array to correspond to color values indicated by the
// bits in the _colorStatus variable.
String ColorWindow::_colors[] = {
    "white",
    "cyan",
    "magenta",
    "blue",
    "yellow",
    "green",
    "red",
    "black" };
ColorWindow::ColorWindow (const char *name) : VkSimpleWindow (name)
{
    Arg args[5];
    int n;
    // Set default resources for the window.
    setDefaultResources(mainWindowWidget(), _defaultResources);
    
    // Create a Form widget to use as the window's view.
    Widget _form = XmCreateForm(mainWindowWidget(), "form", NULL, 0);
    
    // Create a VkCheckBox object to allow users to select primary colors.
    // Add toggle buttons and set their intial values to FALSE (unselected).
    // The labels for the checkbox frame and the toggle buttons are set
    // by the resouce database.
    
    _primaries = new VkCheckBox( "primaries", _form );
    _primaries->addItem("cyan", FALSE);
    _primaries->addItem("magenta", FALSE);
    _primaries->addItem("yellow", FALSE);
    _primaries->addCallback(VkCheckBox::itemChangedCallback, this,
                            (VkCallbackMethod) &ColorWindow::colorChanged);
    _primaries->show();
    
    // Set constraint resources on checkbox's base widget.
    
    n = 0;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
    XtSetValues(_primaries->baseWidget(), args, n);
    // Create a frame to display the name of the resulting blended color.
    n = 0;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
    XtSetArg(args[n], XmNleftWidget, _primaries->baseWidget()); n++;
    Widget _result = XmCreateFrame(_form, "result", args, n);
    XtManageChild(_result);
    
    // Create a frame title label.  The label text is set by the resource
    // database.
    
    n = 0;
    XtSetArg(args[n], XmNchildType, XmFRAME_TITLE_CHILD); n++;
    Widget _resultLabel = XmCreateLabelGadget( _result, "resultLabel", args, n);
    
    // Create the label to display the blended color name.
    
    _resultColor = XmCreateLabelGadget( _result, "resultColor", NULL, 0);
    
    // Set intial value of _colorStatus and label string to white (all off).
    
    _colorStatus = 0;
    displayColor(_colors[_colorStatus]);
    
    XtManageChild(_resultLabel);
    XtManageChild(_resultColor);
    // Add the top-level Form widget as the window's view.
    addView(_form);
    
    // Set the window title and the icon title.
    
    setTitle("windowTitle");
    setIconName("iconTitle");
}
ColorWindow::~ColorWindow()
{
    // Empty
}
const char* ColorWindow::className()
{
    return "ColorWindow";
}
// Given a color name, update the label to display the color
void ColorWindow::displayColor(char *newColor)
{
    Arg args[2];
    int n;
    // Common resource trick in ObjectPak applications.
    // Given a string, check the resource database for a corresponding
    // value.  If none exists, use the string as the value.
    char *_colorName = (char *) VkGetResource(_baseWidget, newColor, "Color",
                                              XmRString, newColor);
    // Update the label
    XmString _label = XmStringCreateSimple(_colorName);
    n = 0;
    XtSetArg(args[n], XmNlabelString, _label); n++;
    XtSetValues(_resultColor, args, n);
    XmStringFree(_label);
}
// When the user changes the value of one of the toggles, update the
// display to show the new blended color.
void ColorWindow::colorChanged(VkCallbackObject *obj, void *, void *callData)
{
    ColorWindow *win = (ColorWindow *) obj;
    int index = (int) callData;
    
    // Update color status based on toggle value.  Set or rest the
    // status bit corresponding to the respective toggle.
    if (_primaries->getValue(index))
        _colorStatus |= 1<<index;
    else
        _colorStatus &= ~(1<<index);
    // Update the display to show the new blended color, using
    // _colorStatus as an index.
    displayColor(_colors[_colorStatus]);
}
///////////////////////////
// colors.C
///////////////////////////
#include <Vk/VkApp.h>
#include "ColorWindow.h"
void main ( int argc, char **argv )
{
    VkApp *colorApp = new VkApp("ColorApp", &argc, argv);
    ColorWindow *colorWin = new ColorWindow("colorWin");
    colorWin->show();
    colorApp->run();
}

The colors program displays the ColorWindow shown in Figure 15.

Figure 15. Example of the ColorWindow Window Subclass



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

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