/*---------------------------------------
BEZIER.C -- Bezier Splines Demo
(c) Charles Petzold, 1998
---------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, 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))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Bezier Splines"),
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 ;
}
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)
{
static POINT apt[4];
HDC hdc;
int cxClient,cyClient;
PAINTSTRUCT ps;
switch(message)
{
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
//这四个点可以结合运行结果来看,更直观
//起点
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_RBUTTONDOWN: //鼠标右键按下
case WM_MOUSEMOVE: //鼠标移动
//对于这三个消息,可以参加MSDN,那里有对这些消息的说明:
//wParam表示哪些鼠标键触发了,LOWORD(lParam),HIWORD(lParam);//低字节保存鼠标当前x坐标,高字节保存y坐标
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);//低字节保存鼠标当前x坐标,高字节保存y坐标,可以重看msdn获取消息
//按下鼠标右键,第二个控制点起作用
apt[1].y = HIWORD(lParam);
}
if(wParam & MK_RBUTTON)
{
apt[2].x = LOWORD(lParam); //低字节保存鼠标当前x坐标,高字节保存y坐标,可以重看msdn获取消息
apt[2].y = HIWORD(lParam);
}
//重新用黑色画笔绘图
SelectObject(hdc,GetStockObject(BLACK_PEN));
DrawBezier(hdc,apt); //可以把这句话注释掉,该为InvalidateRect(hwnd,NULL,TRUE);效果是一样的
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);
}