[ Next ] [ Previous ] Chapter 21
[ Contents ] [ Chapter 20: Drag and Drop ] [ Chapter 22: Notebook ]

Value Set

A value set is a control that provides a way for a user to select from several graphically illustrated choices. Only one choice can be selected at a time. A value set can use icons, bitmaps, colors, text, or numbers. However, it is optimal to use only graphical images and/or short text; other controls should be used if a choice of only text or numbers is offered. The value set is designed to show setting choices, not action choices; if an action choice needs to be designated, a push button or menu should be used. A value set must contain at least two items. A value set choice that is unavailable should be disabled; if a value set has text choices, a letter for each choice should be designated as a mnemonic. A value set can be used as a tool palette also; however, the pointer should be changed to represent the current "tool" selected. For instance, if a "paint" tools is selected, the cursor could be changed to represent a paintbrush.
 value set control
Figure 21.1 Example of the value set control.

Value Set Styles

Table 21.1 lists the available value set styles
Table 21.1 Value Set Styles
Style
 Description
VS_BITMAP
Default all value set items to bitmaps.
VS_ICON
Default all value set items to icons.
VS_TEXT
Default all value set items to text strings.
VS_RGB
Default all value set items to color info in RGB values
VS_COLORINDEX
Default all value set items to color info in color indices
VS_BORDER
Add a border around the value set control.
VS_ITEMBORDER
Add a border around each value set item
VS_SCALEBITMAPS
Scale bitmaps to fit in cell size.
VS_RIGHTTOLEFT
Support right to left ordering.
VS_OWNERDRAW
Owner draws value set control.

The following example program shows the creation of a value set control with the style VS_COLORINDEX.

VALUE.C
VALUE.RC
VALUE.H
VALUE.MAK
VALUE.DEF

The VALUE.RC Resource File

The VALUE.RC file contains two items: a menu and a dialog with the value set control. The dialog is created with the following code.
DLGTEMPLATE IDD_VALUE LOADONCALL MOVEABLE DISCARDABLE
{
DIALOG "Color Set", IDD_VALUE, 12, 12, 155, 105, WS_VISIBLE,
FCF_SYSMENU | FCF_TITLEBAR
{
LTEXT "Select color: ", -1, 11, 25, 102, 8
VALUESET IDV_VALUE, 13, 38, 91, 61, VS_COLORINDEX | VS_BORDER
CTLDATA 8, 0, 3, 4
PUSHBUTTON "Cancel", DID_CANCEL, 6, 2, 40, 14
}
}

The sixth parameter in the VALUESET statement is the combination of window and control styles. In this case, we specify VS_COLORINDEX, indicating that the choices of the value set are the indices into the color index table. We also use VS_BORDER, which draws a border around the value set. The last parameter is the CTLDATA statement. In this case, this represents the VSCDATA structure. The VSCDATA structure is defined as:
   typedef struct _VSCDATA     /* vscd */
{
ULONG cbSize; /* Size of control block */
USHORT usRowCount; /* Number of rows in value set */
USHORT usColumnCount; /* Number of columns in value set */
} VSCDATA;
typedef VSCDATA *PVSCDATA;

The CTLDATA key word sees each parameter as a SHORT, so a LONG is represented as two parameters. The first two parameters correspond to the cbSize structure member. They are specified in low-byte, high-byte order. The third parameter represents usRowCount. Our value set will contain three rows. The fourth parameter represents usColumnCount. Our value set will contain four columns.
A structure defined at the top of the program is used for the window word. It is:
	typedef          struct
{
SHORT sColor;
HWND hwndDlg;
} WNDDATA,*PWNDDATA;

In the structure, the first element SHORT sColor represents the currently selected color in the value set. The hwndDlg is the window handle for the dialog box.
Also, the array alColor is declared. This is the array of color index values that are used in the value set.

Initializing the Value Set

      case  WM_INITDLG :
{ SHORT sColor;
USHORT usX;
USHORT usY;
MRESULT mrReply;

sColor = 0;

/***************************************************/
/* loop through the rows and columns to initialize */
/* items */
/***************************************************/
for (usX = 1; usX <= 3; usX++)
{
for (usY = 1; usY <= 4; usY++)
{
mrReply = WinSendDlgItemMsg(hwndDlg,
IDV_VALUE,
VM_SETITEM,
MPFROM2SHORT(usX,
usY),
MPFROMLONG(alColors
[sColor++]));
if (!LONGFROMMR(mrReply))
DisplayError("WinSendDlgItemMsg failed");

} /* endfor */
} /* endfor */
} /* end WM_INITDLG */
break;

The value set initialization is a very simple process of sending a VM_SETITEM for each item in the value set. Because this value set is of style VS_COLORINDEX, mpParm2 will contain a color index constant. We will use the CLR_* values in the alColor array. mpParm1  is a collection of two SHORTS that make up the row and column of the item. Notice that there is no row or column 0; these values start at 1. All value set messages pertaining to a specific value set item are done by using the row and column of the item of interest.
By default, the first item in the value set is selected.

Value Set Select Notification

   /* get row and column of selected item                      */
usRow = SHORT1FROMMP(mpParm2);
usCol = SHORT2FROMMP(mpParm2);

/* calculate index into color array */
sColorIndex = ((usRow-1)*4)+(usCol-1);

/* get the client window handle to post message */
hwndFrame = WinWindowFromID(HWND_DESKTOP,
ID_FRAME);
hwndClient = WinWindowFromID(hwndFrame,
FID_CLIENT);
bSuccess = WinPostMsg(hwndClient,
USRM_UPDATE,
MPFROMSHORT(sColorIndex),
MPVOID);
The WM_CONTROL message is where the value set will indicate when a new color has been selected. We check for the notification code VN_SELECT from WM_CONTROL message. The row number (starting with 1) is sent as the low order byte of mpParam2. The column number is sent as a high order byte of mpParm2. By doing some quick math, the index into the alColor array is determined. The next task is to notify the client window that a new selection has been made. This is done by posting the user-defined message, UM_UPDATE, to the client, with the color index sent in mpParm1.

VALUE Paint Processing

      case  WM_PAINT :
{ HPS hpsPaint;
RECTL rclPaint;
SHORT sColor;
BOOL bPaint = FALSE; /* variable to indicate whether to paint or not */

pwdData = WinQueryWindowPtr(hwndClient,
QWL_USER);

/* paint the entire client with the dropped color */
hpsPaint = WinBeginPaint(hwndClient,
NULLHANDLE,
&rclPaint);
GpiErase(hpsPaint);

/* do some error checking */
if (pwdData)
{ if (pwdData->sColor >= 0)
{
bPaint = TRUE;
sColor = pwdData->sColor;
}
}

if (bPaint)
WinFillRect(hpsPaint,
&rclPaint,
alColors[sColor]);
WinEndPaint(hpsPaint);
}
break;

The WM_PAINT message starts with WinQueryWindowPtr to retrieve the window word of the client window. Next the usual WinBeginPaint is called. GpiErase is used to erase the entire invalidated region. If the sColor variable in the pwdData structure is greater than 0, a color has been selected by the user. Remember, the variable was initially set to -1. A Boolean variable bPaint is used to indicate all is okay, so go ahead and paint. WinFillRect fills the invalidated region with the specified color, and WinEndPaint is called to release the presentation space.

The User-defined Message UM_UPDATE

      case  USRM_UPDATE :
/******************************************************/
/* user message indicates end-user selected new color */
/* in value set, window needs to repaint itself with */
/* new color */
/******************************************************/

pwdData = WinQueryWindowPtr(hwndClient,
QWL_USER);
if (!pwdData)
{
DisplayError("WinQueryWindowPtr failed");
break;
}
pwdData->sColor = SHORT1FROMMP(mpParm1);
WinInvalidateRect(hwndClient,
NULL,
FALSE);
WinUpdateWindow(hwndClient);
break;
The message UM_UPDATE is a user-defined message that is sent from the value set when a new value set item has been selected. This is the signal to the client to repaint itself. The index of the selected item is sent in mpParam1. This value is retrieved and stored in the pwdData structure so it is visible to the WM_PAINT processing. WinInvalidateRect is used to invalidate the entire client window, and WinUpdateWindow message is used to force the update of the client window - in other words, generate a WM_PAINT message and process it, now!
BOOL  APIENTRY WinUpdateWindow(HWND hwnd);

WinUpdateWindow has only one parameter - hwnd, which is the window handle of the window to update.

This potent approach is not always necessary, but the example program depends on a quick user notification of the new value set selection.


[ Next ] [ Previous ] Chapter 21
[ Contents ] [ Chapter 20: Drag and Drop ] [ Chapter 22: Notebook ]