在第三章SYSMETS2.C實例中,我們是通過CreateWindow函數創建窗口的參數窗口樣式中添加垂直或水平滾動條。本節我們將講述作為子窗口控件的滾動條。
本節必須掌握的知識點:
??? ????滾動條類
??? ????滾動條控件和著色
8.3.1 滾動條類
■窗口滾動條與滾動條控件的異同
滾動條子窗口控件可以出現在父窗口客戶區的任何地方。可以使用預定義的“滾動條”窗口類和兩種滾動條樣式SBS_VERT 和SBS_HORZ之一來創建子窗口滾動條控件。
不同于按鈕控件,滾動條控件不發送 WM_COMMAND消息到父窗口。它們就像窗口滾動條一樣發送WM_VSCROLL和 WM_HSCROLL消息。在處理滾動條消息時,可以用IParam參數區分窗口滾動條和滾動條控件。如果IParam參數等于0,就說明它是窗口滾動條;如果等于滾動條窗口句柄,就說明它是滾動條控件。wParam參數的高位字和低位字部分對于窗口滾動條和滾動條控件的含義是一樣的。
與窗口滾動條有一個固定的寬度不同,Windows會通過CreateWindow調用(或之后的 MoveWindow調用)中指定的矩形尺寸來調整滾動條控件的尺寸。你可以產生長而窄的滾動 條控件或短而粗的滾動條控件。
如果想創建和窗口滾動條具有相同尺寸的滾動條控件,則可以使用GetSystemMetrics 獲得水平滾動條的高度:
GetSyscemMetrics (SM_CYHSCROLL) ;
或者獲得垂直滾動條的寬度:
GetSystemMetrics (SM_CXVSCROLL);
滾動條窗口樣式標識符 SBS_LEFTALIGN,SBS_RIGHTALIGN,SBS_TOPALIGN 和 SBS_BOTTOMALIGN都為滾動條提供標準尺寸。不過它們只適用于對話框中的滾動條。 可以使用與用于窗口滾動條同樣的函數來設置滾動條控件的范圍和位置:
SeCScrollRange (hwndScroll, SB_CTL, iMin, iMax, bRedraw) ;
SetScrollPos (hwndScroll, SB_CTL, iPos, bRedraw) ;
SetScrollInfo (hwndScroll, SB_CTL, &si, bRedraw);
區別在于,窗口滾動條會使用主窗口的句柄作為第一個參數,SB_VERT或SB_HORZ作 為第二個參數。
更神奇的是,名為COLOR_SCROLLBAR的系統顏色不再對滾動條起作用。滾動條兩端的按鈕及滑塊的顏色將基于COLOR_BTNFACE,COLOR_BTNHILIGHT ,COLOR_BTNSHADOW,COLOR_BTNTEXT (給小箭頭用),COLOR_DKSHADOW 以及 COLOR_BTNLIGHT。在兩端按鈕之間的大片區域則基于COLOR_BTNFACE和 COLOR_BTNHIGHLIGHT 的某種組合。
如果你俘獲了 WM_CTLCOLORSCROLLBAR消息,就可以從這個消息返回一個畫刷來修改原來的顏色。
窗口滾動條 | 滾動條控件 | |
消息 | 發送WM_VSCROLL、WM_HSCROLL消息。不發送WM_COMMAND消息。wParam參數的意義是一樣的。lParam:當消息來自窗口滾動條時為NULL,來自滾動條控件時為滾動條的句柄。 | |
寬度或高度 | 固定大小 //水平滾動條高度 GetSysMetrics(SM_CYHSCROLL); //垂直滾動條寬度 GetSysMetrics(SM_CYVSCROLL) | 1、大小、位置均可設定; 2、在CreateWindow或MoveWindow函數中指定,大小可自定義。 |
窗口樣式 | WS_VSCROLL:垂直滾動條(在窗口右側) WS_HSCROLL:水平滾動條(在窗口下方) | 可用滾動條樣式和尺寸 SBS_VERT、SBS_HORZ、 S?SBS_TOPALIGN、? BS_BOTTOMALIGN、SBS_LEFTALIGN、SBS_RIGHTALIGN等。 |
調用函數 的參數 | SetScrollInfo(hwnd,SB_VERT, &si,bRedraw); | SetScrollInfo(hwndScroll,SB_CTL, &si,bRedraw); |
■自動鍵盤接口
滾動條控件還可以處理按鍵信息,但前提是它們擁有輸入焦點。下表顯示了鍵盤光標是如何轉換為滾動條消息的。
光標鍵 | 滾動條消息wParam |
Home | SB_TOP |
End | SB_BOTTOM |
PageUp | SB_PAGEUP |
PageDown | SB_PAGEDOWN |
←或↑ | SB_LINEUP |
→或↓ | SB_LINEDOWN |
事實上,SB_TOP和SB_BOTTOM這兩個滾動條消息只能通過鍵盤產生。如果你想讓滾動條控件在鼠標單擊滾動條時取得輸入焦點,必須在CreateWindow函數的窗口類參數中加入WS_TABSTOP標識符。當滾動條獲得輸入焦點時,滾動條滑塊上會顯示一個閃爍的灰色塊。
為了給滾動條提供完整的鍵盤接口,需要做更多的工作。首先,WndProc窗口過程必須專門提供滾動條所需要的輸入焦點。為此,它會處理WM_SETFOCUS消息,這是父窗口得到輸入焦點時接收到的消息。WndProc只需把輸入焦點給其中一個滾動條:
SetFocus (hwndScroll[idFocus]);
這里的idFocus是一個全局變量。
但還需要一些方法通過鍵盤把輸入焦點從一個滾動條移到另一個,最好是使用Tab鍵。 這樣做會有一定難度,因為一旦滾動條獲得輸入焦點,它就會處理所有的按鍵信息。但是滾動條關心的只有光標鍵,它會忽視Tab鍵。解決這個問題的出路在于使用“窗口子類” 這一技術。
8.3.2 第52練:滾動條控件和著色
/*------------------------------------------------------------------
052? WIN32 API 每日一練
??? ?第52個例子COLORS1.C:滾動條控件和著色
??? ?CallWindowProc 函數
??? ?SetWindowLong函數
??? ?SetClassLong函數
??? ?GetDlgItem 函數
??? ?WM_CTLCOLORSCROLLBAR消息
??? ?WM_CTLCOLORSTATIC 消息
??? ?WM_SYSCOLORCHANGE消息
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ScrollProc(HWND, UINT, WPARAM, LPARAM);
int idFocus;
WNDPROC OldScroll[3];
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
??? PSTR szCmdLine, int iCmdShow)
{
??? static TCHAR szAppName[] = TEXT("Colors1");
??? …(略)
??? return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
??? lParam)
{
??? static COLORREF crPrim[3] = { RGB(255, 0, 0), RGB(0, 255, 0),
??? RGB(0, 0, 255) };
??? static HBRUSH hBrush[3], hBrushStatic; //三個滾動條的背景畫刷
??? static HWND hwndScroll[3], hwndLabel[3], hwndValue[3], hwndRect;
??? static int color[3], cyChar; //三個滾動條當前的顏色值
??? static RECT rcColor;
??? static TCHAR * szColorLabel[] = { TEXT("Red"), EXT("Green"),TEXT("Blue") };
??? HINSTANCE hInstance;
??? int i, cxClient, cyClient;
??? TCHAR szBuffer[10];
??? switch (message)
??? {
??? case WM_CREATE:
??????? hInstance = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);//獲取進程句柄
??????? //創建白色矩形靜態窗口控件ID:9--用來存放3個滾動條,可以隱掉后測試
??????? hwndRect = CreateWindow(TEXT("static"), NULL, //生成一個靜態矩形
??????????? WS_CHILD | WS_VISIBLE | SS_WHITERECT,//白色背景靜態窗口類
??????????? 0, 0, 0, 0,
??????????? hwnd, (HMENU)9, hInstance, NULL);
??????? for (i = 0; i < 3; i++) //生成3個滾動條控件
??????? {
??????????? //創建三個滾動條,范圍0-255,ID分別為0,1,2
//WS_TABSTOP標識符:當滾動條獲得輸入焦點時,
//滾動條滑塊上會顯示一個閃爍的灰色塊。
??????????? hwndScroll[i] = CreateWindow(TEXT("scrollbar"), NULL,
??????????????? WS_CHILD | WS_VISIBLE |
??????????????? WS_TABSTOP | SBS_VERT,? //垂直滾動條窗口類
??????????????? 0, 0, 0, 0,
??????????????? hwnd, (HMENU)i, hInstance, NULL);
??????????? //SB_CTL檢索滾動條控件的位置
//設置滾動條控件的滾動范圍
??????????? SetScrollRange(hwndScroll[i], SB_CTL, 0, 255, FALSE);
??????????? SetScrollPos(hwndScroll[i], SB_CTL, 0, FALSE); //滾動滑塊位置
??????????? //3個顏色名稱為"Red"、"Green"、"Blue"的靜態文本框,ID分別為3,4,5
??????????? hwndLabel[i] = CreateWindow(TEXT("static"), szColorLabel[i],
??????????????? WS_CHILD | WS_VISIBLE | SS_CENTER, //將文本居中
??????????????? 0, 0, 0, 0,
??????????????? hwnd, (HMENU)(i + 3),
??????????????? hInstance, NULL);
??????????? //3個表示顏色值得靜態文本框,初始值為"0",IDs 6, 7, and 8
??????????? hwndValue[i] = CreateWindow(TEXT("static"), TEXT("0"),
??????????????? WS_CHILD | WS_VISIBLE | SS_CENTER,
??????????????? 0, 0, 0, 0,
??????????????? hwnd, (HMENU)(i + 6),
??????????????? hInstance, NULL);
??????????? //為滾動條設置一個新的窗口過程ScrollProc,返回舊的窗口過程地址
??????????? OldScroll[i] = (WNDPROC)SetWindowLong(hwndScroll[i],
??????????????? GWL_WNDPROC, (LONG)ScrollProc);
??????????? //創建3個畫刷
??? ??????? hBrush[i] = CreateSolidBrush(crPrim[i]);
??????? }
??????? //創建靜態文本背景畫刷,3D 顯示元素的高亮顏色
??????? hBrushStatic = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
??? ?? //獲取對話框字體的高
??????? cyChar = HIWORD(GetDialogBaseUnits());
??????? return 0;
??? case WM_SIZE:
??????? cxClient = LOWORD(lParam);
??????? cyClient = HIWORD(lParam);
??????? //設置右側顯式顏色的矩形框坐標
??????? SetRect(&rcColor, cxClient / 2, 0, cxClient, cyClient);
??????? //指定的矩形尺寸來調整白色矩形靜態窗口控件的尺寸
??????? MoveWindow(hwndRect, 0, 0, cxClient / 2, cyClient, TRUE);
??????? //設置滾動條在主窗口大小和位置:寬cxClient/14,高cyClient -4*cyChar;
??????? for (i = 0; i < 3; i++)
??????? {
??????????? MoveWindow(hwndScroll[i],
??????????????? (2 * i + 1) * cxClient / 14, 2 * cyChar,
??????????????? cxClient / 14, cyClient - 4 * cyChar, TRUE);
??????????? MoveWindow(hwndLabel[i],
??????????????? (4 * i + 1) * cxClient / 28, cyChar / 2,
??????????????? cxClient / 7, cyChar, TRUE);
??????????? MoveWindow(hwndValue[i],
??????????????? (4 * i + 1) * cxClient / 28,
??????????????? cyClient - 3 * cyChar / 2,
??????????????? cxClient / 7, cyChar, TRUE);
??????? }
??????? SetFocus(hwnd);
??????? return 0;
??? case WM_SETFOCUS:
??????? SetFocus(hwndScroll[idFocus]);//設置為焦點控件
??????? return 0;
??? case WM_VSCROLL:
??????? //獲取子窗口ID
??????? i = GetWindowLong((HWND)lParam, GWL_ID);
??????? switch (LOWORD(wParam))
??????? {
??????? case SB_PAGEDOWN: color[i] += 15;
??????????? //繼續執行
??????? case SB_LINEDOWN: color[i] = min(255, color[i] + 1); break;
??????? case SB_PAGEUP: color[i] -= 15;
??????????? // 繼續執行
??????? case SB_LINEUP: color[i] = max(0, color[i] - 1); break;
??????? case SB_TOP: color[i] = 0; break;
??????? case SB_BOTTOM: color[i] = 255; break;
??????? case SB_THUMBPOSITION:
??????? case SB_THUMBTRACK: color[i] = HIWORD(wParam); break;
??????? default:? break;
??????? }
??????? SetScrollPos(hwndScroll[i], SB_CTL, color[i], TRUE); //設置滑塊位置
??????? wsprintf(szBuffer, TEXT("%i"), color[i]); //改變顏色值
??????? SetWindowText(hwndValue[i], szBuffer); //顯示顏色值
??? ?? //設置窗口類的背景顏色
??? ?? //創建新畫刷替換窗口類結構中的黑色畫刷
??????? DeleteObject((HBRUSH) //刪除舊畫刷
??????????? SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG) //替換背景畫刷
??????????????? CreateSolidBrush(RGB(color[0], color[1], color[2]))));
??????? InvalidateRect(hwnd, &rcColor, TRUE); //重繪窗口,TRUE擦除背景
??????? //UpdateWindow(hwnd);//立即更新,不需要送入消息隊列
??????? return 0;
??????? //將要繪制控件時滾動條控件消息:
//wParam:滾動條控件的設備上下文的句柄DC,lParam:滾動條句柄
??? case WM_CTLCOLORSCROLLBAR:
??????? //返回畫刷句柄,用來修改三個滾動條內部的顏色
??????? i = GetWindowLong((HWND)lParam, GWL_ID);//獲取控件ID
//必須將句柄返回給畫刷。 系統使用畫刷繪制滾動條控件的背景。
??????? return (LRESULT)hBrush[i];
?? //將要繪制時,靜態控件消息---設定靜態文本的顏色
??? case WM_CTLCOLORSTATIC:
??????? i = GetWindowLong((HWND)lParam, GWL_ID); //獲取窗口ID
??????? if (i >= 3 && i <= 8) // 6個static text controls ID:3~8
??????? {
??????????? //設置靜態文本顏色
??????????? SetTextColor((HDC)wParam, crPrim[i % 3]);
//設置系統顏色為背景色
??????????? SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNHIGHLIGHT));
??????????? return (LRESULT)hBrushStatic;
??????? }
??????? break;
??????? //更改系統顏色
??? case WM_SYSCOLORCHANGE:
??????? DeleteObject(hBrushStatic);//刪除畫刷
//重新創建畫刷
??????? hBrushStatic = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
??????? return 0;
??? case WM_DESTROY:
??????? //創建新的白色畫刷,把句柄存入到窗口類中然后刪除舊的畫刷
??????? DeleteObject((HBRUSH)
??????????? SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)
??????????????? GetStockObject(WHITE_BRUSH)));
??????? for (i = 0; i < 3; i++)
??????????? DeleteObject(hBrush[i]);
??????? DeleteObject(hBrushStatic);
??????? PostQuitMessage(0);
??????? return 0;
??? }
??? return DefWindowProc(hwnd, message, wParam, lParam);
}
//窗口子類過程
LRESULT CALLBACK ScrollProc(HWND hwnd, UINT message,
??? WPARAM wParam, LPARAM lParam)
{
??? int id = GetWindowLong(hwnd, GWL_ID);
??? switch (message)
??? {
??????? //收到按鍵消息時,更改輸入焦點到另一個滾動條
??? case WM_KEYDOWN:
??????? if (wParam == VK_TAB)
??????????? SetFocus(GetDlgItem(GetParent(hwnd),//包含控件的對話框的句柄
??????? ?? //追蹤SHIFT鍵,改變TAB鍵切換的順序:
??????? ?? //按下SHIFT <0:2,1,0;未按下>0:0,1,2
??????????? (id + (GetKeyState(VK_SHIFT) < 0 ? 2 : 1)) % 3));
??????? break;
??? case WM_SETFOCUS:
??????? idFocus = id;
??????? break;
??? }
??? //調用子窗口舊的窗口過程
??? return CallWindowProc(OldScroll[id], hwnd, message, wParam, lParam);
}
/******************************************************************************
CallWindowProc 函數:子窗口類過程返回舊窗口過程
LRESULT CallWindowProcA(
? WNDPROC lpPrevWndFunc,
? HWND??? hWnd,
? UINT??? Msg,
? WPARAM? wParam,
? LPARAM? lParam
);
*******************************************************************************
SetWindowLong函數:設置子窗口類過程
LONG SetWindowLongA(
? HWND hWnd,
? int? nIndex,//設置窗口過程的新地址
? LONG dwNewLong//新窗口過程
);
*******************************************************************************
SetClassLong函數:將指定偏移量處的指定32位(long)值替換到指定窗口所屬類的額外類存儲器或WNDCLASSEX結構中。
DWORD SetClassLongA(
? HWND hWnd,?? //窗口的句柄,間接地,窗口所屬的類。
? int? nIndex, //將要被替換的值。
? LONG dwNewLong//替換值
);
注意? 此函數已被SetClassLongPtr函數取代。要編寫與Windows 32位和64位版本兼容的代碼,請使用SetClassLongPtr。
*******************************************************************************
GetDlgItem 函數用于獲取對話框模板中標識符(ID)對應的子窗口句柄。
HWND GetDlgItem(
? HWND hDlg,??? //對話框的窗口句柄
? int? nIDDlgItem//子窗口的標識符(ID)
);
返回值:對應標識符的子窗口的句柄(HWND)。
*******************************************************************************
WM_CTLCOLORSCROLLBAR消息:發送滾動條控件消息至父窗口
wParam:DC,lParam:滾動條句柄,
//必須返回畫筆句柄
WM_CTLCOLORSTATIC 消息:發送靜態控件消息至父窗口
WM_SYSCOLORCHANGE消息:更改系統顏色設置后,會將WM_SYSCOLORCHANGE消息發送到所有頂級窗口
*/
?????? 運行結果:
圖8-5 滾動條控件
?
總結
實例COLORS1.C在一個白色靜態文本框內繪制了3個滾動條控件,此外還繪制了6個靜態文本控件顯示RGB顏色及顏色值。在主窗口客戶區的左側繪制一個矩形,使用3個滾動條控件的RGB值創建一個畫刷,填充矩形背景。
此外,還根據3個滾動條控件的值(0~255)分別創建3個畫刷,設置3個靜態文本顏色,創建一個高亮系統顏色畫刷作為靜態文本控件的背景色。
實例COLORS1.C還創建了一個窗口子類,定義了一個新的滾動條子窗口控件過程,用于處理鍵盤接口TAB鍵,切換焦點窗口。
主窗口過程對于WM_CREATE消息的處理。首先創建一個存放3個滾動條控件的靜態文本框。接著創建3個滾動條控件,并將滾動條滾動范圍設置為0~255,與RGB顏色值對應。初始滾動條滑塊位置為0。然后在滾動條控件的上方和下方分別創建3個靜態文本控件,用于顯示RGB顏色和顏色值。最后調用SetWindowLong函數設置滾動條控件新的窗口過程ScrollProc,并返回Windows預定義的滾動條控件默認窗口過程,存入OldScroll[i]數組。接著創建一個靜態文本背景畫刷,并獲取對話框字體的高。
WM_SIZE消息的處理:調用SetRect函數在主窗口右側繪制一個矩形框。調用MoveWindow函數調整靜態文本框控件和滾動條控件的大小。
WM_SETFOUCUS消息處理:調用SetFocus函數將當前idFocus滾動條控件設為焦點窗口。
WM_VSCROLL消息處理:調用GetWindowLong函數獲取滾動條控件ID,并依據wParam
參數低字值調整滾動條滑塊位置。滑塊位置即顏色值,修改3個靜態文本顏色值,并以此生成新畫刷填充主窗口右側矩形背景色。
WM_CTLCOLORSCROLLBAR消息處理:將要繪制滾動條控件時接收此消息,該消息的wParam:滾動條控件的設備上下文的句柄DC;lParam:滾動條句柄。調用GetWindowLong依據滾動條控件句柄獲取滾動條控件ID,并返回畫刷return (LRESULT)hBrush[ID];
WM_CTLCOLORSTATIC消息處理:將要繪制靜態文本控件時接收此消息,調用GetWindowLong依據靜態文本控件句柄獲取控件ID,并更新靜態文本顏色和顏色值。
WM_SYSCOLORCHANGE消息處理:如果更改系統顏色,則刪除舊靜態文本背景畫刷,重新依據系統顏色生成新的靜態文本背景畫刷。
WM_DESTROY消息處理:刪除創建的新GDI畫刷對象。
■窗口子類
滾動條控件的窗口過程在Windows內部。但是你可以調用GetWindowLong來獲取這 個窗口過程的地址,使用GWL_WNDPROC標識符作為參數即可。此外,還可以通過調用SetWindowLong,為滾動條設置一個新的窗口過程。這種技術被稱為“窗口子類”。它的功能非常強大。它可以讓你連接到已有的窗口過程,在你的程序中處理一些消息,并將其他消息傳遞給舊的窗口過程。
在COLORS1中,能初步處理滾動條消息的窗口過程名為ScroMProc,它列在 C0L0RS1.C文件的結束部分。由于COLORS1中的ScrollProc是一個被Windows調用的函數,因此它必須被定義成CALLBACK類型。
對這三個滾動條中的每一個COLORS1都使用SetWindowLong來設置新的滾動條窗口過程的地址,同時獲得現有滾動條窗口過程的地址:
OldScroll[i] = (WNDPROC) SetWindowLong (hwndScroll[i),
GWL_VMDPROC,(LONG) ScrollProc));
現在,ScrollProc獲得了 Windows發送給COLORS1程序中三個滾動條的所有消息(當然不包括在其他程序中的滾動條)。當它收到Tab或Shift-Tab擊鍵信息后,此ScrollProc 窗口過程只需更改輸入焦點到下一個(或前一個)滾動條即可。它使用CallWindowProc來調 用舊的滾動條窗口過程。
■背景著色
在COLORS1定義它的窗口類時,給它的客戶區指定了一個黑色的背景畫刷:
wndclass.hbrBackground = CreateSolidBrush (0);
當你更改COLORS1的滾動條設置時,程序必須創建一個新的畫刷,并把新畫刷句柄存入窗口類的結構中。正如我們使用GetWindowLong和SetWindowLong來獲取和設置滾動 條窗口過程一樣,我們可以使用GetClassWord和SetClassWord來獲取和設置這個畫刷的句柄。
你可以創建新的畫刷,把句柄存入到窗口類結構中,然后刪除舊的畫刷:
DeleteObject ((HBRUSH)
?????? ?????? SetClassLong (hwnd, GCL_HBRBACKGROUND, (LONG)
????????????? ?????? CreaceSolidBrush (RGB (colort[0], color[1], color[2]))));
下一次Windows重新給窗口背景著色的時候,Windows將使用這個新畫刷。如果要強制 Windows擦除背景,我們可以讓客戶區的右半部分失效:
InvalidateRect (hwnd, &rcColor, TRUE);
函數的第三個參數輸入TRUE(非零值),表明我們希望在窗口重繪之前擦除背景。
InvalidateRect函數會讓Windows把WM_PAINT消息放在窗口過程的消息隊列中。由于WM_PAINT消息屬于低優先級消息。因此,如果你仍然在移動鼠標或光標鍵,此消息將不會立即被處理。另一種情況是,如果你希望窗口在顏色修改后立即更新,則可以在 InvalidateRect函數被調用后調用下面的函數:
UpdateWindow (hwnd);
不過,這個函數可能會拖慢鍵盤和鼠標處理速度。
COLORS1的WndProc函數不直接處理WM_PAINT消息,而是將它傳遞給 DefWindowProc函數。WM_PAINT消息在Windows中的默認處理方式僅僅是調用 BeginPaint和EndPaint來使窗口有效。因為我們在InvalidateRect中指定舊背景應該被刪除,所以調用BeginPaint會使Windows產生一條WM_ERASEBKGND(擦除背景)消息。 WndProc也會忽略此消息。Windows會對該消息進行處理,它使用窗口類指定的畫刷來擦除這個客戶區的背景。
通常情況下,在終止程序前進行清理總是一個不錯的好主意,因此在處理 WM_DESTROY消息時,DeleteObject被再次調用:
DeleteObject ((HBRUSH)
?????? SetClassLong (hwnd, GCL_HBRBACKGROUND,
????????????? (LONG) GetStockObject (WHITE_BRUSH)));
■給滾動條和靜態文本著色
在COLORS1中,三個滾動條內部和六個文本框中文本的顏色分別被著色為紅色、綠色和藍色。滾動條的著色是通過處理WM_CTLCOLORSCROLLBAR消息來完成的。
在WndProc中,為三個畫刷句柄定義了一個靜態數組:
static HBRUSH hBrush [3];
在處理WM_CREATE的過程中,創建了這三個畫刷:
for (i = 0;i < 3; i++)
hBrush[0] = CreateSolidBrush (crPrim [i]) ;
在這里crPrim數組中包含三個基色的RGB值。在處理WM_CTLCOLORSCROLLBAR
時,窗口過程返回三個畫刷中的一個:
case WM_CTLCOLORSCROLLBAR:
i = GetWindowLong ((HWND) IParam, GWL_ID);
???????????? return (LRESULT) hBrush [i];
這些畫刷必須在處理WM_DESTROY消息期間被銷毀:
for (i =0; i < 3; i++)
?????? DeleteObject (hBrush [i]));
類似地,靜態文本框中文本的著色是通過處理WM_CTLCOLORSTATIC消息和調用 SetTextCoIor函數完成的。文本的背景通過調用SetBkColor設置為系統顏色 COLOR_BTNHIGHLIGHT。這會導致文本的背景與滾動條后面的靜態矩形控件具有相同的顏色。對于靜態文本控件,這種文本的背景顏色只應用于字符串中每個字符背后的矩形框,而不是控件窗口的整個寬度。要做到這一點,窗口過程必須返回一個COLOR_BTNHIGHLIGHT顏色的畫刷句柄。這個被稱為hBrushStatic的畫刷是在 WM_CREATE處理期間產生的,并在WM_DESTROY消息處理期間被銷毀。
程序在WM_CREATE消息處理期間產生COLOR_BTNHIGHLIGHT顏色的畫刷,并在程序生命周期中使用它。但這樣我們會碰到一個小問題。如果C0L0R_BTNHIGHL1GHT 顏色在程序運行過程中被改變了,靜態矩形的顏色會改變,文本背景顏色會改變,但整個文本窗口控件的背景仍將保持原有的COLOR_BTNHIGHLIGHT顏色。
為解決這一問題,COLORS 1在處理WM_SYSCOLORCHANGE消息時簡單地用新顏色重新創建hBrushStatic。