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.
|
|
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.