Windows编程(一)画一只哆啦A梦 您所在的位置:网站首页 哆啦a梦怎么画的过程 Windows编程(一)画一只哆啦A梦

Windows编程(一)画一只哆啦A梦

2024-02-14 22:17| 来源: 网络整理| 查看: 265

 本文为一Windows编程API绘图实战小例子,学习自哔哩哔哩小甲鱼的《Windows程序设计SDK》。最终效果展示:

源码在最后,跟着小甲鱼老师敲一遍代码,这些API能记住不少。 

一、大体脉络

二、相关知识细则(来自鱼C工作室) 1.WM_SIZE 消息 消息含义: 当主窗口的客户区部分大小改变时,操作系统将给应用程序发送 WM_SIZE 消息应用程序通过窗口过程接收该消息 消息定义: #define WM_SIZE                         0x0005 参数解析: wParam:指出窗口的新状态wParam 参数可以是下列值之一: 值含义SIZE_MAXHIDE(4)当该应用程序的其他窗口被最大化的时候,消息被发送往所有的弹出窗口SIZE_MAXIMIZED(2)该窗口被最大化SIZE_MAXSHOW(3)当该应用程序的其他窗口已经恢复到原来大小的时候,消息被发送往所有的弹出窗口SIZE_MINIMIZED(1)该窗口被最小化SIZE_RESTORED(0)该窗口的大小发生变化,但不是最大化(SIZE_MAXIMIZED)或最小化(MINIMIZED) lParam:指出当前客户区的大小(宽度和高度) lParam 参数的低 16 位指定了新窗口的宽度;lParam 参数的高 16 位制定了新窗口的高度。 温馨提醒:可以通过 LOWORD 宏和 HIWORD 宏来获取 lParam 参数的低 16 位和高 16 位。返回值:如果窗口过程响应该消息,必须返回 0。 2.RGB宏 宏功能: RGB 宏有三个参数(byRed, byGreen, byBlue),功能是将这三个参数转换为 COLORREF 颜色值。注释:COLORREF 颜色被定义为 DWORD 类型(4 个字节),用于表示 RGB 颜色。 宏原型: COLORREF RGB(    BYTE byRed,    BYTE byGreen,    BYTE byBlue ); 参数解析: 参数含义byRed红色的颜色值byGreen绿色的颜色值byBlue蓝色的颜色值 小甲鱼忍不住罗嗦补充一句:色彩中不能再分解的基本色称之为原色,红绿蓝即三原色,将它们按照不同比例混合,可以搭配出所有的颜色。返回值:返回三个参数转换后的 COLORREF 颜色值备注: 每个颜色可以指定的颜色值是 0 ~ 255,三个参数同时为 0,即黑色,同时为 255 即白色。 通过 GetRValue、GetGValue 和 GetBValue 宏可以分别从 COLORREF 颜色值中获得红色、绿色、蓝色的颜色值。 3.LOWORD 和 HIWORD 宏 宏功能: 获得指定 32 位数据的低 16 位数据和高 16 位数据。小甲鱼温馨提醒:不要使用 LOWORD 和 HIWORD 宏去获取鼠标的坐标,因为在多显示器的情况下会得到错误的坐标。应该使用 GET_X_LPARAM 和 GET_Y_LPARAM 宏来获取。 宏定义: WORD LOWORD(    DWORD dwValue ); …… WORD HIWORD(    DWORD dwValue ); 参数解析: 参数含义lParam32 位的目标数据 返回值: LOWORD(lParam) 返回 lParam 的低 16 位数据;HIWORD(lParam) 返回 lParam 的高 16 位数据。 4.POINT 结构 POINT 结构定义了一个点的 x 坐标和 y 坐标。结构原型: typedef struct tagPOINT {   LONG x;   LONG y; } POINT, *PPOINT; 成员解析: 成员含义x被定义的点的 x 坐标y被定义的点的 y 坐标 5.MoveToEx 函数功能:MoveToEx 函数将当前绘图位置移动到某个具体的点,同时也可获得之前位置的坐标。API 函数原型:注释:_In_ 说明该参数是输入的,_opt_ 说明该参数是可选参数。 BOOL MoveToEx(   _In_   HDC hdc,   _In_   int X,   _In_   int Y,   _Out_  LPPOINT lpPoint ); 参数解析: 参数含义hdc指定设备环境句柄X指定新位置的 X 轴坐标,按逻辑单位表示坐标Y指定新位置的 Y 轴坐标,按逻辑单位表示坐标lpPoint1. 一个 POINT 结构的指针,用于获得之前位置的坐标 2. 如果这个值是 NULL,则不会获得之前位置的坐标 返回值: 如果函数调用成功,返回值是非 0;如果函数调用失败,返回值是 0。 备注: MoveExTo 函数将影响所有的绘图函数。在默认的设备环境中,点 (0, 0) 为最初设定的当前位置。 6.LineTo 函数功能: LineTo 函数使用当前画笔绘制一条线,线段从当前位置连到一个指定的点 (x, y)。当这个函数调用完毕后,当前位置变成 (x, y)。小甲鱼提示:所绘制的线段并不包含指定的点 (x, y)。 ​​​​​​API 函数原型:注释:_In_ 说明该参数是输入的,_opt_ 说明该参数是可选参数。 BOOL LineTo(   _In_  HDC hdc,   _In_  int nXEnd,   _In_  int nYEnd ); 参数解析: 参数含义hdc指定设备环境句柄nXEnd1. 线段终点X坐标位置,采用逻辑坐标表示。 2. 这个点不会实际画出来,因为它不属于线段的一部份nYEnd1. 线段终点Y坐标位置,采用逻辑坐标表示。 2. 这个点不会实际画出来,因为它不属于线段的一部份 返回值: 如果函数调用成功,返回值是非 0;如果函数调用失败,返回值是 0。 7.Rectangle 函数功能: Rectangle 函数用于绘制一个矩形。该矩形用当前画笔绘制轮廓,用当前画刷填充。

API 函数原型:注释:_In_ 说明该参数是输入的。 BOOL Rectangle(   _In_  HDC hdc,   _In_  int xLeft,   _In_  int yTop,   _In_  int xRight,   _In_  int yBottom ); 参数解析: 参数含义hdc指定设备环境句柄xLeft指定矩形左上角的逻辑 x 坐标yTop指定矩形左上角的逻辑 y 坐标xRight指定矩形右下角的逻辑 x 坐标yBottom指定矩形右下角的逻辑 y 坐标 返回值: 如果函数调用成功,返回值是非 0;如果函数调用失败,返回值是 0。 备注:  该函数既不使用当前位置,也不修改当前位置。写过图形程序的程序员通常熟悉边界偏差(off-by-one)的问题:一些图形程序系统画出的图形包含了右坐标和底坐标表示的点,一些则只画到右坐标和底坐标表示的点之前的一点。Windows 使用后一种方法。如果使用 PS_NULL 画笔,则矩形的尺寸高和宽比实际少一个像素。 8.Ellipse 函数功能: Ellipse 函数用于绘制一个椭圆,椭圆的中心是限定矩形的中心。该椭圆用当前画笔绘制轮廓,用当前画刷填充。

 API 函数原型:注释:_In_ 说明该参数是输入的。 BOOL Ellipse(   _In_  HDC hdc,   _In_  int xLeft,   _In_  int yTop,   _In_  int xRight,   _In_  int yBottom ); 参数解析: 参数含义hdc指定设备环境句柄xLeft指定椭圆限定矩形左上角的逻辑 x 坐标yTop指定椭圆限定矩形左上角的逻辑 y 坐标xRight指定椭圆限定矩形右下角的逻辑 x 坐标yBottom指定椭圆限定矩形右下角的逻辑 y 坐标 返回值: 如果函数调用成功,返回值是非 0;如果函数调用失败,返回值是 0。 备注:该函数既不使用当前位置,也不修改当前位置。 9.RoundRect  函数功能: RoundRect 函数用于绘制一个带圆角的矩形。该矩形用当前画笔绘制轮廓,用当前画刷填充。

API 函数原型:注释:_In_ 说明该参数是输入的。 BOOL RoundRect(   _In_  HDC hdc,   _In_  int xLeft,   _In_  int yTop,   _In_  int xRight,   _In_  int yBottom,   _In_  int xCornerEllipse,   _In_  int yCornerEllipse ); 参数解析: 参数含义hdc指定设备环境句柄xLeft指定限定矩形的左上角的逻辑 x 坐标yTop指定限定矩形的左上角的逻辑 y 坐标xRight指定限定矩形的右下角的逻辑 x 坐标yBottom指定限定矩形的右下角的逻辑 y 坐标xCornerEllipse指定用来画圆角的椭圆的宽yCornerEllipse指定用来画圆角的椭圆的高 返回值: 如果函数调用成功,返回值是非 0;如果函数调用失败,返回值是 0。 备注:该函数既不使用当前位置,也不修改当前位置。 10.Arc  函数功能:Arc 函数用于绘制一个椭圆的圆弧。

API 函数原型:注释:_In_ 说明该参数是输入的。 BOOL Arc(   _In_  HDC hdc,   _In_  int xLeft,   _In_  int yTop,   _In_  int xRight,   _In_  int yBottom,   _In_  int xStart,   _In_  int yStart,   _In_  int xEnd,   _In_  int yEnd ); 参数解析: 参数含义hdc指定设备环境句柄xLeft指定限定矩形的左上角的逻辑 x 坐标yTop指定限定矩形的左上角的逻辑 y 坐标xRight指定限定矩形的右下角的逻辑 x 坐标yBottom指定限定矩形的右下角的逻辑 y 坐标xStart指定圆弧开始的逻辑 x 坐标yStart指定圆弧开始的逻辑 y 坐标xEnd指定圆弧结束的逻辑 x 坐标yEnd指定圆弧结束的逻辑 y 坐标 返回值: 如果函数调用成功,返回值是非 0;如果函数调用失败,返回值是 0。 备注: 点 (xLeft, yTop) 和点 (xRight, yBottom) 指定限定矩形的位置。由指定的限定矩形形成的椭圆定义弧的曲线。弧的起始点 (xStart, yStart) 开始和终点 (xEnd, yEnd) 并不在椭圆上,而是定义为在椭圆的中心的延长线上(不懂的鱼油请看上图)。如果椭圆的起始点和终点是同一个点,那么将绘制整个椭圆。 11.Pie 函数功能: Pie 函数绘制一个由弧以及椭圆中心构成的扇形。该扇形用当前画笔绘制轮廓,用当前画刷填充。

API 函数原型:注释:_In_ 说明该参数是输入的。 BOOL Pie(   _In_  HDC hdc,   _In_  int xLeft,   _In_  int yTop,   _In_  int xRight,   _In_  int yBottom,   _In_  int xStart,   _In_  int yStart,   _In_  int xEnd,   _In_  int yEnd ); 参数解析: 参数含义hdc指定设备环境句柄xLeft指定限定矩形的左上角的逻辑 x 坐标yTop指定限定矩形的左上角的逻辑 y 坐标xRight指定限定矩形的右下角的逻辑 x 坐标yBottom指定限定矩形的右下角的逻辑 y 坐标xStart指定圆弧开始的逻辑 x 坐标yStart指定圆弧开始的逻辑 y 坐标xEnd指定圆弧结束的逻辑 x 坐标yEnd指定圆弧结束的逻辑 y 坐标 返回值: 如果函数调用成功,返回值是非 0;如果函数调用失败,返回值是 0。 备注: 扇形对应的曲线(弧)由限定矩形画出的椭圆所指定。曲线(弧)的起始点 (xStart, yStart) 开始和终点 (xEnd, yEnd) 并不在椭圆上,而是定义为在椭圆的中心的延长线上(不懂的鱼油请看上图)。该函数既不使用当前位置,也不修改当前位置。 三、程序源码 #include LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hprevInstance,PSTR szCmdLine,int iCmdShow) { static TCHAR szAppName[] = TEXT("MyWindows"); 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("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("哆啦A梦"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters 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) { HDC hdc; PAINTSTRUCT ps; HPEN hPen, hOldPen; HBRUSH hBlueBrush, hOldBrush, hRedBrush, hYellowBrush; POINT apt[128]; static int cxClient, cyClient; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); //辅助线 hPen = CreatePen(PS_DOT, 1, RGB(192, 192, 192)); hOldPen = SelectObject(hdc, hPen); MoveToEx(hdc, cxClient / 2, 0, NULL); LineTo(hdc, cxClient / 2, cyClient); MoveToEx(hdc, 0, cyClient / 2, NULL); LineTo(hdc, cxClient, cyClient / 2); SelectObject(hdc, hOldPen); //头 直径240 hBlueBrush = CreateSolidBrush(RGB(0, 159, 232)); //借 hOldBrush = SelectObject(hdc, hBlueBrush); Ellipse(hdc, cxClient / 2 - 120, cyClient / 2 - 200, cxClient / 2 + 120, cyClient / 2 + 40); SelectObject(hdc, hOldBrush); //还 //脸 直径200 Ellipse(hdc, cxClient / 2 - 100, cyClient / 2 - 160, cxClient / 2 + 100, cyClient / 2 + 40); //眼睛 长60 宽50 Ellipse(hdc, cxClient / 2 - 50, cyClient / 2 - 180, cxClient / 2, cyClient / 2 - 120); Ellipse(hdc, cxClient / 2 + 50, cyClient / 2 - 180, cxClient / 2, cyClient / 2 - 120); //眼珠 hOldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH)); Ellipse(hdc, cxClient / 2 - 20, cyClient / 2 - 160, cxClient / 2 - 5, cyClient / 2 - 140); Ellipse(hdc, cxClient / 2 + 20, cyClient / 2 - 160, cxClient / 2 + 5, cyClient / 2 - 140); SelectObject(hdc, hOldBrush); hOldBrush = SelectObject(hdc, GetStockObject(WHITE_BRUSH)); Ellipse(hdc, cxClient / 2 - 15, cyClient / 2 - 155, cxClient / 2 - 10, cyClient / 2 - 145); Ellipse(hdc, cxClient / 2 + 15, cyClient / 2 - 155, cxClient / 2 + 10, cyClient / 2 - 145); SelectObject(hdc, hOldBrush); //鼻子 hRedBrush = CreateSolidBrush(RGB(255, 0, 0)); hOldBrush = SelectObject(hdc, hRedBrush); Ellipse(hdc, cxClient / 2 - 10, cyClient / 2 - 135, cxClient / 2 + 10, cyClient / 2 -115); SelectObject(hdc, hOldBrush); MoveToEx(hdc, cxClient / 2, cyClient / 2 - 115, NULL); LineTo(hdc, cxClient / 2, cyClient / 2 - 30); //嘴巴 Arc(hdc, cxClient / 2 - 70, cyClient / 2 - 120, cxClient / 2 + 70, cyClient / 2 - 30, cxClient / 2 - 60, cyClient / 2 - 50, cxClient / 2 + 60, cyClient / 2 - 50); //胡须 中上下 MoveToEx(hdc, cxClient / 2 + 20, cyClient / 2 - 85, NULL); LineTo(hdc, cxClient / 2 + 75, cyClient / 2 - 85); MoveToEx(hdc, cxClient / 2 - 20, cyClient / 2 - 85, NULL); LineTo(hdc, cxClient / 2 - 75, cyClient / 2 - 85); MoveToEx(hdc, cxClient / 2 + 20, cyClient / 2 - 95, NULL); LineTo(hdc, cxClient / 2 + 70, cyClient / 2 - 105); MoveToEx(hdc, cxClient / 2 - 20, cyClient / 2 - 95, NULL); LineTo(hdc, cxClient / 2 - 70, cyClient / 2 - 105); MoveToEx(hdc, cxClient / 2 + 20, cyClient / 2 - 75, NULL); LineTo(hdc, cxClient / 2 + 70, cyClient / 2 - 65); MoveToEx(hdc, cxClient / 2 - 20, cyClient / 2 - 75, NULL); LineTo(hdc, cxClient / 2 - 70, cyClient / 2 - 65); //身体 hOldBrush = SelectObject(hdc, hBlueBrush); Rectangle(hdc, cxClient / 2 - 100, cyClient / 2 - 10, cxClient / 2 + 100, cyClient / 2 + 150); SelectObject(hdc, hOldBrush); //肚皮 Ellipse(hdc, cxClient / 2 - 70, cyClient / 2 - 20, cxClient / 2 + 70, cyClient / 2 + 120);//圆 hPen = CreatePen(PS_DOT, 1, RGB(255, 255, 255));//擦除肚皮上面嘴巴下面的圆弧 hOldPen = SelectObject(hdc, hPen); Arc(hdc, cxClient / 2 - 70, cyClient / 2 - 20, cxClient / 2 + 70, cyClient / 2 + 120, cxClient / 2 + 60, cyClient / 2 - 10, cxClient / 2 - 60, cyClient / 2 - 10); SelectObject(hdc, hOldPen); //围脖 hOldBrush = SelectObject(hdc, hRedBrush); RoundRect(hdc, cxClient / 2 - 102, cyClient / 2 - 12, cxClient / 2 + 102, cyClient / 2 + 5, 20,20); SelectObject(hdc, hOldBrush); //铃铛 hYellowBrush = CreateSolidBrush(RGB(255, 255, 0)); hOldBrush = SelectObject(hdc, hYellowBrush); Ellipse(hdc, cxClient / 2 - 12, cyClient / 2 - 4, cxClient / 2 + 12, cyClient / 2 + 20); RoundRect(hdc, cxClient / 2 - 12, cyClient / 2 + 3, cxClient / 2 + 12, cyClient / 2 + 6, 20, 20); SelectObject(hdc, hRedBrush); Ellipse(hdc, cxClient / 2 - 5, cyClient / 2 + 8, cxClient / 2 + 5, cyClient / 2 + 18); SelectObject(hdc, hOldBrush); //裤腿 Ellipse(hdc, cxClient / 2 - 20, cyClient / 2 + 130, cxClient / 2 + 20, cyClient / 2 + 170);//画圆 hPen = CreatePen(PS_DOT, 1, RGB(255, 255, 255)); //擦除肚皮下面嘴巴上面的圆弧 hOldPen = SelectObject(hdc, hPen); Arc(hdc, cxClient / 2 - 20, cyClient / 2 + 130, cxClient / 2 + 20, cyClient / 2 + 170, cxClient / 2 - 20, cyClient / 2 + 150, cxClient / 2 + 20, cyClient / 2 + 150); SelectObject(hdc, hOldPen); //口袋 Pie(hdc, cxClient / 2 - 50, cyClient / 2, cxClient / 2 + 50, cyClient / 2 + 100, cxClient / 2 - 50, cyClient / 2 + 50, cxClient / 2 + 50, cyClient / 2 + 50); /*Pie(hdc, cxClient / 2 - 50, cyClient / 2, cxClient / 2 + 50, cyClient / 2 + 100, cxClient / 2 - 50, cyClient / 2 + 50, cxClient / 2 + 50, cyClient / 2 + 50); 画弧线时是逆时针的*/ //脚掌 /*Ellipse(hdc, cxClient / 2 - 100, cyClient / 2 + 130, cxClient / 2 - 20, cyClient / 2 + 170); Ellipse(hdc, cxClient / 2 + 20, cyClient / 2 + 130, cxClient / 2 + 100, cyClient / 2 + 170);*/ Ellipse(hdc, cxClient / 2 - 110, cyClient / 2 + 135, cxClient / 2 - 10, cyClient / 2 + 165); Ellipse(hdc, cxClient / 2 + 10, cyClient / 2 + 135, cxClient / 2 + 110, cyClient / 2 + 165); //胳膊 hOldBrush = SelectObject(hdc, hBlueBrush); apt[0].x = cxClient / 2 - 100; apt[0].y = cyClient / 2; apt[1].x = cxClient / 2 - 150; apt[1].y = cyClient / 2 + 60; apt[2].x = cxClient / 2 - 140; apt[2].y = cyClient / 2 + 80; apt[3].x = cxClient / 2 - 100; apt[3].y = cyClient / 2 + 60; //点是按顺序连接的,下面是错误用例 /*apt[0].x = cxClient / 2 - 100; apt[0].y = cyClient / 2; apt[1].x = cxClient / 2 - 150; apt[1].y = cyClient / 2 + 60; apt[3].x = cxClient / 2 - 140; apt[3].y = cyClient / 2 + 80; apt[2].x = cxClient / 2 - 100; apt[2].y = cyClient / 2 + 60;*/ Polygon(hdc, apt, 4); SelectObject(hdc, hOldBrush); Ellipse(hdc, cxClient / 2 - 168, cyClient / 2 + 60, cxClient / 2 - 138, cyClient / 2 + 90); //左手掌 hOldBrush = SelectObject(hdc, hBlueBrush); apt[0].x = cxClient / 2 + 100; apt[0].y = cyClient / 2; apt[1].x = cxClient / 2 + 150; apt[1].y = cyClient / 2 + 60; apt[2].x = cxClient / 2 + 140; apt[2].y = cyClient / 2 + 80; apt[3].x = cxClient / 2 + 100; apt[3].y = cyClient / 2 + 60; Polygon(hdc, apt, 4); SelectObject(hdc, hOldBrush); Ellipse(hdc, cxClient / 2 + 168, cyClient / 2 + 60, cxClient / 2 + 138, cyClient / 2 + 90); //右手掌 //去多余线,增强立体感 hPen = CreatePen(PS_SOLID, 2, RGB(0, 159, 232)); hOldPen = SelectObject(hdc, hPen); MoveToEx(hdc, cxClient / 2 - 100, cyClient / 2, NULL);; LineTo(hdc, cxClient / 2 - 100, cyClient / 2 + 50);; MoveToEx(hdc, cxClient / 2 + 100, cyClient / 2, NULL);; LineTo(hdc, cxClient / 2 + 100, cyClient / 2 + 50); SelectObject(hdc, hOldPen); EndPaint(hwnd,&ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有