Creating the Window Interface

This section describes the following three methods that you can use to create the contents of a window:

  • Create a subclass of VkSimpleWindow or VkWindow and define the interface in the class constructor
  • Create a subclass of VkSimpleWindow or VkWindow and define the interface by overriding the virtual function setUpInterface(),
  • Create an instance of VkSimpleWindow or VkWindow, define the interface separately, and then add the interface as the window's view

The following sections describe each method, and the advantages and disadvantages of each approach.

Creating the Window Interface in the Constructor

The preferred method of defining the contents of a window is to create the interface in the constructor of a VkSimpleWindow or VkWindow subclass. In this case, you simply create the widgets and components that you want to appear in your window in your subclass constructor. Remember that each window can have only one direct child widget as a view, so in most cases you must create a container widget and then create all other widgets and components as descendents of this direct child. Manage all widgets except the container widget, which you should leave unmanaged.

The parent widget of your view's top-level widget or component must be the window's XmMainWindow widget. You can retrieve this widget by calling the mainWindowWidget() function inherited from VkSimpleWindow. "Window Data Access Functions" discusses the mainWindowWidget() function.


Note: The _baseWidget data member for VkSimpleWindow and derived classes is the window's popup shell widget. Do not assign any other widget to this data member in a derived class.


After creating your interface, call addView():

void addView(Widget w)
void addView(VkComponent *component)

addView() accepts as an argument either a widget or a pointer to a component, which addView() installs as the view for the window.


Note: Some OSF/Motif functions such as XmCreateScrolledText(3) create a ScrolledWindow widget and a child widget, and then return the ID of the child widget. As a convenience for using these functions, addView() can automatically determine the correct parent widget if you provide the child widget ID instead of the ScrolledWindow ID.


Example 17. shows a simple example that defines ScaleWindow, which creates a window with a RowColumn widget containing three Scale widgets. Because ScaleWindow is derived from VkSimpleWindow, it does not support a menu bar. If you required a menu bar, you would instead derive this class from VkWindow.


Note: ScaleWindow includes default resources for the Scale widget labels. This encapsulation technique is a good object-oriented practice to follow when creating reusable components in ViewKit ObjectPak. For example, if you were to extend this class by adding callback functions to the Scale widgets, you should make the callback functions members of the ScaleWindow class.


Example 17. Creating a Window Interface in the Class Constructor

Code

///////////////////////////
// ScaleWindow.h
///////////////////////////
#include <Vk/VkSimpleWindow.h>
class ScaleWindow: public VkSimpleWindow {
public:
ScaleWindow (const char *);
~ScaleWindow();
virtual const char* className();
private:
static String _defaultResources[];
};
///////////////////////////
// ScaleWindow.C
///////////////////////////
#include "ScaleWindow.h"
#include <Xm/RowColumn.h>
#include <Xm/Scale.h>
String ScaleWindow::_defaultResources[] = {
"*dayScale.titleString: Days",
"*weekScale.titleString: Weeks",
"*monthScale.titleString: Months",
NULL };
ScaleWindow::ScaleWindow (const char *name) : VkSimpleWindow (name)
{
setDefaultResources(mainWindowWidget(), _defaultResources);
Widget scales = XtCreateWidget("scales", xmRowColumnWidgetClass,
mainWindowWidget(), NULL, 0);
Widget dayScale = XtCreateManagedWidget("dayScale", xmScaleWidgetClass,
scales, NULL, 0);
XtVaSetValues(dayScale,
XmNorientation, XmHORIZONTAL,
XmNminimum, 1,
XmNmaximum, 7,
XmNvalue, 1,
XmNshowValue, TRUE,
NULL);
Widget weekScale = XtCreateManagedWidget("weekScale", xmScaleWidgetClass,
scales, NULL, 0);
XtVaSetValues(weekScale,
XmNorientation, XmHORIZONTAL,
XmNminimum, 1,
XmNmaximum, 52,
XmNvalue, 1,
XmNshowValue, TRUE,
NULL);
Widget monthScale = XtCreateManagedWidget("monthScale", xmScaleWidgetClass,
scales, NULL, 0);
XtVaSetValues(monthScale,
XmNorientation, XmHORIZONTAL,
XmNminimum, 1,
XmNmaximum, 12,
XmNvalue, 1,
XmNshowValue, TRUE,
NULL);
addView(scales);
}
ScaleWindow::~ScaleWindow()
{
// Empty
}
const char* ScaleWindow::className()
{
return "ScaleWindow";
}
///////////////////////////
// scaleApp.C
///////////////////////////
#include "ScaleWindow.h"
#include <Vk/VkApp.h>
void main ( int argc, char **argv )
{
VkApp *scaleApp = new VkApp("ScaleApp", &argc, argv);
ScaleWindow *scaleWin = new ScaleWindow("scaleWin");
scaleWin->show();
scaleApp->run();
}

Running the scaleApp program, as illustrated in this example, displays a ScaleWindow, shown in Figure 12.

Figure 12. A Simple Example of a VkSimpleWindow Subclass

You can also create components and add them just as you would widgets. The constructor shown in Example 18. creates a VkRadioBox(3) component and installs several items.

Example 18. Using a Component as a Window's View

Code

///////////////////////////
// RadioWindow.h
///////////////////////////
#include <Vk/VkSimpleWindow.h>
class RadioWindow: public VkSimpleWindow {
public:
RadioWindow (const char *);
~RadioWindow();
virtual const char* className();
private:
static String _defaultResources[];
};
///////////////////////////
// RadioWindow.C
///////////////////////////
#include "RadioWindow.h"
#include <Vk/VkRadioBox.h>
String RadioWindow::_defaultResources[] = {
"*color*label*labelString: Color",
"*red.labelString: Red",
"*green.labelString: Green",
"*blue.labelString: Blue",
NULL };
RadioWindow::RadioWindow (const char *name) : VkSimpleWindow (name)
{
setDefaultResources(mainWindowWidget(), _defaultResources);
VkRadioBox *rb = new VkRadioBox( "color", mainWindowWidget() );
rb->addItem("red");
rb->addItem("green");
rb->addItem("blue");
addView(rb);
}
RadioWindow::~RadioWindow()
{
// Empty
}
const char* RadioWindow::className()
{
return "RadioWindow";
}
///////////////////////////
// radioApp.C
///////////////////////////
#include <Vk/VkApp.h>
#include "RadioWindow.h"
void main ( int argc, char **argv )
{
VkApp *radioApp = new VkApp("RadioApp", &argc, argv);
RadioWindow *radioWin = new RadioWindow("radioWin");
radioWin->show();
radioApp->run();
}

Running the radioApp program, as illustrated in this example, displays a RadioWindow shown in Figure 13.

Figure 13. Using a Component as a Window's View

Creating a Window Interface in the setUpInterface() Function

When you create your window interface in your window constructor using addView(), all setup overhead occurs when the window is instantiated. Additionally, your program allocates memory for all of the widgets created. Occasionally, you might need to instantiate a window so that your application can access some of its public functions, but not display it. If the window interface is large or complex, the time and memory consumed to create the interface is unnecessary if the user might not display it.

The ViewKit ObjectPak window classes provide a mechanism for delaying the creation of a window's interface until the window needs to be displayed. Rather than including the interface code in the window constructor, you can include the code in the definition of the protected virtual member function setUpInterface().

When you call show() to display a window, show() checks to see whether you have already added a view to the window (for example, in the window's constructor). If not, show() calls setUpInterface() to create the window's interface.

Using this approach, you do not allocate memory for the window interface until your application actually displays the window for the first time--and you never allocate the memory if your application never displays the window. Additionally, this approach reduces your application's startup time. The trade-off is that the first time you display this window, the response time might be slow because your application must create the interface before displaying the window.

The syntax of setUpInterface() is:

virtual Widget setUpInterface(Widget parent)

show() passes the main window widget to setUpInterface() for you to use as the parent of the window's widget hierarchy. You must return a widget to be added as a view. Do not call addView() from within setUpInterface().


Note: Some OSF/Motif functions such as XmCreateScrolledText(3) create a ScrolledWindow widget and a child widget, and then return the ID of the child widget. As a convenience for using these functions, setUpInterface() can automatically determine the correct parent widget if you provide the child widget ID instead of the ScrolledWindow ID.


Example 19. shows the RadioWindow example from Example 18. rewritten to use setUpInterface() instead of addView() in the constructor.

Example 19. Creating a Window's Interface in setUpInterface() Function

Code

///////////////////////////
// RadioWindow2.h
///////////////////////////
#include <Vk/VkSimpleWindow.h>
class RadioWindow: public VkSimpleWindow {
public:
RadioWindow (const char *);
~RadioWindow();
virtual const char* className();
protected:
Widget setUpInterface(Widget);
private:
static String _defaultResources[];
};
///////////////////////////
// RadioWindow2.C
///////////////////////////
#include "RadioWindow2.h"
#include <Vk/VkRadioBox.h>
String RadioWindow::_defaultResources[] = {
"*color*label*labelString: Color",
"*red.labelString: Red",
"*green.labelString: Green",
"*blue.labelString: Blue",
NULL };
RadioWindow::RadioWindow (const char *name) : VkSimpleWindow (name)
{
// Empty
}
RadioWindow::~RadioWindow()
{
// Empty
}
const char* RadioWindow::className()
{
return "RadioWindow";
}
Widget RadioWindow::setUpInterface (Widget parent)
{
setDefaultResources(mainWindowWidget(), _defaultResources);
VkRadioBox *rb = new VkRadioBox( "color", parent );
rb->addItem("red");
rb->addItem("green");
rb->addItem("blue");
return(*rb);
}

Note: This example uses the Widget operator defined by VkComponent to return the VkRadioBox's base widget in setUpInterface(). (See "VkComponent Access Functions" on page 18 for information on the Widget operator.)


If you prefer, you can explicitly call baseWidget():

return( rb->baseWidget() );

Adding a Window Interface to a Direct Instantiation of a ViewKit ObjectPak Window Class

There are exceptional cases for which you may choose to directly instantiate a VkSimpleWindow or VkWindow object and use addView() to associate a view with the window. For example, if you have a complex, self-contained component and need a window simply to display the component, you might find this method acceptable. Example 20. shows a simple example of adding a component to a direct instantation of the VkSimpleWindow class.

Example 20. Adding a View to a Direct Instantiation of a Window Class

Code

VkSimpleWindow *roloWindow = VkSimpleWindow("roloWindow");
Rolodex *rolodex = Rolodex( "rolodex", roloWindow->mainWindowWidget() );
roloWindow->addView(rolodex);

In most cases, you should not use this technique because most windows require data and support functions that should be encapsulated by the window class to follow proper object-oriented programming style.

Replacing a Window's View

Occasionally, you might want to replace the view of an existing window. To do so, you must first remove the current view using the removeView() function:

void removeView()

You should not call this function unless you have previously added a view to this window. removeView() does not destroy the view; if you no longer need the view, you should destroy it.

After removing a view, you can add another view using addView().

Documentation Type: