#include <windows.h> #include <math.h> #define NUM 1000 #define TWOPI (2*3.14159) LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hInstance, //当前实例句柄 HINSTANCE hPrevInstance, //先前实例句柄 LPSTR lpCmdLine, //命令行 int iCmdShow) //显示状态 { static TCHAR szAppName[] = TEXT("Bezier"); //窗口句柄 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.lpszMenuName = NULL; //窗口类名 wndclass.lpszClassName = szAppName; //注册窗口 if(!RegisterClass(&wndclass)) { return -1; } //创建窗口 hwnd = CreateWindow(szAppName, //窗口类的名称,必须是已经注册的 TEXT("贝塞尔函数"), //窗口标题 WS_OVERLAPPEDWINDOW, //窗口风格 CW_USEDEFAULT, //X坐标 CW_USEDEFAULT, //Y坐标 CW_USEDEFAULT, //宽度 CW_USEDEFAULT, //高度 NULL, //父窗口句柄 NULL, //菜单窗口句柄 hInstance, //高级版本的windos忽略 NULL); //显示窗口 //ShowWindow(hwnd,SW_SHOWNA); ShowWindow (hwnd, iCmdShow); //更新窗口 UpdateWindow(hwnd); //消息循环 while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); //将消息给窗口 DispatchMessage(&msg); } return msg.wParam; } void DrawBezier(HDC hdc,POINT apt[]) { //调用系统的绘制贝塞尔函数 PolyBezier(hdc,apt,4); MoveToEx(hdc,apt[0].x,apt[0].y,NULL); LineTo (hdc,apt[1].x,apt[1].y); MoveToEx(hdc,apt[2].x,apt[2].y,NULL); LineTo (hdc,apt[3].x,apt[3].y); } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; int i,j; static int cxClient,cyClient; static POINT apt[4] ; switch(message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); //4个点分别是起点,第一控制点,第二控制点。终点 apt[0].x = cxClient / 4 ; apt[0].y = cyClient / 2 ; apt[1].x = cxClient / 2 ; apt[1].y = cyClient / 4 ; apt[2].x = cxClient / 2 ; apt[2].y = 3 * cyClient / 4 ; apt[3].x = 3 * cxClient / 4 ; apt[3].y = cyClient / 2 ; return 0; case WM_LBUTTONDOWN: case WM_RBUTTONUP: case WM_MOUSEMOVE: //左键或者右键均可画图 if(wParam & MK_LBUTTON || wParam & MK_RBUTTON) { hdc = GetDC(hwnd); //用白笔 SelectObject(hdc,GetStockObject(WHITE_PEN)); //自定义的画贝叶斯曲线的函数 DrawBezier (hdc,apt); //左键控制第一控制点 if(wParam & MK_LBUTTON) { apt[1].x = LOWORD(lParam); apt[1].y = HIWORD(lParam); } //右键控制第二控制点 if(wParam & MK_RBUTTON) { apt[2].x = LOWORD(lParam); apt[2].y = HIWORD(lParam); } //换成自定义的画笔 SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0))) ; //画曲线 DrawBezier (hdc,apt); ReleaseDC(hwnd,hdc); } return 0; case WM_PAINT: InvalidateRect(hwnd,NULL,TRUE); hdc = BeginPaint(hwnd,&ps); //这一句的目的是为了一开始的时候就有曲线 DrawBezier (hdc, apt) ; EndPaint(hwnd,&ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,message,wParam,lParam); }
在windows中,使用PolyBezier函数绘制贝塞尔曲线。
程序中要注意的是:WM_MOUSEMOVE下的消息处理方式:先用白色的画笔画曲线,再用黑色的画笔画曲线,这样就做出了皮筋一样的效果:第一条曲线实际上是随着鼠标运动而产生的轨迹,不是我们想要的结果,我们想要的是最后移动到位置时的曲线,所以最后才用我们自定义的笔(这里定义为红色,虚线)画图。