[ Next ] [ Previous ] | Chapter 23 |
View Type |
Contents Displayed | Sample |
Icon view |
Displays either icons or bit maps, with text beneath the
icons or bit maps, to represent container items. These are called icon/text or bit-map/text pairs. Each icon/text or bit-map/text pair represents one container item. This is the default view |
|
Name view |
Displays either icons or bit maps, with text to the right of
the icons or bit maps, to represent container items. These are called
icon/text or bit-map/text pairs. Each icon/text or bit-map/text pair
represents one container item. |
|
Text view |
Displays a simple text list to represent container items. |
|
Tree view |
Displays a hierarchical view of the container items. Three
types of Tree views are available: Tree text, Tree icon, and Tree name.
|
|
Details view |
Displays detailed information about each container item. The
same type of data is displayed for each container item, arranged in
columns. The data in each column can consist of an icon or bit
map, text, numbers, dates, or time |
Style |
Description |
CCS_EXTENDSEL | Specifies that the extended selection model is to be used
according to the CUA'91 guidelines. |
CCS_MULTIPLESEL |
Specifies that one or more items can be selected at any time. |
CCS_SINGLESEL |
Specifies that only a single item may be selected at any time. This is the default. |
CCS_AUTOPOSITION |
Specifies that the container should position items automatically when one of a specific set of events occurs. This is valid for icon view only. |
CCS_VERIFYPOINTERS |
Specifies that the container should verify that all pointers used belong to the object list. It does not validate the accessibility pf the pointers. This should be used only during debugging, since it affects the performance of the container. |
CCS_READONLY |
Specifies that no text should be editable |
CCS_MINIRECORDCORE |
Specifies that the object records are of the type MINIRECORDCORE (instead of RECORDCORE) |
CCS_MINIICONS |
Style to have container support mini icons with
the minirecord |
CCS_NOCONTROLPTR |
don't send WM_CONTROLPOINTER on WM_MOUSEMOVE |
typedef struct _ITEMINFOProgrammers always should be sure to specify the style bit that corresponds to the type of object record they decide to use.
{ MINIRECORDCORE mrcRecord;
CHAR achItem[256];
ULONG lUnitsSold;
float fRevenue;
} ITEMNFO,*PITEMINFO;
typedef struct _RECORDINSERTcb is the size of the structure in bytes. pRecordOrder specifies the record after which the record(s) are to be inserted. CMA_FIRST or CMA_END also can be specified to indicate that the record(s) should go at the front or end of the record list. pRecordParent specifies the parent record and can be NULL to indicate a top-level record. This field is valid only for tree view. fInvalidateRecord is TRUE if the records are to be invalidated (and thus redrawn) after being inserted. zOrder specifies the Z-order of the record and can be either CMA_TOP or CNA_BOTTOM to specify the top and bottom of the Z-order. cRecordsInsert specifies the number of records that are being inserted
{
ULONG cb;
PRECORDCORE pRecordOrder;
PRECORDCORE pRecordParent;
ULONG fInvalidateRecord;
ULONG zOrder;
ULONG cRecordsInsert;
} RECORDINSERT;
typedef RECORDINSERT *PRECORDINSERT;
/**********************************************************************/
/* CNRINFO data structure, describes the container control. */
/**********************************************************************/
typedef struct _CNRINFO /* ccinfo */
{ ULONG cb; /* size of CNRINFO struct */
PVOID pSortRecord; /* ptr to sort function, */
/* RECORDCORE */
PFIELDINFO pFieldInfoLast; /* pointer to last column in left pane of a split window. */
PFIELDINFO pFieldInfoObject; /* Pointer to a column to represent an object. This is */
/* the column which will receive IN-USE emphasis. */
PSZ pszCnrTitle; /* text for container title. One string separated by line */
/* separators for multi-lines */
ULONG flWindowAttr; /* container attrs - CV_*, CA_* */
POINTL ptlOrigin; /* lower-left origin in virtual coordinates. CV_ICON view */
ULONG cDelta; /* Application defined threshold or number of records from */
/* either end of the list. */
ULONG cRecords; /* number of records in container*/
SIZEL slBitmapOrIcon; /* size of bitmap in pels */
SIZEL slTreeBitmapOrIcon; /* size of tree bitmaps in pels */
HBITMAP hbmExpanded; /* bitmap for tree node */
HBITMAP hbmCollapsed; /* bitmap for tree node */
HPOINTER hptrExpanded; /* icon for tree node */
HPOINTER hptrCollapsed; /* icon for tree node */
LONG cyLineSpacing; /* space between two rows */
LONG cxTreeIndent; /* indent for children */
LONG cxTreeLine; /* thickness of the Tree Line */
ULONG cFields; /* number of fields in container*/
LONG xVertSplitbar; /* position relative to the container (CV_DETAIL); */
/* if 0xFFFF then unsplit */
} CNRINFO;
typedef CNRINFO *PCNRINFO;
CNRINFO structure contains a large number of fields. Note that
not every one of them needs to be initialized. Instead, only the needed
fields are initialized; fields which were initialized are cited as a
combination of flags specified in the second parameter of the
CM_SETCNRINFO message. To change the vie to icon view, for example:
CNRINFO ciInfo;
ciInfo.cb = sizeof(CNRINFO);
ciInfo.flWindowAttr = CV_ICON;
WinSendMsg(pcdData->hwndCnr,
CM_SETCNRINFO,
MPFROMP(&ciInfo),
MPFROMLONG(CMA_FLWINDOWATTR));
Since we're talking about views of an object, let's look at the
various combinations of view flags to specify the different view types.
Table 23.2 provides a list of view flags.
Constant |
Description |
CV_TEXT | Specifies that the text alone should be displayed. This can be combined with CV_FLOW flag. |
CV_NAME | Specifies that the icon should be displayed with the text to the right. This can be combined with CV_FLOW flag. |
CV_ICON | Specifies that the icon or bitmap should be displayed with
the text below it. |
CV_DETAIL | The details view shows data in a columnar format. This is
discussed in more detail in Details View. |
CV_FLOW | Specifies that, ones a column is filled, the list should continue in an adjacent column. |
CV_MINI | use mini icon |
CV_TREE |
Used for records that have
children. Three view types can be used with the tree view (See Tree
View) The three view shows a hierarchical view of the data |
CV_GRID | gridded icon view |
CV_EXACTLENGTH | Exact match for SearchString |
CONTAIN1.C CONTAIN1.RC CONTAIN1.H CONTAIN1.MAK CONTAIN1.DEF |
Icon View |
Name/flowed View |
Text/flowed view
|
psiYears = (PSALESINFO)PVOIDFROMMR(Then the allocated records are initialized by calling the initSales function; after each record is initialized it is inserted using the riRecord structure that was initialized earlier.
WinSendMsg(pcdData->hwndCnr,
CM_ALLOCRECORD,
MPFROMLONG(ulExtra),
MPFROMSHORT(MAX_YEARS) ) );
psiCYear = psiYears;
for (usIndex = 0; usIndex < MAX_YEARS; usIndex++)
{ initSalesInfo(pcdData, psiCYear, usIndex);
riRecord.pRecordParent = NULL;
riRecord.cRecordsInsert = 1;
WinSendMsg(pcdData->hwndCnr,
CM_INSERTRECORD,
MPFROMP(psiCYear),
MPFROMP(&riRecord));
psiCYear = (PSALESINFO) psiCYear->mrcStd.preccNextRecord;
} /* endfor */It is true that the the source code should "practice what we preach" in terms of inserting more than one record at a time to increase performance, but simplicity was deemed more important to allow better understanding of the code.
WinSendMsg(hwndClient,The WM_COMMAND code to switch between container view is rather simple as well. For space reasons, here we present only the code or switching to icon view.
WM_COMMAND,
MPFROMSHORT(MI_ICON),
0);
case MI_ICON :
{ CNRINFO ciInfo;
ciInfo.cb = sizeof(CNRINFO);
ciInfo.flWindowAttr = CV_ICON;
WinSendMsg(pcdData->hwndCnr,
CM_SETCNRINFO,
MPFROMP(&ciInfo),
MPFROMLONG(CMA_FLWINDOWATTR));
WinSendMsg(pcdData->hwndCnr,
CM_ARRANGE,
NULL,
NULL);
}
break;
View | Description |
Tree icon view |
Objects in the tree are represented by icons or bitmaps with
the text to the right. If an item is expandable, a separate bitmap as
drawn to the left of the object. This view is specified by adding
CV_ICON and CV_TREE flags to the flWindowAttr
field. |
Tree name view |
This is the same as the tree icon view except that an object's expandability is shown on the icon or bitmap of the object, and not as a separate bitmap; the TREEITEMDESC structure contains the bitmap or icon handles for both expanded and collapsed views. The caveat here is that the TREEITEMDESC structure is pointed to by the RECORDCORE structure but not by the MINIRECORDCORE structure. This view is specified by adding the CV_NAME and CV_TREE flags to the flWindowAttr field. |
Tree text view |
Objects in the tree are represented by text only. The
feedback on the expandability of an object is represented by a separate
bitmap to the left of the text. This view is specified by adding the
CV_TEXT and CV_TREE flags to the flWindowAttr
field. |
typedef struct _FIELDINFO /* fldinfo */cb specifies the size of the structure in bytes. flData specifies the type of the data in this field and any associated attributes of the column via one ore more CFA_ constants listed in table 23.4
{ ULONG cb; /* size of FIELDINFO struct */
ULONG flData; /* attributes of field's data */
ULONG flTitle; /* attributes of field's title */
PVOID pTitleData; /* title data (default is string). If CFT_BITMAP, must be HBITMAP */
ULONG offStruct; /* offset from RECORDCORE to data */
PVOID pUserData; /* pointer to user data */
struct _FIELDINFO *pNextFieldInfo; /* pointer to next linked FIELDINFO structure */
ULONG cxWidth; /* width of field in pels */
} FIELDINFO;
Constant | Description |
CFA_LEFT |
Specifies that the data is to be horizontally aligned left. |
CFA_RIGHT |
Specifies that the data is to be horizontally aligned right. |
CFA_CENTER |
Specifies that the data is to be horizontally centered. |
CFA_TOP |
Specifies that the data is to be vertically aligned top. |
CFA_VCENTER |
Specifies that the data is to be vertically centered. |
CFA_BOTTOM |
Specifies that the data is to be vertically aligned bottom. |
CFA_INVISIBLE |
Specifies that the column is not to be shown |
CFA_BITMAPORICON |
Specifies that offStruct points to a bitmap or icon
handle to be displayed in the column, depending on the current setting
of flWindowAttr in the CNRINFO
structure last used to set the container attributes. |
CFA_SEPARATOR |
Specifies that there should be
a vertical separator to the right of the column. |
CFA_HORZSEPARATOR |
(flTitle
only)Specifies that the column title should have a horizontal separator
dividing it from the data. |
CFA_STRING |
Specifies that offStruct points to a pointer to a
string to be displayed in the column. |
CFA_OWNER |
Specifies that the column is to
be owner-drawn. |
CFA_DATE |
Specifies that offStruct points to a CDATE structure. |
CFA_TIME |
Specifies that offStruct points to a CTIME structure. |
CFA_FIREADONLY |
Specifies that the column data
should be read-only |
CFA_FITITLEREADONLY |
(flTitle
only)Specifies that the column should be read-only |
CFA_ULONG |
Specifies that offStruct points to a ULONG |
CFA_RANGE |
??? |
CFA_NEWCOMP |
(CLASSFIELDINFO in
wpobject.h ) Tells the system to use strings specified in pNewComp |
CFA_OBJECT |
(CLASSFIELDINFO in
wpobject.h ) Tells the system that the applications wants to use its own comparison function in which the first parameter is a pointer to an object. For example: LONG MyComp(WPObject *obj, PSZ str2) |
CFA_LIST |
??? |
CFA_CLASS |
??? |
CFA_IGNORE |
??? |
Gotcha! If flData specifies CFA_STRING, then offStruct specifies the offset of the pointer to the text and not the text itself |
Gotcha! The column heading data is not copied into the container's workspace. Thus they must be global, static, or dynamically allocated data. |
Gotcha! A common mistake when specifying CFA_DATE or CFA_TIME for a column is to improperly convert an FDATE structure to a CDATE structure and FTIME structure to a CTIME structure. |
CONTAIN2.C CONTAIN2.RC CONTAIN2.H CONTAIN2.MAK CONTAIN2.DEF |
Detail View |
Tree View |
As before, we allocate a number of records using the CM_ALLOCRECORD
structure; withing the loop to initialize each record (which represents
a year of sales figures), we allocate 12 records to represent each
month initialize these records, and insert them into the container,
specifying the year record previously inserted as the parent. This
establishes a hierarchical structure that we may observe by placing the
container in tree view.
psiMonths = (PSALESINFO)PVOIDFROMMR(
WinSendMsg(pcdData->hwndCnr,
CM_ALLOCRECORD,
MPFROMLONG(ulExtra),
MPFROMSHORT(MAX_MONTHS)));
psiCMonth = psiMonths;
for (usIndex2 = 0; usIndex2 < MAX_MONTHS; usIndex2++)
{ initSalesInfo(pcdData,
psiCYear,
psiCMonth,
usIndex2);
psiCMonth = (PSALESINFO)
psiCMonth->mrcStd.preccNextRecord;
} /* endfor */
riRecord.pRecordParent = (PRECORDCORE)psiCYear;Finally, we call initColumns to set up the datail view. It allocates a fixed number of FIELDINFO structures by sending a CM_ALLOCDETAILFIELDINFO message to the container.
riRecord.cRecordsInsert = MAX_MONTHS;
WinSendMsg(pcdData->hwndCnr,
CM_INSERTRECORD,
MPFROMP(psiMonths),
MPFROMP(&riRecord));
pfiInfo = (PFIELDINFO)PVOIDFROMMR(WinSendMsg(pcdData->hwndCnr,
CM_ALLOCDETAILFIELDINFO,
MPFROMLONG(MAX_COLUMNS),
0));
Each FIELDINFO structure is then initialized, and then all of the
FIELDINFO structures are inserted.pfiCurrent->flData = CFA_BITMAPORICON|CFA_HORZSEPARATOR|CFA_CENTER|CFA_SEPARATOR;
pfiCurrent->flTitle = CFA_STRING|CFA_CENTER;
pfiCurrent->pTitleData = "Icon";
pfiCurrent->offStruct = FIELDOFFSET(SALESINFO,
mrcStd.hptrIcon);
......
fiiInfo.cb = sizeof(fiiInfo);Finally, the splitbar is initialized by sending the CM_SETCNRINFO message.
fiiInfo.pFieldInfoOrder = (PFIELDINFO)CMA_FIRST;
fiiInfo.cFieldInfoInsert = MAX_COLUMNS;
fiiInfo.fInvalidateFieldInfo = TRUE;
WinSendMsg(pcdData->hwndCnr,
CM_INSERTDETAILFIELDINFO,
MPFROMP(pfiInfo),
MPFROMP(&fiiInfo));
memset(&ciInfo, 0, sizeof(ciInfo));
ciInfo.cb = sizeof(CNRINFO);
ciInfo.pFieldInfoLast = pfiLefty;
ciInfo.xVertSplitbar = CX_SPLITBAR;
WinSendMsg(pcdData->hwndCnr,
CM_SETCNRINFO,
MPFROMP(&ciInfo),
MPFROMLONG(CMA_PFIELDINFOLAST|CMA_XVERTSPLITBAR));
Emphasis | Constant | Description |
Cursored |
CRA_CURSORED |
Set whenever the input focus belongs to the object. This is
shown as a dotted-line rectangle around the object. |
Selected |
CRA_SELECTED |
Set whenever the object was selected using the mouse button
on the spacebar. The selection style of the container defines how
records previously selected behave when a new record is selected. This
is shown as an inverted background around the object. |
In-use |
CRA_INUSE |
Set whenever the object is defined to be in use by the application. This is shown as a crosshatch pattern in the background of the object. |
Source |
CRA_SOURCE |
Set whenever the the object is a source of some action This
record also could be in the selected state, but doing so is not
required. This is shown as a dashed-line rectangle with rounded corners
around the object. |
Target |
CRA_TARGET |
Target emphasis is used during
direct manipulation. When a user drags one container item over another,
the item beneath the dragged item displays target emphasis. Two forms
of target emphasis (visible feedback) are available: a black line and a
black border. These forms of emphasis indicate the target, where the
container item is dropped if the user releases the drag button. |
Picked |
CRA_PICKED |
record picked (Lazy Drag) |
CONTAIN3.C CONTAIN3.RC CONTAIN3.H CONTAIN3.MAK CONTAIN3.DEF |
psiSales = (PSALESINFO)PVOIDFROMMP(mpParm2);The records are selected using CM_SETRECORDEMHASIS message; this message sets the appropriate bit in the flRecordAttr field and redraw the record. Conceivably this could be done explicitly, but why go through the extra work ? The method of determining which records are given source emphasis follows that of Workplace Shell, and can be summarized in the following manner:
if (psiSales != NULL)
{
if ((psiSales->mrcStd.flRecordAttr
&CRA_SELECTED) == 0)
{
WinSendMsg(pcdData->hwndCnr,
CM_SETRECORDEMPHASIS,
MPFROMP(psiSales),
MPFROM2SHORT(TRUE, CRA_SOURCE));
psiSales->bEmphasized = TRUE;
} else {
emphasizeRecs(pcdData->hwndCnr, TRUE);
} /* endif */
} else {
WinSendMsg(pcdData->hwndCnr,
CM_SETRECORDEMPHASIS,
0,
MPFROM2SHORT(TRUE, CRA_SOURCE));
pcdData->bCnrSelected = TRUE;
} /* endif */
Gotcha! The documentation does not state how the container is given source emphasis this is done by specifying NULL for the record pointer in mpParm1. The container does not keep track of whether it has source emphasis or not and blindly draws this emphasis using the XOR method. Thus, if two CM_SETRECORDEMPHASIS messages are sent, both specifying that source emphasis is to be removed from the container, no visible difference will be seen. |
WinQueryPointerPos(HWND_DESKTOP, &ptlMouse);
WinMapWindowPoints(HWND_DESKTOP,
hwndClient,
&ptlMouse,
1);
WinPopupMenu(hwndClient,
hwndClient,
pcdData->hwndMenu,
ptlMouse.x,
ptlMouse.y,
M_VIEWS,
PU_HCONSTRAIN | PU_VCONSTRAIN |
PU_KEYBOARD | PU_MOUSEBUTTON1 |
PU_MOUSEBUTTON2| PU_NONE);
typedef struct _CNREDITDATA /* cnredat */cb is the size of the structure in bytes. hwndCnr is the handle of the container window. pRecord is a pointer to the RECORDCORE structure of the object being edited. If the container titles are being edited, this field is NULL. pFieldInfo is a pointer to the FIELDINFO structure if the current view is detail view and the column titles are not being edited. Otherwise, this field is NULL. ppszText points to the pointer to the current text if the notification code is CN_BEGINEDIT or CN_REALLOCPSZ. For CN_ENDEDIT notification, this points to the pointer to the new text. cbText specifies the number of bytes in the text. id is the identifier of the window being edited and is a CID_ constant.
{ ULONG cb;
HWND hwndCnr;
PRECORDCORE pRecord;
PFIELDINFO pFieldInfo;
PSZ *ppszText; /* address of PSZ */
ULONG cbText; /* size of the new text */
ULONG id;
} CNREDITDATA;
Gotcha! The application must return TRUE from CN_REALLOCPSZ notifications, or else the container will discard the editing changes. |
SHORT EXPENTRY pfnCompare(PRECORDCORE p1,
PRECORDCORE p2,
PVOID pStorage);
BOOL PFN pfnFilter(PRECORDCORE p,Of course, if the container was created with the CCS_MINIRECORDCORE style, the RECORDCORE pointers are instead MINIRECORDCORE pointers.
PVOID pStorage);
case MI_SORTBYUNITS :As was said, this really is simple. The callback function is just as easy to understand.
{ USHORT usId;
usId = MI_SORTBYUNITS;
WinSendMsg(pcdData->hwndCnr,
CM_SORTRECORD,
MPFROMP(sortRecords),
MPFROMP(&usId));
}
break;
SHORT EXPENTRY sortRecords(PSALESINFO psiFirst,
PSALESINFO psiSecond,
PUSHORT pusSortBy)
{
switch (*pusSortBy)
{
case MI_SORTBYUNITS :
if (psiFirst->ulNumUnits < psiSecond->ulNumUnits)
{ return -1;
} elseIt checks to see by what the user requested the items to be sorted and then checks the appropriate field in the SALESINFO structure. That is all there is to sorting; there isn't anything difficult about it.
if (psiFirst->ulNumUnits == psiSecond->ulNumUnits)
{ return 0;
} else {
return 1;
} /* endif */
case MI_SORTBYYEAR :
return strcmp(psiFirst->mrcStd.pszIcon,
psiSecond->mrcStd.pszIcon);
default :
return 0;
} /* endswitch */
}
case MI_FILTER300DOLLARS :This is almost identical to code that initiates the sorting. The callback is simpler than the sorting callback.
{ USHORT usId;
usId = MI_FILTER300DOLLARS;
WinSendMsg(pcdData->hwndCnr,
CM_FILTER,
MPFROMP(filterRecords),
MPFROMP(&usId));
}
break;
BOOL EXPENTRY filterRecords(PSALESINFO psiInfo,PUSHORT pusFilterBy)It checks to see by what criteria the user wanted to filter the records and returns the appropriate value.
{ switch (*pusFilterBy)
{
case MI_FILTER300DOLLARS :
return (psiInfo->fSales > 300.0);
case MI_FILTER400DOLLARS :
return (psiInfo->fSales > 400.0);
case MI_FILTER500DOLLARS :
return (psiInfo->fSales > 500.0);
case MI_FILTERNONE :
return TRUE;
default :
return TRUE;
} /* endswitch */
}
Notification |
Explanation |
CN_DRAGAFTER |
Sent to container's owner whenever the container receives a
DM_DRAGOVER message. The CN_DRAGAFTER notification code is sent only if
the CA_ORDEREDTARGETEMPHASIS or CA_MIXEDTARGETEMPHASIS attribute of the
CNRINFO data structure is set and the current view is the name, text,
or details view. |
CN_DRAGLEAVE |
Sent to container's owner when the container receives a
DM_DRAGLEAVE message. |
CN_DRAGOVER |
Sent to container's owner when the container receives a
DM_DRAGOVER message. The CN_DRAGOVER notification code is sent only if
the CA_ORDEREDTARGETEMPH attribute of the CNRINFO data structure is not
set or the current view is the icon view or tree view. |
CN_DROP |
Sent to container's owner when the container receives a DM_DROP message. |
CN_DROPHELP |
Sent to container's owner when the container receives a
DM_DROPHELP message. |
CN_INITDRAG |
Sent to container's owner when the drag button is pressed and the pointer is moved while the pointer is over the container control. |
CN_DROPNOTIFY |
Sent to container's
owner when a pickup set is dropped over the container. |
[ Next ] [ Previous ] | Chapter 23 |