To see some uses of scroll bars and static child windows—and also to explore color in more depth—we'll use the COLORS1 program, shown in Figure 6-3. COLORS1 displays three scroll bars in the left half of the client area labeled ”Red,“ ”Green,“ and ”Blue.“ As you scroll the scroll bars, the right half of the client area changes to the composite color indicated by the mix of the three primary colors. The numeric values of the three primary colors are displayed under the three scroll bars.
COLORS1.MAK
#-----------------------
# COLORS1.MAK make file
#-----------------------
colors1.exe : colors1.obj colors1.def
link colors1, /align:16, NUL, /nod slibcew libw, colors1
rc colors1.exe
colors1.obj : colors1.c
cl -c -Gsw -Ow -W2 -Zp colors1.c
COLORS1.C
/*----------------------------------------
COLORS1.C -- Colors Using Scroll Bars
(c) Charles Petzold, 1990
----------------------------------------*/
#include <windows.h>
#include <stdlib.h>
long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;
long FAR PASCAL ScrollProc (HWND, WORD, WORD, LONG) ;
FARPROC lpfnOldScr[3] ;
HWND hwndScrol[3], hwndLabel[3], hwndValue[3], hwndRect ;
short color[3], nFocus ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
static char szAppName[] = "Colors1" ;
static char *szColorLabel[] = { "Red", "Green", "Blue" } ;
FARPROC lpfnScrollProc ;
HWND hwnd ;
MSG msg ;
short n ;
WNDCLASS wndclass ;
if (hPrevInstance)
return FALSE ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = NULL ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = CreateSolidBrush (0L) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
RegisterClass (&wndclass) ;
hwnd = CreateWindow (szAppName, "Color Scroll",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
hwndRect = CreateWindow ("static", NULL,
WS_CHILD | WS_VISIBLE | SS_WHITERECT,
0, 0, 0, 0,
hwnd, 9, hInstance, NULL) ;
lpfnScrollProc = MakeProcInstance ((FARPROC) ScrollProc, hInstance) ;
for (n = 0 ; n < 3 ; n++)
{
hwndScrol[n] = CreateWindow ("scrollbar", NULL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP | SBS_VERT,
0, 0, 0, 0,
hwnd, n, hInstance, NULL) ;
hwndLabel[n] = CreateWindow ("static", szColorLabel[n],
WS_CHILD | WS_VISIBLE | SS_CENTER,
0, 0, 0, 0,
hwnd, n + 3, hInstance, NULL) ;
hwndValue[n] = CreateWindow ("static", "0",
WS_CHILD | WS_VISIBLE | SS_CENTER,
0, 0, 0, 0,
hwnd, n + 6, hInstance, NULL) ;
lpfnOldScr[n] = (FARPROC) GetWindowLong (hwndScrol[n], GWL_WNDPROC) ;
SetWindowLong (hwndScrol[n], GWL_WNDPROC, (LONG) lpfnScrollProc) ;
SetScrollRange (hwndScrol[n], SB_CTL, 0, 255, FALSE) ;
SetScrollPos (hwndScrol[n], SB_CTL, 0, FALSE) ;
}
ShowWindow (hwnd, nCmdShow) ;
UpdateWindow (hwnd);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
static HBRUSH hBrush[3] ;
char szbuffer[10] ;
HDC hdc ;
POINT point ;
short n, cxClient, cyClient, cyChar ;
TEXTMETRIC tm ;
switch (message)
{
case WM_CREATE :
hBrush[0] = CreateSolidBrush (RGB (255, 0, 0)) ;
hBrush[1] = CreateSolidBrush (RGB (0, 255, 0)) ;
hBrush[2] = CreateSolidBrush (RGB (0, 0, 255)) ;
return 0 ;
case WM_SIZE :
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
cyChar = tm.tmHeight ;
ReleaseDC (hwnd, hdc) ;
MoveWindow (hwndRect, 0, 0, cxClient / 2, cyClient, TRUE) ;
for (n = 0 ; n < 3 ; n++)
{
MoveWindow (hwndScrol[n],
(2 * n + 1) * cxClient / 14, 2 * cyChar,
cxClient / 14, cyClient - 4 * cyChar, TRUE) ;
MoveWindow (hwndLabel[n],
(4 * n + 1) * cxClient / 28, cyChar / 2,
cxClient / 7, cyChar, TRUE) ;
MoveWindow (hwndValue[n],
(4 * n + 1) * cxClient / 28, cyClient - 3 * cyChar / 2,
cxClient / 7, cyChar, TRUE) ;
}
SetFocus (hwnd) ;
return 0 ;
case WM_SETFOCUS :
SetFocus (hwndScrol[nFocus]) ;
return 0 ;
case WM_VSCROLL :
n = GetWindowWord (HIWORD (lParam), GWW_ID) ;
switch (wParam)
{
case SB_PAGEDOWN :
color[n] += 15 ; /* fall through */
case SB_LINEDOWN :
color[n] = min (255, color[n] + 1) ;
break ;
case SB_PAGEUP :
color[n] -= 15 ; /* fall through */
case SB_LINEUP :
color[n] = max (0, color[n] - 1) ;
break ;
case SB_TOP :
color[n] = 0 ;
break ;
case SB_BOTTOM :
color[n] = 255 ;
break ;
case SB_THUMBPOSITION :
case SB_THUMBTRACK :
color[n] = LOWORD (lParam) ;
break ;
default :
break ;
}
SetScrollPos (hwndScrol[n], SB_CTL, color[n], TRUE) ;
SetWindowText (hwndValue[n], itoa (color[n], szbuffer, 10)) ;
DeleteObject (GetClassWord (hwnd, GCW_HBRBACKGROUND)) ;
SetClassWord (hwnd, GCW_HBRBACKGROUND,
CreateSolidBrush (RGB (color[0], color[1], color[2]))) ;
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case WM_CTLCOLOR :
if (HIWORD (lParam) == CTLCOLOR_SCROLLBAR)
{
SetBkColor (wParam, GetSysColor (COLOR_CAPTIONTEXT)) ;
SetTextColor (wParam, GetSysColor (COLOR_WINDOWFRAME)) ;
n = GetWindowWord (LOWORD (lParam), GWW_ID) ;
point.x = point.y = 0 ;
ClientToScreen (hwnd, &point) ;
UnrealizeObject (hBrush[n]) ;
SetBrushOrg (wParam, point.x, point.y) ;
return ((DWORD) hBrush[n]) ;
}
break ;
case WM_DESTROY :
DeleteObject (GetClassWord (hwnd, GCW_HBRBACKGROUND)) ;
for (n = 0 ; n < 3 ; DeleteObject (hBrush [n++])) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
long FAR PASCAL ScrollProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
short n = GetWindowWord (hwnd, GWW_ID) ;
switch (message)
{
case WM_KEYDOWN :
if (wParam == VK_TAB)
SetFocus (hwndScrol[(n +
(GetKeyState (VK_SHIFT) < 0 ? 2 : 1)) % 3]) ;
break ;
case WM_SETFOCUS :
nFocus = n ;
break ;
}
return CallWindowProc (lpfnOldScr[n], hwnd, message, wParam, lParam) ;
}
COLORS1.DEF
;------------------------------------
; COLORS1.DEF module definition file
;------------------------------------
NAME COLORS1
DESCRIPTION 'Colors Using Scroll Bars (c) Charles Petzold, 1990'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS WndProc
ScrollProc
COLORS1 puts its children to work. The program uses 10 child window controls: 3 scroll bars, 6 windows of static text, and 1 static rectangle. COLORS1 traps WM_CTLCOLOR messages to color the interior sections of the three scroll bars red, green, and blue. You can scroll the scroll bars using either the mouse or the keyboard. You can use COLORS1 as a development tool in experimenting with color and choosing attractive (or, if you prefer, ugly) colors for your own Windows programs. A monochrome version of the COLORS1 display is shown in Figure 6-4; obviously, to take advantage of the program's manipulation of color, you'll need to use a color monitor.
COLORS1 doesn't process WM_PAINT messages, and the program obtains a device context handle only for determining the height of a character. Most of the work in COLORS1 is done by the child windows.
The color shown on the right half of the client area is actually the background color of the parent window. A static child window with style SS_WHITERECT blocks out the left half of the client area. The three scroll bars are child window controls with the style SBS_VERT placed on top of the SS_WHITERECT child. Six more static child windows of style SS_CENTER (centered text) provide the labels and the color values. COLORS1 creates its normal overlapped window and the ten child windows within the WinMain function using CreateWindow. The SS_WHITERECT and SS_CENTER static windows use the window class ”static,“ and the three scroll bars use the window class ”scrollbar.“
The x position, y position, width, and height parameters of the CreateWindow call are initially set to 0 because the position and sizing depend on the size of the client area, which is not yet known. COLORS1's window procedure resizes all ten child windows using MoveWindow when it receives a WM_SIZE message. So whenever you resize the COLORS1 window, the size of the scroll bars changes proportionally.
When the WndProc window procedure receives a WM_VSCROLL message, the high word of the lParam parameter is the handle to the child window. We can use GetWindowWord to get the window ID number:
n = GetWindowWord (HIWORD (lParam), GWW_ID) ;
For the three scroll bars, we have conveniently set the ID numbers to 0, 1, and 2, so WndProc can tell which scroll bar is generating the message.
Because the handles to the child windows were saved in arrays when the windows were created, WndProc can process the scroll bar message and set the new value of the appropriate scroll bar using the SetScrollPos call:
SetScrollPos (hwndScrol[n], SB_CTL, color[n], TRUE) ;
WndProc also changes the text of the child window at the bottom of the scroll bar:
SetWindowText (hwndValue[n], itoa (color[n], szbuffer, 10)) ;