The IContainer class supports both the
CUA '91 container control and the Windows container. The Windows CUA container
is a ported version of the OS/2 Presentation Manager container control.
It has the same look-and-feel as the OS/2 Presentation Manager container
control. The Windows container is composed of the list view and tree view
control which are native to the Windows environment.
On all platforms, you can get CUA 91 style
controls using the IContainerControl::pmCompatible option. On NT, you can also get the Win 32
list view control. This style of control is not available on OS/2 or AIX.
The Windows list view control
is the default selection in the Windows environment.
The following figure shows
an example of a container:
Use the IContainerControl class to create an instance of a container object. With this class, you can control, for example, the view of the objects inside the container. The following example shows one way to create a container:
IContainerControl cnrCtl(CNR_RESID, this, this);
Several styles are available for containers that you can use to manage such activities as multiple-selection and automatic positioning.
You can define the styles in the constructor, or you can use member functions to set the style required after you create an instance of the container object. An example of a style statement is highlighted in the following code:
cnrCtl = new IContainerControl (CNR_RESID, this, this); cnrCtl->setExtendedSelection();Refer to the Open Class Library Reference to learn about other styles and related member functions.
The following is an example of an IContainerObject constructor:
IContainerObject ( const IString& string,
const IPointerHandle& iconHandle = 0);
To design your own objects for your applications, create a class that is derived from the IContainerObject class. If you use multiple inheritance, you must list the IContainerObject class first. To create a container object with department names, addresses, and zip codes for your company, define this class as follows:
class Department : public IContainerObject
{
public:
Department(const IString& Name,
const IPointerHandle& Icon,
const IString& Code,
const IString& Address);
IString Code()
const { return strCode; }
IString Address()
const { return strAddress; }
void setCode (IString code)
{strCode = code;}
void setAddress (IString address)
{strAddress = address;}
virtual void handleOpen
(IContainerControl* container);
private:
IString strAddress;
IString strCode;
};
The statements for a constructor definition
are as follows:
Department :: Department(const IString& Name,
const IPointerHandle& Icon,
const IString& Code,
const IString& Address):
IContainerObject(Name, Icon),
strCode (Code),
strAddress (Address),
{}
After you define the class, create an instance
of an object using either of the following statement:
dept1 = new Department (
"OS2 Development",
IApplication::current().userResourceLibrary().loadIcon(IBMLOGO),
"TWPD",
"Building 71");
dept2=new Department(reslib.loadString(STR_ITEM_21),
reslib.loadIcon(CLOGO),
reslib.loadString(STR_ITEM_22),
reslib.loadString(STR_ITEM_23));
The following statements add objects to the container, cnrCtl. The first line adds an object, dept1. The next three lines add dept2, dept3, and dept4 in a hierarchy under dept1. The last two lines add dept5 and dept6.
cnrCtl->addObject(dept1); // Add Department 1 to container cnrCtl->addObject(dept2,dept1); // Add Department 2 under Department 1 cnrCtl->addObject(dept3,dept1); // Add Department 3 under Department 1 cnrCtl->addObject(dept4,dept1); // Add Department 4 under Department 1 cnrCtl->addObject(dept5); // Add Department 5 to container cnrCtl->addObject(dept6); // Add Department 6 to container
When you place the container in the client window and show the window and the container, you see a window like the one below.
Example
of a Container Showing Objects in an Expanded Tree View
The window shows a tree view of the container's objects. This view is discussed later.
Note that in these figures we show both
the PM compatible version and the Windows native container.
You can also use the ICnrAllocator class to allocate a list of container items to be inserted into an IContainerControl. When you construct instances of this class, you can allocate memory from the container control for a specified number of objects with one call.
The IContainerControl::addObjects member function inserts all the initialized items of the allocator.
The following example shows how to use the ICnrAllocator class and the IContainerControl::addObjects member function:
/**********************************************/
/* Define your derived IContainerObject class */
/**********************************************/
class MyObject : public IContainerObject
{
public:
MyObject(const IString& name) : IContainerObject(name) {}
~MyObject() {}
};
/**********************************/
/* Create a frame and a container */
/**********************************/
IFrameWindow frame(0x1300);
IContainerControl cnr(0x1400, &frame, &frame);
cnrCtl.showTextView();
/**************************************************/
/* Create an allocator and allocate 10000 objects */
/**************************************************/
ICnrAllocator allocator(10000, sizeof(MyObject));
/************************/
/* Initialize all 10000 */
/************************/
for(int i=0; i<10000; i++)
{
new(allocator) MyObject("Peter");
}
/****************************************/
/* Add all the objects to the container */
/****************************************/
cnrCtl.addObjects(allocator);
By default, the container only removes objects when the container is deleted. It does not delete them. However, you can delete all objects in the container when the container is deleted by using the following code statement:
cnrCtl->setDeleteObjectsOnClose();You can call IContainerControl::deleteAllObjects to delete all objects in a container. Specify the style IContainerControl::noSharedObjects when you create a container that does not share any objects with other containers. This increases the performance of the IContainerControl::deleteAllObjects member function.
The following example shows how to create a container with the noSharedObjects style:
/*****************************************************/
/* Create a container with the noSharedObjects style */
/*****************************************************/
IContainerControl* cnrCtl = new IContainerControl(0x1400, &frame,
&frame, IRectangle(0,0,0,0),
IContainerControl::defaultStyle() |
IContainerControl::noSharedObjects);
You can also create objects and place them in multiple containers. The same object is then shared by two or more different containers.
In our example, dept2, dept3, and dept4 are in a hierarchy under dept1. We now want to create another container with only the main departments. This new container will then share dept1, dept5, and dept6 with the other container.
The following statements add three objects to a container, cnrCtl2, that already exists in another container, cnrCtl:
/*************************************************/ /* Container with all departments */ /*************************************************/ cnrCtl->addObject(dept1); // Add Department 1 to container cnrCtl->addObject(dept2,dept1); // Add Department 2 under Department 1 cnrCtl->addObject(dept3,dept1); // Add Department 3 under Department 1 cnrCtl->addObject(dept4,dept1); // Add Department 4 under Department 1 cnrCtl->addObject(dept5); // Add Department 5 to container cnrCtl->addObject(dept6); // Add Department 6 to container /*************************************************/ /* Container with main departments only */ /*************************************************/ cnrCtl2->addObject(dept1); // Add Department 1 to second container cnrCtl2->addObject(dept5); // Add Department 5 to second container cnrCtl2->addObject(dept6); // Add Department 6 to second container
Since the same object can exist in more than one container, the attributes of an object also reflect the state of that object. For example, an object can be visible in one container but hidden in another. You should consider the state of an object's attribute in each container and the state of the attribute in each place the object resides.
The following container attributes can be modified:
For example, for both containers to reflect the same selection emphasis, you must attach an ICnrHandler to keep the objects in the same state in each container. Once both icons are selected, the same action is performed on both containers.
If you are performing multiple actions that cause the container to refresh, you can manipulate the refresh state so that the container will not repaint, as follows:
cnrCntl.setRefreshOff(); : : cnrCntl.setRefreshOn(); cnrCntl.refresh();
You can filter objects in a container when using the CUA container control. The container uses the FilterFn nested class to show a subset of the existing objects by filtering some of the objects.
The native Windows list view and tree
view controls do not support
filtering container objects.
To create a filter, do the following:
class SelectedObjectsFilter : public IContainerControl::FilterFn
{
virtual bool
isMemberOf( IContainerObject* object,
IContainerControl* container) const
{
return container->isSelected(object);
}
};
If true is returned by the FilterFn derived class, the container object remains displayed in the container; if false, the object is hidden.
The isSelected member function returns true if the object has selection emphasis.
SelectedObjectsFilter selObjects; cnrCtl->filter(selObjects);
Before Filtering the Container Objects:

After Filtering the Container Objects:

To provide your own sort behavior, do the following:
The following example sorts the objects in our container by two different criteria:
case ID_SORT1:
{
/*-----------------------------------------------------------------------------
| Sort the container based on the Icon Text. |
| We call a container function to do this. |
----------------------------------------------------------------------------*/
pcnr->sortByIconText ( true );
break;
}
case ID_SORT2:
{
/*-----------------------------------------------------------------------------
| Sort the container based on the Code Text. |
| We must create an instance of the SortByCode class and pass this in. |
----------------------------------------------------------------------------*/
SortByCode sortByCode;
pcnr->sort( sortByCode );
break;
}
To view the entire sample, see the acnr.cpp
file in the samples directory.The following example creates an ObjectCursor and uses it to select all container objects:
IContainerControl::ObjectCursor CO1 (*cnrCtl);
for (CO1.setToFirst(); CO1.isValid(); CO1.setToNext())
{
cnrCtl->setSelected(cnrCtl->objectAt(CO1));
}
The following figure shows the before and after result of setting the selection emphasis using an object cursor.


cnrCtl->showIconView();This statement provides the container view shown below:

The following statement provides the tree icon view:
cnrCtl->showTreeIconView();The following figure shows a container with the tree icon view:

One way to create an instance of an IContainerColumn is for you to provide the offset of the object data to be displayed in the column and, optionally, the styles to be used for the heading and data.
IContainerColumn ( unsigned long dataOffset,
const HeadingStyle& title = defaultHeadingStyle(),
const DataStyle& data = defaultDataStyle());
ANSI C++ allows use of the offsetof macro only for structures and not classes.
Use the following
macro if your compiler raises an error for offsetof:
ICONTAINERCOLUMN_OFFSETOF
To create an instance of a container column, use the following statements:
colIcon = new IContainerColumn (IContainerColumn::isIcon); colName = new IContainerColumn (IContainerColumn::isIconViewText); colCode = new IContainerColumn (ICONTAINERCOLUMN_OFFSETOF(Department, strCode)); colAddress = new IContainerColumn (ICONTAINERCOLUMN_OFFSETOF(Department, strAddress));
In the previous example, colIcon, colName, colCode, and colAddress are defined as members of an IFrameWindow. The statements look like this:
private: //Define private information IContainerControl * cnrCtl; Department *dept1, *dept2, *dept3, *dept4, *dept5, *dept6 ; IContainerColumn *colIcon, *colName, *colCode, *colAddress; IMenuBar * menuBar;
After creating the container columns, you can add heading text to them using the following statements:
colIcon->setHeadingText("Icon");
colName->setHeadingText("Department Name");
colCode->setHeadingText("Code");
colAddress->setHeadingText("Address");
When using the CUA container you can use
showSeparators to add a vertical separator next to a column or a horizontal
separator under the heading text. The default adds both. To create only
one of the separators, specify it in the member function statement. The
following statements show examples of how to create separators:
//Only Horizontal Separator colIcon->showSeparators(IContainerColumn::horizontalSeparator); //Only Vertical Separator colName->showSeparators(IContainerColumn::verticalSeparator); colCode->showSeparators(); //both separator by default colAddress->showSeparators(); //both separator by default
After you create the container columns, add them into the container using the following statements:
cnrCtl->addColumn(colIcon); cnrCtl->addColumn(colName); cnrCtl->addColumn(colCode); cnrCtl->addColumn(colAddress);
The following shows an example of a details view of a container:
When using the CUA container control,
you can use the following code statement to put a split bar in the details
view by specifying the last column to be viewed in the left window and
the location of the split bar in pixels.
cnrCtl->setDetailsViewSplit(colName, 350);
Separators and split bars are ignored
in the native Windows list view and tree view containers. These options
are supported by the CUA control on both the Windows and OS/2 operating
systems. The native control, however, provides dynamic sizing of all columns.
class ACnrMenuHandler: public ICnrMenuHandler
{
public:
/*------------------------ Constructors/Destructor ----------------------------
| Construct the object in only one way: |
| 1) Parameter for IContainerControl |
-----------------------------------------------------------------------------*/
ACnrMenuHandler( IContainerControl* cnr ) { pcnr = cnr; };
protected:
virtual bool
makePopUpMenu( IMenuEvent& event );
private:
IContainerControl
*pcnr;
};
After overriding the makePopUpMenu member function, you can add your own statements. The following statements in acnr.cpp create a pop-up menu displayed next to a container object with source emphasis:
bool ACnrMenuHandler::makePopUpMenu( IMenuEvent& event )
{
/*-----------------------------------------------------------------------------
| If a valid container object, continue |
----------------------------------------------------------------------------*/
if ( popupMenuObject() )
{
/*-----------------------------------------------------------------------------
| Create a popup menu |
| If not in details view, disable editing of Name, Code, and Address columsn. |
----------------------------------------------------------------------------*/
IPopUpMenu* popUp = new IPopUpMenu( ID_POPMENU,
event.window() );
if ( !pcnr->isDetailsView() )
{
popUp->disableItem( MI_EDNAME );
popUp->disableItem( MI_EDCODE );
popUp->disableItem( MI_EDADDRESS );
}
else
{
/*-----------------------------------------------------------------------------
| Disable editing of the object |
----------------------------------------------------------------------------*/
popUp->disableItem( MI_EDRECORD );
}
/*-----------------------------------------------------------------------------
| To avoid memory leaks, auto delete the C++ popup menu when the GUI popup |
| window closes |
| Show the popup menu at the current mouse position |
| Visually indicate the container object is the source for this action |
| Visually indicate the container object is the current cursor |
----------------------------------------------------------------------------*/
popUp->setAutoDeleteObject();
pcnr->showSourceEmphasis( popupMenuObject() );
pcnr->setCursor( popupMenuObject() );
popUp->show( event.mousePosition() );
return true;
}
return false;
};
The following figure shows the pop-up menu in a container object:
This section lists the differences between
the native Windows container control and the PM compatible CUA '91 control.
For specific platform information on each member function, refer to the
Open Class Library Reference
The default IContainerControl wrappers the Windows native ListView and TreeView controls. The underlying controls are created when needed. If you create an IContainerControl in the default icon view, only a ListView control is created. A TreeView control is not created until the view is switched to a tree view or a child object is added. To optimize a tree view container, consider the following:
Constructors
For the native Windows control, you cannot use the following constructors:
IContainerControl ( unsigned long id,
IWindow* parentDialog);
IContainerControl ( const IWindowHandle& handle);
Member Functions
Source emphasis is not supported. This is true of both the Windows CUA control and the native Windows control.
There is no windows native multiple selection. IContainerControl::multipleSelection is the same as extendedSelection and IContainerControl::verifyPointers is ignored.
The following IContainerControl attributes are ignored:
Note: The native ListView control requires the first column in a details view to be the icon and text pair that is displayed in the other views. This column is sized to nonzero if either a IContainerColumn with
objectDataType=isIconor
objectDataType=isIconViewTextis added. Regardless of where they are added, these columns are displayed as the first column. If neither is added, the column size is set to zero but it is possible for the user to size this column using the mouse.
This is the only icon that may be displayed in the details view. If you add any other columns to display icons, the icons are not be visible.
The native control allows selection only in this first column. If this column is sized to zero, objects in the container cannot be selected.
Using Default Direct Manipulation
Task and Samples Cross-Reference Table
ICnrHandler
IContainerColumn
IContainerControl
IContainerObject