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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章