标签:
(1)子窗口控件:①子窗口,其parent为父窗口句柄;②子窗口状态发生变化时,会处理鼠标和键盘消息,并且通知其父窗口。可分为自定义子窗口控件和标准的子窗口控件(如按钮)
(2)子窗口控件的使用场合
①在对话框里使用最广——有内在机制支持Tab和光标移动键来转移焦点。
②在窗口表面直接使用:没内在机制支持Tab键和光标移动键来移动焦点到另一个控件;
对于自定义的控件,当单击子窗口时,父窗口会得到焦点。但对于标准子窗口控件,单击时会自动获得焦点(估计子窗口过程内部在WM_LBUTTONDOWN中实现了SetFocus(hwnd)了)。不管是哪类子窗口,都可以得到输入焦点,但一旦得到焦点,它自己无法把输入焦点交回给其父窗口。(可以通过窗口子类化来达到目的)。
(3)子窗口的销毁:在父窗口销毁的同时,会自动销毁子窗口,程序不必自己处理。
9.1 按钮类
9.1.1 创建子窗口:CreateWindow各参数设置
参数 |
值 |
备注 |
lpClassName |
Text(“button”) |
预定义的名称,不可更改 |
lpWindowName |
button[i].szText |
按钮上显示的文本 |
dwStyle |
WS_CHILE|WS_VISIBLE|button[i].style |
|
x |
cxChar |
相对于父窗口客户区左上角 |
y |
cyChar*(1+2*i) |
相对于父窗口客户区左上角 |
nWidth |
20*xChar |
|
nHeight |
7*yChar/4 |
|
hWndParent |
Hwnd |
|
hMenu |
(HMENU)i |
子窗口ID,每个窗口唯一 |
hInstance |
((LPCREATESTRUCT)lParam)->hInstance |
WM_CREATE的lParam指向一个CREATESTRUCT结构,可从中获得hInstance句柄 |
lpParam |
NULL |
额外参数 |
★获取hInstance的4种方法:
①设置全局变量hInst,在WinMain函数中 hInst = hInstance;
②hInstance =GetWindowLong(hwnd,GWL_INSTANCE);
③在WM_CREATE消息中从lParam中获取:hInstance = ((LPCREATESTRUCT)lParam)->hInstance
④hInstance =GetModuleHandle(NULL);
9.1.2 子窗口传递信息给父窗口
(1)子窗口过程获取父窗口句柄的方法:hwndParent =GetParent(hwnd);
(2)子窗口向父窗口过程发送消息:SendMessage(hwndParent,message,wParam,lParam);
★注意发送自定义消息时:message可以是大于等于WM_USER的任何值。
wParam:可设为子窗口ID。
lParam:可设置额外的信息。
(3)单击按钮,子窗口会向父窗口发送WM_COMMAND消息。各参数如下
参数 |
值 |
备注 |
|
lParam |
子窗口句柄 |
|
|
wParam |
LOWORD(wParam) :子窗口ID |
|
|
HIWORD(wParam):通知码
通知码以BN_开头,表示消息传输的方向是给父窗口的通知消息。 |
BN_CLICKED (0) |
释放鼠标时发生 |
|
BN_PAINT (1) |
为过时的按钮样式BS_USERBUTTON所用(己被BS_OWNERDRAW和另一套通知机制取代) |
||
BN_HILITE或BN_PUSHED (2) |
|||
BN_UNHILITE或BN_UNPUSHED (3) |
|||
BN_DISABLE (4) |
|||
BN_DOUBLECLICKED或BN_DBLCLK (5) |
仅用于BS_RADIOBUTTON、BS_AUTORADIOBUTTON和BS_OWNERDRAW或BS_NOTIFY的按钮使用 |
||
BN_SETFOCUS (6) |
仅用于BS_NOTIFY样式的按钮 |
||
BN_KILLFOCUS (7) |
9.1.3 父窗口传递信息给子窗口:按钮消息以BM_开头(不是WM_开头的)
(1)获取子窗口ID或子窗口句柄或方法
①id = GetWindowLong(hwndChild,GWL_ID)或 id =GetDlgCtrlID(hwndChild)
②hwndChild = GetDlgItem(hwndParent,id);
(2)SentMessage的message(消息)设置
按钮消息 |
备注 |
BM_GETCHECK (0x00F0) |
单击或复选框按钮 |
BM_SETCHECK (0x00F1) |
|
BM_GETSTATE (0x00F2) |
返回 BST_CHECKED:被单击 BST_FOCUS:具有输入焦点 BST_PUSHED:按住鼠标 …… |
BM_SETSTATE (0x00F3) |
|
BM_CLICK (0x00F4) |
模拟按钮单击 |
BM_GETIMAGE (0x00F5) |
|
BM_SETIMAGE (0x00F6) |
|
9.1.4 按钮
(1)按键按钮的最佳视觉高度:字符高度的7/4。宽度:文本宽度 + 2个字符宽度。
(2)模拟按键按钮的状态
①按住状态:SendMessage(hwndButton,BM_SETSTATE,1,0);
②正常状态:SendMessage(hwndButton,BM_SETSTATE,0,0);
9.1.5 复选框
样式 |
状态 |
BS_CHECKBOX |
1、SendMessage(hwndButton,BM_SETCHECK,1,0); //选中 2、SendMessage(hwndButton,BM_SETCHECK,0,0); //取消选中 3、SendMessage((HWND)lParam,BM_SETCHECK,(WPARAM) //切换 !SendMessage((HWND)lParam,BM_GETCHECK,0,0),0); |
BS_AUTOCHECKBOX |
1、自动切换 2、获取状态:iCheck = (int)SendMessage(hwndButton,BM_GETCHECK,0,0); |
BS_3STATE |
SendMessage(hwndButton,BM_SETCHECK,2,0); //第3种状态 |
BS_AUTO3STATE |
//自动切换 |
(1)宽度和高度:最低高度——1个字符的高度,最小宽度——字符数+2个字符的宽度。
(2)复选框中的文本位置及文本对齐
9.1.6 单选按钮——第二次单击时,不会状态切换,其状态保持不变
(1)BS_AUTORADIOBUTTON:
(2)BS_RADIOBUTTON:父窗口收到WM_COMMAND消息时,可以
选中单选按钮:SendMessage(hwndButton,BM_SETCHECK,1,0);
取消选中: SendMessage(hwndButton,BM_SETCHECK,0,0);
9.1.7 组合框(Group Boxes)——不发送WM_COMMAND消息,也不接收鼠标和键盘消息。
9.1.8 改变按钮文本
(1)设置文本:SetWindowText(hwnd,pszString);
(2)获取文本: iLength = GetWindowTextLength(hwnd);//先获取文本长度
GetWindowText(hwnd,pszBuffer,iLength);//获取文本到指定缓冲区
9.1.9 可见的按钮和启用的按钮
(1)显示子窗口:ShowWindow(hwndChild,SW_SHOWNORMAL); //窗口类没WS_VISIBLE时不显示。
(2)判断窗口可见性:IsWindowVisible(hwndChild);
(3)启用或禁用:EnableWindow(hwndChild,TRUE)或EnableWindow(hwndChild,FALSE);
(4)子窗口是否被启动:IsWindowEnabled(hwndChild);
9.1.10 按钮或输入焦点
(1)单击鼠标时,按钮会自动得到焦点,键盘消息发往子窗口(即按钮的内部窗口过程)
①子窗口只对空格键做出响应(类似鼠标单击)
②父窗口失去对键盘处理的控制——解决方法就是窗口子类化
(2)当焦点从父窗口向子窗口转移时的消息顺序
①WM_KILLFOCUS发往父窗口,wParam为要获得焦口的窗口句柄。
②WM_SETFOCUS发往子窗口,wParam为失去焦点的窗口句柄。
(3)阻止子窗口获得输入焦点
方法1 |
方法2 |
case WM_KILLFOCUS: //NUM为子窗口的数目 for (int i = 0; i < NUM;i++) { //wParam为要获取焦点的窗口句柄 if (hwndChild[i] == (HWND)wParam) { SetFocus(hwnd); break; } } return 0; |
case WM_KILLFOCUS: //要获得焦点的是子窗口,则抢回焦点 if (hwnd == GetParent((HWND)wParam)) SetFocus(hwnd);//父窗口抢回焦点
return 0; |
【BtnLook程序】
效果图:
/*------------------------------------------------------------ BTNLOOK.C -- Button Look Program (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> struct { int iStyle; //按钮样式 TCHAR* szText; //显示文本 } button[] = { BS_DEFPUSHBUTTON, TEXT("PushButton"), BS_DEFPUSHBUTTON, TEXT("DefPushButton"), BS_CHECKBOX, TEXT("CheckBox"), BS_AUTOCHECKBOX, TEXT("AutoCheckBox"), BS_RADIOBUTTON, TEXT("RadioButton"), BS_3STATE, TEXT("3State"), BS_AUTO3STATE, TEXT("Auto3State"), BS_GROUPBOX, TEXT("GroupBox"), BS_AUTORADIOBUTTON, TEXT("AutoRadioButton"), BS_OWNERDRAW, TEXT("OwnerDraw") }; #define NUM (sizeof(button)/sizeof(button[0])) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("BtnLook"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("Button Look"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static HWND hwndButton[NUM]; static int cxChar, cyChar; static TCHAR szTop[] = TEXT("message wParam lParam"), szUnd[] = TEXT("_______ ______ ______"), szFormat[] = TEXT("%-16s%04X-%04X %04X-%04X"), szBuffer[50]; static RECT rect; switch (message) { case WM_CREATE: cxChar = LOWORD(GetDialogBaseUnits());//对话框基本单位, cyChar = HIWORD(GetDialogBaseUnits());//为系统字体字符的平均宽度和高度 //创建NUM个按钮 for (int i = 0; i < NUM; i++) { hwndButton[i] = CreateWindow( TEXT("button"), button[i].szText, WS_VISIBLE | WS_CHILD | button[i].iStyle, cxChar, cyChar*(1 + 2 * i), //每个按钮高度为7/4*cyChar,加1/4间隔,得2*cyChar 20 * cxChar, 7 * cyChar / 4, hwnd, (HMENU)i, ((LPCREATESTRUCT)lParam)->hInstance, NULL); } return 0; case WM_SIZE: rect.left = 24 * cxChar; rect.top = 2 * cyChar; rect.right = LOWORD(lParam); rect.bottom = HIWORD(lParam); return 0; case WM_DRAWITEM: case WM_COMMAND: ScrollWindow(hwnd, 0, -cyChar, &rect, &rect); //产生一个无效区 hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); TextOut(hdc, 24 * cxChar, cyChar*(rect.bottom / cyChar - 1), szBuffer, wsprintf(szBuffer, szFormat, message == WM_DRAWITEM ? TEXT("WM_DRAWITEM") : TEXT("WM_COMMAND"), HIWORD(wParam), LOWORD(wParam), HIWORD(lParam), LOWORD(lParam))); ReleaseDC(hwnd, hdc); ValidateRect(hwnd, &rect); //因为ScrollWindow会将生无效区, //而ValidateRect会将无效区有效化,阻止发送WM_PAINT消息。 //如果注释掉ValidateRect,将引起不断的重绘。 return 0; case WM_PAINT: /* 1、窗口句柄(HWND)都是由操作系统内核管理的,系统内部有一个z-order序列,记录着当前从屏幕底部 (假象的从屏幕到眼睛的方向),到屏幕最高层的一个窗口句柄的排序,这个排序不关注父窗口还 是子窗口。当任意一个窗口接受到WM_PAINT消息产生重绘,更新区绘制完成以后,就搜索它的前面 的一个窗口,如果此窗口的范围和更新区有交集,就向这个发送wm_paint消息,周而复始,直到执 行到顶层窗口才算完成。 2、主窗口接受WM_PAINT绘制完成后,会引起更新区上所有子窗口的重绘(所有子窗口也是从底到外排序的) 3、子窗口无效不会引起父窗口重绘。父窗口无效,如果父窗口(没有WS_CLIPCHILDREN属性)收到WM_PAINT, 则所有子窗口都会在父窗口处理WM_PAINT之后收到WM_PAINT重绘消息。当然,如果父窗口带有属性 WS_CLIPCHILDREN,则不会引起子窗口重绘。 */ //以下将客户区刷白,因子窗口范围与无效区有交集,会导致子窗口重绘,因此本例中WM_DRAWITEM会被触发, //而WM_DRAWITEM过程中的SrollWindow会引起WM_PAINT,可在WM_DRAWITEM里,将无效区有效化,阻止 //ScrollWindow引发的WM_PAINT,从而防止死循环。 InvalidateRect(hwnd, NULL, TRUE);//因为在WM_COMMAND过程中绘制的内容,在WM_PAINT中无法重绘出来, //为防止主窗口被遮挡,再移开时,出现WM_COMMMAND中会制的无法重现, //最省事的做法是,那些内容全部不要了。 hdc = BeginPaint(hwnd, &ps); //将无效区有效化,阻止重复发送WM_PAINT消息。 SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); SetBkMode(hdc, TRANSPARENT); TextOut(hdc, 24 * cxChar, cyChar, szTop, lstrlen(szTop)); TextOut(hdc, 24 * cxChar, cyChar, szUnd, lstrlen(szUnd)); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
9.2 控件和颜色
(1)29种系统颜色:GetSysColor(SetSysColor)
常量索引值 |
注册表键值 |
默认RGB值 |
COLOR_SCROLLBAR |
Scrollbar |
C0-C0-C0 |
COLOR_BACKGROUND |
Background |
00-80-80 |
COLOR_ACTIVECAPTION |
ActiveTile |
00-00-80 |
COLOR_INACTIVECAPTION |
InactiveTitle |
80-80-80 |
COLOR_MENU |
Menu |
C0-C0-C0 |
COLOR_WINDOW |
Window |
FF-FF-FF |
COLOR_WINDOWFRAME |
WindowFrame |
00-00-00 |
COLOR_MENUTEXT |
MenuText |
C0-C0-C0 |
COLOR_WINDOWTEXT |
WindowText |
00-00-00 |
COLOR_CAPTIONTEXT |
TitleText |
FF-FF-FF |
COLOR_ACTIVEBORDER |
ActiveBorder |
C0-C0-C0 |
COLOR_INACTIVEBORDER |
InactiveBorder |
C0-C0-C0 |
COLOR_APPWORKSPACE |
AppWorkspace |
80-80-80 |
COLOR_HIGHLIGHT |
Highlight |
00-00-80 |
COLOR_HIGHLIGHTTEXT |
HighlightText |
FF-FF-FF |
COLOR_BTNFACE |
ButtonFace |
C0-C0-C0 |
COLOR_BTNSHADOW |
ButtonShadow |
80-80-80 |
COLOR_GRAYTEXT |
GrayText |
80-80-80 |
COLOR_BTNTEXT |
ButtonText |
00-00-00 |
COLOR_INACTIVECAPTIONTEXT |
InactiveTitleText |
C0-C0-C0 |
COLOR_BTNHIGHLIGHT |
ButtonHighlight |
FF-FF-FF |
COLOR_3DDKSHADOW |
ButtonDkShadow |
00-00-00 |
COLOR_3DLIGHT |
ButtonLight |
C0-C0-C0 |
COLOR_INFOTEXT |
InfoText |
00-00-00 |
COLOR_INFOBK |
InfoWindow |
FF-FF-FF |
[没有标识符,使用值25] |
ButtonAlternateFace |
B8-B4-B8 |
COLOR_HOTLIGHT |
HotTrackingColor |
00-00-FF |
COLOR_GRADIENTACTIVECAPTION |
GradientActiveTitle |
00-00-80 |
COLOR_GRADIENTINACTIVECAPTION |
GradientInactiveTitle |
80-80-80 |
(2)使用举例
①将客户区背景色设为COLOR_BTNFACE
wndClass.hbrBackground=(HBRUSH)(COLOR_BTNFACE + 1);
//注意:hbrBackground值很低时,指的是系统颜色,而不是实际的句柄。+1是为了防止NULL。
②TextOut显示的文本和其背景颜色
SetBkColor(hdc,GetSysColor(COLOR_BTNFACE));
SetTextColor(hdc,GetSysColor(COLOR_WINDOWTEXT));
(3)用户更改系统颜色,会发送WM_SYSCOLORCHANGE消息
caseWM_SYSCOLORCHANGE:InvalidateRect(hwnd,NULL,TRUE);break;
9.2.2 按钮的颜色
颜色 |
说明 |
COLOR_BTNFACE |
按钮主表面颜色或其他按钮的背景颜色 |
COLOR_BTNSHADOW |
按钮右侧和底部的阴影颜色 |
COLOR_BTNTEXT |
对按键按钮而言的,为上面的文本颜色 |
COLOR_WINDOWTEXT |
其他控件的文本颜色 |
9.2.3 WM_CTLCOLORBTN消息:当子窗口即将重绘其客户区时,发送其给父窗口
wParam |
按钮的设备环境句柄 |
lParam |
按钮的窗口句柄 |
(1)只要按钮按钮和自绘按钮会发送WM_CTLCOLORBTN消息
(2)自绘按钮由父窗口过程来负责绘制
(3)处理WM_CTLCOLORBTN消息时,可以
①SetTextColor:设置文本颜色
②SetBkColor设置文本背景颜色
③返回子窗口的画刷句柄
9.2.4 自绘按钮Owner-Draw Button
(1)按钮风格
BS_ICON、BS_BITMAP |
显示为一个图标或位图,可使用BM_SETIMAGE消息 |
BS_OWNERDRAW |
可完全控制的绘制 |
(2)WM_DRAWITEM消息中的lParam参数——DRAWITEMSTRUCT结构
成员 |
常见值 |
备注 |
CtlType |
ODT_BUTTON: 按钮控件 ODT_COMBOBOX:组合框控件 ODT_LISTBOX: 列表框控件 ODT_LISTVIEW:列表视图控件 ODT_MENU: 菜单项 ODT_STATIC: 静态文本控件 ODT_TAB: Tab控件 |
控件类型 |
CtlID |
自绘控件ID,而对于菜单项则不需要使用该成员 |
|
itemID |
菜单项ID |
|
itemAction |
ODA_DRAWENTIRE:要整个控件被绘制,设置该值 ODA_FOCUS: 要在获得或失去焦点时被绘制。 ODA_SELECT:要在选中状态改变时被绘制。 |
指定绘制行为,其取值可以为右边中所示值的一个或者多个的联合 |
itemState |
ODS_CHECKED:要菜单被选中,可设置该值 ODS_COMBOBOXEDIT:只绘制组合框中选择区域 ODS_DEFAULT:默认值 ODS_DISABLED:禁用控件 ODS_FOCUS:控件需要焦点,则该置该值 ODS_GRAYED:控件被灰色 ODS_SELECTED:选中的菜单项 …… |
所绘项的可见状态 |
hwndItem |
自绘控件的窗口句柄;如果自绘的对象时菜单项,则表示包含该菜单项的菜单句柄。 |
|
hDC |
指定了绘制操作所使用的设备环境 |
|
rcItem |
指定了将被绘制的矩形区域 |
|
itemData |
|
(3)自绘按钮坐标
(4)DrawFocusRect函数用来绘制虚线矩形
(5)DRAWITEMSTRUCT结构中的设备环境的状态必须保持原样,被选入hdc的GDI对象必须设置回原有的不被选中的状态。
【OwnerDraw程序】
效果图
/*------------------------------------------------------------ OWNDRAW.C -- Owner-Draw Button Demo Program (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #define ID_SMALLER 1 #define ID_LARGER 2 #define BTN_WIDTH (8 * cxChar) #define BTN_HEIGHT (4 * cyChar) HINSTANCE hInst; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("OwnDraw"); HWND hwnd; MSG msg; WNDCLASS wndclass; hInst = hInstance; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("Owner-Draw Button Demo"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void Triangle(HDC hdc, POINT pt[]) { SelectObject(hdc, GetStockObject(BLACK_BRUSH)); Polygon(hdc, pt, 3); SelectObject(hdc, GetStockObject(WHITE_BRUSH)); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hwndSmaller, hwndLarger; static cxClient, cyClient, cxChar, cyChar; DRAWITEMSTRUCT* pdis; int cx, cy; POINT pt[3]; RECT rc; switch (message) { case WM_CREATE: cxChar = LOWORD(GetDialogBaseUnits()); cyChar = HIWORD(GetDialogBaseUnits()); //创建自绘PushButtons hwndSmaller = CreateWindow(TEXT("button"), TEXT(""), WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, BTN_WIDTH, BTN_HEIGHT, hwnd, (HMENU)ID_SMALLER, hInst, NULL); hwndLarger = CreateWindow(TEXT("button"), TEXT(""), WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, BTN_WIDTH, BTN_HEIGHT, hwnd, (HMENU)ID_LARGER, hInst, NULL); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); //移动按钮到新的中心 MoveWindow(hwndSmaller, cxClient / 2 - 3 * BTN_WIDTH / 2, cyClient / 2 - BTN_HEIGHT / 2, BTN_WIDTH, BTN_HEIGHT, TRUE); MoveWindow(hwndLarger, cxClient / 2 + BTN_WIDTH / 2, cyClient / 2 - BTN_HEIGHT / 2, BTN_WIDTH, BTN_HEIGHT, TRUE); return 0; case WM_COMMAND: GetWindowRect(hwnd, &rc); switch (LOWORD(wParam)) { //每次10%放大或缩小窗口 case ID_SMALLER: rc.left += cxClient / 20; //左边缩小5% rc.right -= cxClient / 20; //左边缩小5% rc.top += cyClient / 20; //上边缩小5% rc.bottom -= cyClient / 20; //下边缩小5% break; case ID_LARGER: rc.left -= cxClient / 20; //左边扩大5% rc.right += cxClient / 20; //左边扩大5% rc.top -= cyClient / 20; //上边扩大5% rc.bottom += cyClient / 20; //下边扩大5% break; } MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); return 0; case WM_DRAWITEM: pdis = (LPDRAWITEMSTRUCT)lParam; //画白色矩形和黑色边框 FillRect(pdis->hDC, &pdis->rcItem, GetStockObject(WHITE_BRUSH)); FrameRect(pdis->hDC, &pdis->rcItem, GetStockObject(BLACK_BRUSH)); //画向内和向外的黑三角形 cx = pdis->rcItem.right - pdis->rcItem.left; cy = pdis->rcItem.bottom - pdis->rcItem.top; switch (pdis->CtlID) { case ID_SMALLER: //上边的三角形 pt[0].x = 3 * cx / 8; pt[0].y = 1 * cy / 8; pt[1].x = 5 * cx / 8; pt[1].y = 1 * cy / 8; pt[2].x = 4 * cx / 8; pt[2].y = 3 * cy / 8; Triangle(pdis->hDC, pt); //下边的三角形 pt[0].x = 4 * cx / 8; pt[0].y = 5 * cy / 8; pt[1].x = 5 * cx / 8; pt[1].y = 7 * cy / 8; pt[2].x = 3 * cx / 8; pt[2].y = 7 * cy / 8; Triangle(pdis->hDC, pt); //左边的三角形 pt[0].x = 1 * cx / 8; pt[0].y = 3 * cy / 8; pt[1].x = 3 * cx / 8; pt[1].y = 4 * cy / 8; pt[2].x = 1 * cx / 8; pt[2].y = 5 * cy / 8; Triangle(pdis->hDC, pt); //右边的三角形 pt[0].x = 5 * cx / 8; pt[0].y = 4 * cy / 8; pt[1].x = 7 * cx / 8; pt[1].y = 3 * cy / 8; pt[2].x = 7 * cx / 8; pt[2].y = 5 * cy / 8; Triangle(pdis->hDC, pt); break; case ID_LARGER: //上边的三角形 pt[0].x = 4 * cx / 8; pt[0].y = 1 * cy / 8; pt[1].x = 5 * cx / 8; pt[1].y = 3 * cy / 8; pt[2].x = 3 * cx / 8; pt[2].y = 3 * cy / 8; Triangle(pdis->hDC, pt); //下边的三角形 pt[0].x = 3 * cx / 8; pt[0].y = 5 * cy / 8; pt[1].x = 5 * cx / 8; pt[1].y = 5 * cy / 8; pt[2].x = 4 * cx / 8; pt[2].y = 7 * cy / 8; Triangle(pdis->hDC, pt); //左边的三角形 pt[0].x = 1 * cx / 8; pt[0].y = 4 * cy / 8; pt[1].x = 3 * cx / 8; pt[1].y = 3 * cy / 8; pt[2].x = 3 * cx / 8; pt[2].y = 5 * cy / 8; Triangle(pdis->hDC, pt); //右边的三角形 pt[0].x = 5 * cx / 8; pt[0].y = 3 * cy / 8; pt[1].x = 7 * cx / 8; pt[1].y = 4 * cy / 8; pt[2].x = 5 * cx / 8; pt[2].y = 5 * cy / 8; Triangle(pdis->hDC, pt); break; } //选中时,反转矩形 if (pdis->itemState & ODS_SELECTED) InvertRect(pdis->hDC, &pdis->rcItem); //按钮获得焦点时画虚线框 if (pdis->itemState & ODS_FOCUS) { pdis->rcItem.left += cx / 16; pdis->rcItem.top += cy / 16; pdis->rcItem.right -= cx / 16; pdis->rcItem.bottom -= cy / 16; DrawFocusRect(pdis->hDC, &pdis->rcItem); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
9.3 静态类
(1)创建:CreateWindow中的参数——“static”
(2)静态窗口的样式
样式 |
说明 |
SS_BLACKRECT/SS_BLACKFRAME |
填充矩形或画边框,分别对应的系统颜色为COLOR_3DDSHADOW、COLOR_BTNSHADOW、COLOR_BTNHIGHLIGHT。在CreateWindow调用的窗口文本字段将被忽略(因为被填充了)。坐标是相对于父窗口的 |
SS_GRAYRECT / SS_GRAYRECT |
|
SS_WHITERECT/SS_WHITEFRAME |
|
SS_ETCHEDHORZ |
用白色和灰色,建立一个边框,并将顶端边框设置为浮雕风格 |
SS_ETCHEDVERT |
用白色和灰色,建立一个边框,并将左侧边框设置为浮雕风格 |
SS_ETCHEDFRAME |
建立一个浮雕边框(阴影边框) |
SS_LEFT |
文本的对齐方式,相应的文本由CreateWindow的文本参数指定,可通过SetWindowsText修改。窗口过程内部使用DrawText函数带DT_WORDBREAK、DT_NOCLIP、DT_EXPANDTABS参数来显文本 |
SS_RIGHT |
|
SS_CENTER |
|
SS_ICON |
作为子窗口控件时,该样式是无意义的。 |
SS_USERITEM |
(3)消息
①不接受鼠标和键盘输入,也不向父窗口发送WM_COMMAND消息
②单击时子窗口捕获WM_NCHITTEST,并返回HTTRANSPARENT,导致Windows向底层窗口发送相同的WM_NCHITTEST消息,通常父窗口将该消息传给DefWindowProc,在那里会转换为客户区的鼠标消息。
标签:
原文地址:http://www.cnblogs.com/5iedu/p/4658941.html