windows 程序设计第七章 鼠标命中测试的心得

//*************************************
//windows程序设计第七章
//程序中的命中测试
//*************************************




#include <Windows.h>
#define DIVISIONS 5


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);
int g_nIdFocus = 0;
TCHAR g_szChildClass[] = TEXT("MySecondExample_Child");


int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
PSTR szCmdLine,int iCmdShow)
{
static TCHAR szAppName[] = TEXT("MySecondExample");
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)(COLOR_WINDOW+1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;


if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("Program requires windows NT!"),szAppName,MB_ICONERROR);
return 0;
}


wndclass.lpfnWndProc = ChildWndProc;
wndclass.cbWndExtra = sizeof(long);                           //预留空间,为之后的消息传递提供内存空间。
wndclass.hIcon = NULL;
wndclass.lpszClassName = g_szChildClass;


RegisterClass(&wndclass);


hwnd = CreateWindow(szAppName,TEXT("Example"),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 hWndChild[DIVISIONS][DIVISIONS];
int         cxBlock,cyBlock,x,y;


switch(message)
{
case WM_CREATE:
for(x=0;x<DIVISIONS;++x)
{
for(y=0;y<DIVISIONS;++y)
{
hWndChild[x][y] = CreateWindow(g_szChildClass,NULL,WS_CHILDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,hwnd,(HMENU)(y<<8 | x),
(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),NULL);
}
}
return 0;
case WM_SIZE:
cxBlock = LOWORD(lParam)/DIVISIONS;
cyBlock = HIWORD(lParam)/DIVISIONS;
for(x=0;x<DIVISIONS;++x)
{
for(y=0;y<DIVISIONS;++y)
{
MoveWindow(hWndChild[x][y],x*cxBlock,y*cyBlock,
cxBlock,cyBlock,TRUE);
}
}
return 0;
case WM_LBUTTONDOWN:
MessageBeep(0);
return 0;
case WM_SETFOCUS:
SetFocus(GetDlgItem(hwnd,g_nIdFocus));
return 0;
case WM_KEYDOWN:
x = g_nIdFocus & 0xFF;
y = g_nIdFocus >> 8;
switch(wParam)
{
case VK_UP:
y--; 
break;
case VK_DOWN:
y++;
break;
case VK_LEFT:
x--;
break;
case VK_RIGHT:
x++;
break;
case VK_HOME:
x = y = 0;
break;
case VK_END:
x = y = DIVISIONS - 1;
break;
default:
return 0;
}
x = (x+DIVISIONS)%DIVISIONS;
y = (y+DIVISIONS)%DIVISIONS;
g_nIdFocus = y << 8 | x;
SetFocus(GetDlgItem(hwnd,g_nIdFocus));
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);


}


LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;


switch(message)
{
case WM_CREATE:
SetWindowLong(hwnd,0,0);
return 0;
case WM_KEYDOWN:
if(wParam != VK_RETURN && wParam != VK_SPACE)
{
SendMessage(GetParent(hwnd),message,wParam,lParam);
return 0;
}
case WM_LBUTTONDOWN:
SetWindowLong(hwnd,0,1^GetWindowLong(hwnd,0/*DWL_MSGRESULT*/));         // GetWindowLong(hwnd,DWL_MSGRESULT)获取在对话框过程中一个消息的返回值,通过设置
SetFocus(hwnd);
InvalidateRect(hwnd,NULL,FALSE);
return 0;
case WM_SETFOCUS:
g_nIdFocus = GetWindowLong(hwnd,GWL_ID);
case WM_KILLFOCUS:
InvalidateRect(hwnd,NULL,TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&rect);                              //获取当前窗口的尺寸大小
Rectangle(hdc,0,0,rect.right,rect.bottom);              //画个矩形


if(GetWindowLong(hwnd,0))                               //通过SetWindowLong(hwnd,0,1^GetWindowLong(hwnd,0/*DWL_MSGRESULT*/));将1^GetWindowLong(hwnd,0/*DWL_MSGRESULT*/)作为
//GetWindowLong(hwnd,0)的返回值,故不停的在0跟1切换
{
MoveToEx(hdc,0,0,NULL);
LineTo(hdc,rect.right,rect.bottom);
MoveToEx(hdc,0,rect.bottom,NULL);
LineTo(hdc,rect.right,0);
}


if(hwnd == GetFocus())
{
rect.left += rect.right/10;
rect.right  -=      rect.left;
rect.top    += rect.bottom/10;
rect.bottom -= rect.top;


SelectObject(hdc,GetStockObject(NULL_BRUSH)); //不需要填充画刷,以免矩形遮挡了线条                
SelectObject(hdc,CreatePen(PS_DASH,0,0)); //创建虚线逻辑画笔
Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom);
DeleteObject(SelectObject(hdc,GetStockObject(BLACK_PEN))); //删除原先创建的画笔
}
EndPaint(hwnd,&ps);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);

}

界面:



以上是源码跟效果图


整个源码的部分流程是这样的:

一开始创建主窗口的时候创建了5*5个子窗口,并在主窗口的WM_SIZE消息里将他们平均分布在主窗口上,这时候其实从界面上还看不出子窗口,需要之后绘制矩形边框才能看出。之所以放在这个消息里是为了使子窗口的大小可以跟着主窗口一起协调变化。当在客户区按下鼠标左键时,由于子窗口覆盖了父窗口,所以响应的是子窗口的WM_LBUTTONDOWN,在子窗口中做了如下操作:

SetWindowLong(hwnd,0,1^GetWindowLong(hwnd,0));      
SetFocus(hwnd);
InvalidateRect(hwnd,NULL,FALSE);

return 0;

首先需要讲解下SetWindowLong和GetWindowLong这两个函数。由于在设置子窗口的参数时wndclass.cbWndExtra = sizeof(long); 已经为子窗口设定了额外的一个参数值,具体可查询cbWndExtra的特性。当setWindowLong的第二个参数为0时,就将他第三个参数的值存在cbWndExtra预留的空间里。当GetWindowLong(hwnd,0)时,便将它以返回值的形式取出来

在子窗口创建的WM_CREATE阶段,已有SetWindowLong(hwnd,0,0),故一开始GetWindowLong(hwnd,0)返回的值为0,再与1异或变为1.然后将1存储到额外空间,等待下一次读出。接下来的SetFocus(hwnd)和InvalidateRect(NULL,NULL,FALSE),触发了自身的WM_SETFOCUS和WM_PAINT消息。由于每次WM_PAINT都是重绘子窗口,所以交叉线会交替出现。

发布了23 篇原创文章 · 获赞 25 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章