第8章计时器
1.计时器使用方法一:
#define TIMER_SEC 1
SetTimer(hwnd,TIMER_SEC,uiMsecInterval,NULL);
KillTimer(hwnd,TIMER_SEC);
2.计时器使用方法二:
/*
*回调函数TimerProc传入的参数:hwnd为SetTimer时的hwnd;message始终为WM_TIMER;
*dwTime是从GetTickCount()函数返回的值。
*/
VOID CALLBACK TimerProc(HWND hwnd,UINT message,UINT iTimerID,DWORD dwTime);
SetTimer(hwnd,TIMER_SEC,iMsecInterval,TimerProc);
3.计时器使用方法三:
/*
*SetTimer和KillTimer的hwnd为NULL,KillTimer的第二个参数为SetTimer的返回值
*/
iTimerID=SetTimer(NULL,0,wMsecInterval,NULL);
KillTimer(NULL,iTimerID);
4.提示音的使用
MessageBeep(-1);
5.获得一个窗口的父窗口的句柄
hwndParent=GetParent(hwnd);
6.获得一个窗口的实例句柄
HINSTANCE hInst=GetWindowLong(hwnd,GWL_HINSTANCE);
第9章子窗口控件
1.创建子窗口控件
#include <windows.h>
struct {
int iStyle;
TCHAR *szText;
}button[] = {
BS_PUSHBUTTON,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("AUTORADIO"),
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.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);//将客户区的背景设为和按键背景的系统色同样的颜色
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("Program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("Button Look"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
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)
{
static HWND hwndButton[NUM];
static RECT rect;
static TCHAR szTop[] = TEXT("message wParam lParam"),
szUnd[] = TEXT("_______ ______ ______"),
szFormat[] = TEXT("%-16s%04X-%04X %04X-%04X"),
szBuffer[50];
static int cxChar, cyChar;
HDC hdc;
PAINTSTRUCT ps;
int i;
switch (message)
{
case WM_CREATE:
cxChar = LOWORD(GetDialogBaseUnits());
cyChar = HIWORD(GetDialogBaseUnits());
for (i = 0;i < NUM;i++)
{
/*
*子控件的创建:
*从左到右的参数说明:类名,窗口文本,窗口样式,x坐标,y坐标,宽度,高度,父窗口,子窗口ID,案例句柄,额外参数。
*子窗口ID的位置原本是用于指定该程序的菜单的,所有它必须转换成HMENU类型;
*在WM_CREATE消息里lParam实际上是一个指向CREATESTRUCT结构的指针,hInstance则是这个结构的一个成员。因此,我们把lParam
*转换为一个指向CREATESTRUCT结构的指针,并从中获得hInstance句柄。
*/
hwndButton[i] = CreateWindow(TEXT("button"), button[i].szText,
WS_CHILD | WS_VISIBLE | button[i].iStyle,
cxChar, cyChar*(1 + 2 * i),
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_PAINT:
InvalidateRect(hwnd, &rect, TRUE);
hdc = BeginPaint(hwnd, &ps);
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_DRAWITEM:
case WM_COMMAND:
ScrollWindow(hwnd, 0, -cyChar, &rect, &rect);
hdc = GetDC(hwnd);
SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));//设置客户区的文本背景颜色为按钮背景的系统色
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));//设置客户区的文本颜色为系统色
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);
if (LOWORD(wParam) == 2)
{
SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)!SendMessage((HWND)lParam, BM_GETCHECK, 0, 0), 0);
}
if (GetWindowLong((HWND)lParam, GWL_ID) == 4)
{
SendMessage((HWND)lParam, BM_SETCHECK, 1, 0);
SendMessage(GetDlgItem(hwnd, 8), BM_SETCHECK, 0, 0);
}
if (GetDlgCtrlID((HWND)lParam) == 8)
{
SendMessage((HWND)lParam, BM_SETCHECK, 1, 0);
SendMessage(GetDlgItem(hwnd, 4), BM_SETCHECK, 0, 0);
}
if (LOWORD(wParam) == 5)
{
SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)((SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) + 1) % 3), 0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
2.获取字符的默认字体的宽度和高度
/*
GetDialogBaseUnits和GetTextMetrics返回类似的数据,但是GetDialogBaseUnits更易于使用,它更利于保持与对话框中的控件的更多的一致性。
*/
cxChar = LOWORD(GetDialogBaseUnits());
cyChar = HIWORD(GetDialogBaseUnits());
3.子窗口传递信息给父窗口WM_COMMAND
LOWORD(wParam)//子窗口的ID
HIWORD(wParam)//通知码
lParam//子窗口句柄
通知码: | 值 |
---|---|
BN_CLICKED | 0 |
BN_PAINT | 1 |
BN_HILITE或BN_PUSHED | 2 |
BN_UNHILITE或BN_UNPUSHED | 3 |
BN_DISABLE | 4 |
BN_DOUBLECLICKED或BN_DBLCLK | 5 |
BN_SETFOCUS | 6 |
BN_KILLFOCUS | 7 |
4.按钮消息
按钮消息 | 值 |
---|---|
BM_GETCHECK | 0x00F0 |
BM_SETCHECK | 0x00F1 |
BM_GETSTATE | 0x00F2 |
BM_SETSTATE | 0x00F3 |
BM_SETSTYLE | 0x00F4 |
BM_CLICK | 0x00F5 |
BM_GETIMAGE | 0x00F6 |
BM_SETIMAGE | 0x00F7 |
SendMessage(hwndButton,BM_SETSTATE,1,0);//设置按钮按下状态
SendMessage(hwndButton,BM_SETSTATE,0,0);//设置按钮正常状态
5.获取子窗口的ID和句柄
id=GetWindowLong(hwndChild,GWL_ID);
id=GetDlgCtrlID(hwndChild);
hwndChild=GetDlgItem(hwndParent,id);
6.改变窗口的文本
SetWindowText(hwnd,pszString);
iLength=GetWindowTextLength(hwnd);
iLength=GetWindowText(hwnd,pszBuffer,iMaxLength);
7.可见的按钮和启用按钮
要接收鼠标和键盘输入,子窗口必须是可见的并且是启用的。如果在创建子窗口时在窗口类中没有包括WS_VISIBLE,子窗口将不会显示,除非调用ShowWindow:
ShowWindow(hwndChild,SW_SHOWNORMAL);//正常显示窗口
ShowWindow(hwndChild,SW_HIDE);//隐藏窗口
IsWindowVisible(hwndChild);//判断窗口是否可见
禁用窗口:
EnableWindow(hwndChild,FALSE);//禁用窗口
EnavleWindow(hwndChild,TRUE);//启用窗口
IsWindowEnable(hwndChild);//判断窗口是否已被启用
8.按钮的输入焦点
在Windows把输入焦点从一个窗口切换到另一个窗口时,它首先会向将要失去输入焦点的窗口发送一条消息WM_KILLFOCUS。相应的wParam参数是将要获得输入焦点的窗口句柄。Windows然后向要接收输入焦点的窗口发送WM_SETFOCUS消息,用wParam指定失去输入焦点的窗口的句柄。(在这两种情况下,wParam都可能是NULL,表明没有窗口具有或正在接收输入焦点)。
SetFocus(hwnd);//调用此函数才能把具体的焦点设置到相应的窗口,调用了SetFocus函数后会发相应,的WM_KILLFOCUS和WM_SETFOCUS消息,注意并没有KillFocus(hwnd)这样的函数。
父窗口可以通过对WM_KILLFOCUS消息的处理来阻止子窗口控件获得输入焦点,在父窗口的消息处理过程函数,处理WM_KILLFOCUS函数:
case WM_KILLFOCUS:
if(hwnd==GetParent((HWND)wParam)
{
SetFocus(hwnd);
}
return 0;
9.控件和颜色
Windows有29种系统颜色来支持各部分的显示
序号 | GetSysColor和SetSysColors | 注册表键值或WIN.INI标识符 | 默认RGB值 |
---|---|---|---|
0 | COLOR_SCROLLBAR | Scrollbar | C0-C0-C0 |
1 | COLOR_BACKGROUND | Background | 00-80-80 |
… | … | … | … |
28 | COLOR_GRADIENTINACTIVECAPTION | GradientInactiveTitle | 80-80-80 |
10.当按钮的背景颜色和客户区的背景颜色不一样时候的解决办法
COLOR_BTNFACE用于按键按钮的主表面颜色和其他按钮的背景颜色。(这也是对话框和消息框使用的系统颜色。)COLOR_BTNSHADOW用在按键按钮的右侧和底部、复选框方块的内部和单选按钮的圆圈内,用来表示阴影。对于按键按钮,COLOR_BTNTEXT用于文本的颜色;其他控件的文本颜色使用的则是COLOR_WINDOWTEXT。
因此,如果我们要在客户区表面显示按钮,一个避免颜色冲突的途径就是使用这些系统颜色。
- 首先,在设计窗口类时,使用COLOR_BTNFACE作为客户区的背景颜色:
改 wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); 为
/*
在Windows中,在WNDCLASS结构中hbrBackground值很低时,它实际上指的是系统颜色,而不是一个实际的句柄。Windows要求在使用这些标识符时,要加上1,并在WNDCLASS结构的hbrBackground字段中加以指定,但这样做并没有什么深远的目的,只是为了防止出现空值(NULL)。
*/
wndclass.hbrBackground=(HBRUSH)(COLOR_BTNFACE+1); - 再次输出文字时不要忘记改变文字的背景色和客户区的背景色一样:
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));//设置客户区的文本背景颜色为按钮背景的系统色;
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));//设置客户区的文本颜色为系统色; - 最后当用户改变了系统颜色可以通过处理WM_SYSCOLORCHANGE消息:
case WM_SYSCOLORCHANGE:
InvalidateRect(hwnd,NULL,TRUE);
break;
11.当子窗口即将重绘其客户区时,按钮控件会发WM_CTLCOLORBTN给父窗口的窗口过程。父窗口可以利用这个机会来改
变子窗口的背景颜色。当父窗口的窗口过程收到WM_CTLCOLORBTN消息时,wParam消息参数是按钮的设备环境的句柄,lParam是按钮的窗口句柄。当在窗口过程中处理WM_CTLCOLORBTN消息时,可以选择以下做法:
- 使用SetTextColor设置文本颜色
- 使用SetBkColot设置文本的背景颜色
- 返回子窗口的画刷句柄
从理论上讲,子窗口使用这个画刷来着色背景。在不再需要画刷时,你需要负责销毁画刷。
#include <windows.h>
#define ID_SMALLER 1
#define ID_LARGER 2
#define BTN_WIDTH (8*cxChar)
#define BTN_HEIGHT (4*cyChar)
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
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 = szAppName;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("Program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("Owner-Draw Button Demo"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
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 int cxClient, cyClient, cxChar, cyChar;
int cx, cy;
LPDRAWITEMSTRUCT pdis;
POINT pt[3];
RECT rc;
switch (message)
{
case WM_CREATE:
cxChar = LOWORD(GetDialogBaseUnits());
cyChar = HIWORD(GetDialogBaseUnits());
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 (wParam)
{
case ID_SMALLER:
rc.left += cxClient / 20;
rc.right -= cxClient / 20;
rc.top += cyClient / 20;
rc.bottom -= cyClient / 20;
break;
case ID_LARGER:
rc.left -= cxClient / 20;
rc.right += cxClient / 20;
rc.top -= cyClient / 20;
rc.bottom += cyClient / 20;
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, (HBRUSH)GetStockObject(WHITE_BRUSH));
FrameRect(pdis->hDC, &pdis->rcItem, (HBRUSH)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 = 7 * cx / 8;pt[0].y = 3 * cy / 8;
pt[1].x = 7 * cx / 8;pt[1].y = 5 * cy / 8;
pt[2].x = 5 * cx / 8;pt[2].y = 4 * cy / 8;
Triangle(pdis->hDC, pt);
pt[0].x = 5 * cx / 8;pt[0].y = 7 * cy / 8;
pt[1].x = 3 * cx / 8;pt[1].y = 7 * cy / 8;
pt[2].x = 4 * cx / 8;pt[2].y = 5 * cy / 8;
Triangle(pdis->hDC, pt);
pt[0].x = 1 * cx / 8;pt[0].y = 5 * cy / 8;
pt[1].x = 1 * cx / 8;pt[1].y = 3 * cy / 8;
pt[2].x = 3 * cx / 8;pt[2].y = 4 * cy / 8;
Triangle(pdis->hDC, pt);
break;
case ID_LARGER:
pt[0].x = 5 * cx / 8;pt[0].y = 3 * cy / 8;
pt[1].x = 3 * cx / 8;pt[1].y = 3 * cy / 8;
pt[2].x = 4 * cx / 8;pt[2].y = 1 * cy / 8;
Triangle(pdis->hDC, pt);
pt[0].x = 5 * cx / 8;pt[0].y = 5 * cy / 8;
pt[1].x = 5 * cx / 8;pt[1].y = 3 * cy / 8;
pt[2].x = 7 * cx / 8;pt[2].y = 4 * 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 = 3 * cx / 8;pt[0].y = 3 * cy / 8;
pt[1].x = 3 * cx / 8;pt[1].y = 5 * cy / 8;
pt[2].x = 1 * cx / 8;pt[2].y = 4 * 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);
}