- ابتدا تابعی با نام DrawBorder را برای ترسیم یک مستطیل تعریف می کنیم.
- دقت کنید که از آن جایی که در خارج از پیام WM_PAINT در حال رسم هستیم لذا ابتدا هندل DC یا همان display device context را برای انجام کارهای گرافیکی قسمت client area باید با استفاده از GetDC دریافت کنید و در پایان ترسیم نیز با ReleaseDC آزاد کنید.
- تابع SetROP2 با فلگ R2_NOT باعث می شود مستطیل ما با رنگی معکوس زنگ زمینه در هنگام drag کردن mouse نمایش داده شود.
void DrawBorder(HWND hwnd, POINT ptBeg, POINT ptEnd)
{
HDC hdc ;
hdc = GetDC (hwnd) ;
SetROP2 (hdc, R2_NOT) ;
SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;
ReleaseDC (hwnd, hdc) ;
}
تابع WndProc را همانند مثال قبل برای پیام ها به شکل زیر تغییر دهید:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
HDC hdc ;
PAINTSTRUCT ps ;
static BOOL drawing, drawBox ;
static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd ;
switch (message)
{
case WM_LBUTTONDOWN :
ptBeg.x = ptEnd.x = LOWORD (lParam) ;
ptBeg.y = ptEnd.y = HIWORD (lParam) ;
drawing = TRUE ;
return 0 ;
case WM_MOUSEMOVE :
if (drawing)
{
SetCursor (LoadCursor (NULL, IDC_CROSS)) ;
DrawBorder (hWnd, ptBeg, ptEnd) ; // clean previous drawing
ptEnd.x = LOWORD (lParam) ;
ptEnd.y = HIWORD (lParam) ;
DrawBorder (hWnd, ptBeg, ptEnd) ;
}
return 0 ;
case WM_LBUTTONUP :
if (drawing)
{
DrawBorder (hWnd, ptBeg, ptEnd) ;
ptBoxBeg = ptBeg ;
ptBoxEnd.x = LOWORD (lParam) ;
ptBoxEnd.y = HIWORD (lParam) ;
SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
drawing = FALSE ;
drawBox = TRUE ;
InvalidateRect (hWnd, NULL, TRUE) ;
}
return 0 ;
case WM_PAINT :
hdc = BeginPaint (hWnd, &ps) ;
if (drawBox)
{
SelectObject (hdc, GetStockObject (LTGRAY_BRUSH)) ;
Rectangle (hdc, ptBoxBeg.x, ptBoxBeg.y, ptBoxEnd.x, ptBoxEnd.y) ;
}
if (drawing)
{
SetROP2 (hdc, R2_NOT) ;
SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;
}
EndPaint (hWnd, &ps) ;
return 0 ;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_about:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
پیام های mouse مورد استفاده :
- پیام WM_LBUTTONDOWN وقتی فراخوانی می شود که کلیک چپ mouse زده می شود.
- پیام WM_MOUSEMOVE وقتی که mouse در حال حرکت می باشد.
لذا با یک متغیر bool تست می کنیم که حتما پیام LBUTTONDOWN مقدار true داشته باشد و سپس عملیات انجام شود.
- پیام WM_LBUTTONUP وقتی کلیک چپ mouse آزاد می شود
پس از پایان این پیام تابع InvalidateRect را فراخوانی می کنیم تا با رفرش کردن تصویر در قسمت WM_PAINT ترسیم نهایی مستطیل انجام شود (متغیر drawBox وقتی true می شود)
- با استفاده از lParam های در پیام های mouse مختصات x و y را دریافت می کنیم.
- تابع SetCursor نشان mosue را به یک شکل دیگر مانند + تغییر می دهد.
سورس کد پروژه ضمیمه شد
موفق باشید