在第三章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。