在SDK中實現畫條直線,畫個矩形等都有現成的函數供我們去調用,有時候直線,矩形畫完之後需要能夠隨滑鼠進行移動進而調整圖形的位置。
不知道該怎麼去表述,就貼代碼吧,代碼中已經添加了很詳細的注釋了。
直接把完整的例子代碼都貼出來吧,這樣最省事了。
// areatest.cpp : 定義應用程式的進入點。//#include "stdafx.h"#include "areatest.h"#include <math.h>#define MAX_LOADSTRING 100// 全域變數:HINSTANCE hInst;// 當前執行個體TCHAR szTitle[MAX_LOADSTRING];// 標題列文本TCHAR szWindowClass[MAX_LOADSTRING];// 主視窗類名// 此代碼模組中包含的函數的前向聲明:ATOMMyRegisterClass(HINSTANCE hInstance);BOOLInitInstance(HINSTANCE, int);LRESULT CALLBACKWndProc(HWND, UINT, WPARAM, LPARAM);INT_PTR CALLBACKAbout(HWND, UINT, WPARAM, LPARAM);int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// TODO: 在此放置代碼。MSG msg;HACCEL hAccelTable;// 初始化全域字串LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_AREATEST, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);// 執行應用程式初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_AREATEST));// 主訊息迴圈:while (GetMessage(&msg, NULL, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return (int) msg.wParam;}//// 函數: MyRegisterClass()//// 目的: 註冊視窗類別。//// 注釋://// 僅當希望// 此代碼與添加到 Windows 95 中的“RegisterClassEx”// 函數之前的 Win32 系統相容時,才需要此函數及其用法。調用此函數十分重要,// 這樣應用程式就可以獲得關聯的// “格式正確的”小表徵圖。//ATOM MyRegisterClass(HINSTANCE hInstance){WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style= CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc= WndProc;wcex.cbClsExtra= 0;wcex.cbWndExtra= 0;wcex.hInstance= hInstance;wcex.hIcon= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_AREATEST));wcex.hCursor= LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName= MAKEINTRESOURCE(IDC_AREATEST);wcex.lpszClassName= szWindowClass;wcex.hIconSm= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassEx(&wcex);}//// 函數: InitInstance(HINSTANCE, int)//// 目的: 儲存執行個體控制代碼並建立主視窗//// 注釋://// 在此函數中,我們在全域變數中儲存執行個體控制代碼並// 建立和顯示主程式視窗。//BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){HWND hWnd;hInst = hInstance; // 將執行個體控制代碼儲存在全域變數中hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;}//// 函數: WndProc(HWND, UINT, WPARAM, LPARAM)//// 目的: 處理主視窗的訊息。//// WM_COMMAND- 處理應用程式菜單// WM_PAINT- 繪製主視窗// WM_DESTROY- 發送退出訊息並返回////LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){//隨便定義2點用來畫線static POINT start={200,200},end={500,500};//儲存滑鼠按下的點static POINT ptButtondown;//儲存滑鼠移動的點static POINT ptMousemove;//判斷是否繪製static bool draw;int wmId, wmEvent;PAINTSTRUCT ps;HDC hdc,hdcMem;HBITMAP hBitmap;static HRGN hrgn;RECT clientrect;switch (message){case WM_COMMAND:wmId = LOWORD(wParam);wmEvent = HIWORD(wParam);// 分析菜單選擇: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_LBUTTONDOWN:{/////////////////////////////////////////////////////每次滑鼠按下,需要銷毀原來的感應地區,重新建立////新的感應地區///////////////////////////////////DeleteObject(hrgn);hrgn=NULL;POINT pointList[4];///////////////////////////////////////////////////////簡單說明一下這裡,由於一條直線是由首位2點組成///////這裡需要給他建立一個感應地區,方便起見,建立一//////個矩形感應地區,簡單的用了勾股定理3,4,5就是建立/////一個寬度為2*5,長度為直線長度的矩形裁剪地區,當鼠////標在此地區按下的時候給予感應,變換滑鼠形狀實施拖////動操作///////////////////////////////////////////pointList[0].x = (int)(start.x-3);pointList[0].y = (int)(start.y+4);pointList[1].x = (int)(start.x+3);pointList[1].y = (int)(start.y-4);pointList[2].x = (int)(end.x-3);pointList[2].y = (int)(end.y+4);pointList[3].x = (int)(end.x+3);pointList[3].y = (int)(end.y-4);//建立直線新位置的感應地區hrgn = CreatePolygonRgn(pointList, _countof(pointList), WINDING);ptButtondown.x=LOWORD(lParam);ptButtondown.y=HIWORD(lParam);if(PtInRegion(hrgn,ptButtondown.x,ptButtondown.y)){OutputDebugString(_T("InRegion"));//設定滑鼠捕獲,讓滑鼠逃不出我視窗的手心控制SetCapture(hWnd);//設定游標為四個方向SetCursor(LoadCursor(NULL,IDC_SIZEALL));draw=true;}}break;case WM_MOUSEMOVE:hdc=GetDC(hWnd);if(draw==false) break;OutputDebugString(_T("Move\n"));SetCursor(LoadCursor(NULL,IDC_SIZEALL));//得到此刻滑鼠移動位置的座標ptMousemove.x=LOWORD(lParam);ptMousemove.y=HIWORD(lParam);//計算新直線的起點跟終點,加上位移start.x=start.x+ptMousemove.x-ptButtondown.x;start.y=start.y+ptMousemove.y-ptButtondown.y;end.x=end.x+ptMousemove.x-ptButtondown.x;end.y=end.y+ptMousemove.y-ptButtondown.y;//在新的位置上畫線MoveToEx(hdc,start.x,start.y,NULL);LineTo(hdc,end.x,end.y);//把當前滑鼠移動位置的座標賦值給ptButtondown,下次計算位移才準確ptButtondown.x=ptMousemove.x;ptButtondown.y=ptMousemove.y;//完成在新的位置繪製直線InvalidateRect(hWnd,NULL,TRUE);ReleaseDC(hWnd,hdc);break;case WM_LBUTTONUP://釋放視窗對滑鼠的捕獲ReleaseCapture(); //改變滑鼠形狀SetCursor(LoadCursor(NULL,IDC_ARROW)); //設定畫線標記draw=false;break;case WM_PAINT:hdc = BeginPaint(hWnd, &ps);// TODO: 在此添加任意繪圖代碼...///////////////////////////如果嫌棄閃爍,可以使用雙緩衝GetClientRect(hWnd,&clientrect);hdcMem=CreateCompatibleDC(hdc);hBitmap=CreateCompatibleBitmap(hdc,clientrect.right,clientrect.bottom);SelectObject(hdcMem,hBitmap);FillRect(hdcMem,&clientrect,NULL);MoveToEx(hdcMem,start.x,start.y,NULL);LineTo(hdcMem,end.x,end.y);BitBlt(hdc,0,0,clientrect.right,clientrect.bottom,hdcMem,0,0,SRCCOPY);DeleteObject(hBitmap);DeleteDC(hdcMem);//////////////////////////////////////////////////////////////////////EndPaint(hWnd, &ps);break;///////////////////////////////////////////////////////////////////////由於把整個背景都重繪了,所以不再需要擦除背景了,預設的擦除背景是用///DefWindowProc(xxx,WM_ERASEBKGND,X,X)做到的,因此在這裡我們主動去告///訴系統我已經處理過了。/////////////////////////////////////////////case WM_ERASEBKGND:return true;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;}// “關於”框的訊息處理常式。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;}
至於矩形,橢圓的移動就不多說了。
給個簡單的運行案例吧。
光棍節要來了。。。。。。。。。
祝各位棍友good luck!!!!