<2017年12月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

跟我一起玩Win32开发(9):绘图(B)

我们今天继续涂鸦,实践证明,涂鸦是人生一大乐趣。

首先,我们写一个程序骨架子,以便做实验。

[cpp] view plain copy
 
  1. #include <Windows.h>  
  2.   
  3. LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
  4.   
  5. int WINAPI WinMain(  
  6.     HINSTANCE hThisApp,  
  7.     HINSTANCE hPrevApp,  
  8.     LPSTR lpsCmdln,  
  9.     int iShow)  
  10. {  
  11.     WNDCLASS wc;  
  12.     wc.cbClsExtra = 0;  
  13.     wc.cbWndExtra = 0;  
  14.     wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));  
  15.     // 默认光标类型为箭头  
  16.     wc.hCursor = LoadCursor(hThisApp, IDC_ARROW);  
  17.     // 默认应用程序图标  
  18.     wc.hIcon = LoadIcon(hThisApp, IDI_APPLICATION);  
  19.     wc.hInstance = hThisApp;  
  20.     wc.lpfnWndProc = MainWinProc;  
  21.     wc.lpszClassName = L"MyAppTest";  
  22.     wc.lpszMenuName = NULL;  
  23.     wc.style = CS_HREDRAW | CS_VREDRAW;  
  24.     // 注册窗口类  
  25.     RegisterClass(&wc);  
  26.     // 创建窗口  
  27.     HWND hwnd = CreateWindow(  
  28.         L"MyAppTest",  
  29.         L"绘画课",  
  30.         /* 使用 WS_VISIBLE 就不用调用ShowWindow了 */  
  31.         WS_VISIBLE | WS_OVERLAPPEDWINDOW,  
  32.         100,  
  33.         45,  
  34.         500,  
  35.         380,  
  36.         NULL,  
  37.         NULL,  
  38.         hThisApp,  
  39.         NULL);  
  40.     // 消息循环  
  41.     MSG msg;  
  42.     while(GetMessage(&msg, NULL, 0, 0))  
  43.     {  
  44.         TranslateMessage(&msg);  
  45.         DispatchMessage(&msg);  
  46.     }  
  47.     return 0;  
  48. }  
  49.   
  50.   
  51. LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  52. {  
  53.     switch(msg)  
  54.     {  
  55.     case WM_DESTROY:  
  56.         PostQuitMessage(0);  
  57.         return 0;  
  58.     case WM_PAINT:  
  59.         PAINTSTRUCT ps;  
  60.         BeginPaint(hwnd, &ps);  
  61.                 /* 
  62.                     待实现 
  63.                 */  
  64.         EndPaint(hwnd, &ps);  
  65.         return 0;  
  66.     }  
  67.     return DefWindowProc(hwnd, msg, wParam, lParam);  
  68. }  

 

 CreatePen函数

我们要进行素描画创作,所以我们必须想清楚要使用什么样的钢笔,画出什么样的线条。故,画图之前得创建一支钢笔,不然,巧妇难为无米之炊。

[cpp] view plain copy
 
  1. HPEN  CreatePen(  
  2.       int iStyle, //钢笔的样式,如虚线、实线  
  3.       int cWidth, //线条宽度  
  4.       COLORREF color //线条是啥颜色的  
  5. );  

第一个参数指定线条的样式,如

[cpp] view plain copy
 
  1. /* Pen Styles */  
  2. #define PS_SOLID            0  
  3. #define PS_DASH             1       /* -------  */  
  4. #define PS_DOT              2       /* .......  */  
  5. #define PS_DASHDOT          3       /* _._._._  */  
  6. #define PS_DASHDOTDOT       4       /* _.._.._  */  
  7. #define PS_NULL             5  
  8. #define PS_INSIDEFRAME      6  
  9. #define PS_USERSTYLE        7  
  10. #define PS_ALTERNATE        8  

函数成功创建钢笔后就会返回HPEN,H开头的你就要知道它表示句柄。Pen也是系统资源,所以创建笔后系统要为它一个标识。

 

SelectObject函数

上过美术课,你会知道,有了用于进行素描创作的钢笔还不能动手干活,我们还需要有纸。接下来,调用SelectObject函数,把刚才创建的钢笔与绘图纸关联,就等于把我们创建的绘图资源放进DC工具箱中,

[cpp] view plain copy
 
  1. HGDIOBJ WINAPI SelectObject(  
  2. HDC hdc, //设备描述表的句柄  
  3. HGDIOBJ h //要放到DC中的资源的句柄  
  4. );  

调用成功后,返回原先的资源句柄。

 

MoveToEx和LineTo

MoveToEx是设置绘制的起点,下次绘图将从这个点开始。它的最后一个参数将被设置为当前点,即Move后的坐标。LineTo从当前坐标开始,到指定坐标之间绘制一条线段。

[cpp] view plain copy
 
  1. // 创建钢笔  
  2. HPEN pen = CreatePen(PS_DASH, 1, RGB(0,255,50));  
  3. // 把笔选到DC中  
  4. SelectObject(ps.hdc, pen);  
  5. // 设定线段的起点  
  6. MoveToEx(ps.hdc, 15, 25, NULL);  
  7. // 绘制线条  
  8. LineTo(ps.hdc, 65, 49);  
  9. LineTo(ps.hdc, 12, 120);  
  10. LineTo(ps.hdc, 250, 78);  
  11. LineTo(ps.hdc, 312, 185);  
  12. DeleteObject(pen);  


记住,只要是我们创建的句柄,用完后调用DeleteObject函数将其销毁。


 

PolyBezier函数和PolyBezierTo函数

两个函数都是用来绘制贝塞尔曲线的,不同的是,PolyBezier函数包含指定的起点和终点,PolyBezierTo是从当前点开始绘制贝塞尔曲线。

[cpp] view plain copy
 
  1. // 绘制贝塞尔曲线  
  2. pen = CreatePen(PS_DOT, 1, RGB(0,3,255));  
  3. SelectObject(ps.hdc, pen);  
  4. POINT* pts = new POINT[4];  
  5. pts[0].x = 421;  
  6. pts[0].y = 16;  
  7. pts[1].x = 7;  
  8. pts[1].y = 197;  
  9. pts[2].x = 480;  
  10. pts[2].y = 320;  
  11. pts[3].x = 30;  
  12. pts[3].y = 350;  
  13. PolyBezier(ps.hdc, pts, 4);  
  14. delete [] pts;  
  15. // 第二段贝塞尔曲线  
  16. POINT* pts2 = new POINT[3];  
  17. pts2[0].x = 176;  
  18. pts2[0].y = 84;  
  19. pts2[1].x = 17;  
  20. pts2[1].y = 247;  
  21. pts2[2].x = 400;  
  22. pts2[2].y = 490;  
  23. // 移动当前点  
  24. MoveToEx(ps.hdc, 395, 270, NULL);  
  25. PolyBezierTo(ps.hdc, pts2, 3);  
  26. delete [] pts2;  



 

 

 PolyPolyline绘制复合线条

PolyPolyline函数可以绘制多段复合线条。它的声明如下:

[cpp] view plain copy
 
  1. BOOL PolyPolyline(  
  2.   HDC hdc,  
  3.   const POINT *lppt,  
  4.   const DWORD *lpdwPolyPoints,  
  5.   DWORD cCount  
  6. );  


 lppt参数指向一个POINT的数组,它包含绘制复合线条所需的所有点;lpdwPolyPoints指向一个数组,这个数字数组指明如何分配点数组。

例如,lppt有7个点,我计划,前2个点绘制第一条线,接着3个点绘制第二条线,最后2个点绘制第三条线,这样一来,lpdwPolyPolyPoints得值应为:

{  2, 3, 2 }

nCount里包含lpdwPolyPolyPoints中的数量,我们上面的例子是3.

由于两点决定一条线段,因此,lpdwPolyPolyPoints里面的值记得要>=2。

 

[cpp] view plain copy
 
  1. // 复杂图形  
  2. pen = CreatePen(PS_DASHDOTDOT, 1, RGB(80,20,160));  
  3. SelectObject(ps.hdc, pen);  
  4. POINT plpts[10] =  
  5. {  
  6.     {47,3}, {11,46}, {28,199}, {203,305}, {94,22},  
  7.     {402,377}, {21,45}, {237,7}, {300,398}, {175,25}  
  8. };  
  9. DWORD arr[4] = { 2, 3, 3, 2};  
  10. PolyPolyline(ps.hdc, &plpts[0], &arr[0], 4);  

上面的代码将画出以下图形。

 

 完整的代码清单如下:

[cpp] view plain copy
 
    1. #include <Windows.h>  
    2.   
    3. LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
    4.   
    5. int WINAPI WinMain(  
    6.     HINSTANCE hThisApp,  
    7.     HINSTANCE hPrevApp,  
    8.     LPSTR lpsCmdln,  
    9.     int iShow)  
    10. {  
    11.     WNDCLASS wc;  
    12.     wc.cbClsExtra = 0;  
    13.     wc.cbWndExtra = 0;  
    14.     wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));  
    15.     // 默认光标类型为箭头  
    16.     wc.hCursor = LoadCursor(hThisApp, IDC_ARROW);  
    17.     // 默认应用程序图标  
    18.     wc.hIcon = LoadIcon(hThisApp, IDI_APPLICATION);  
    19.     wc.hInstance = hThisApp;  
    20.     wc.lpfnWndProc = MainWinProc;  
    21.     wc.lpszClassName = L"MyAppTest";  
    22.     wc.lpszMenuName = NULL;  
    23.     wc.style = CS_HREDRAW | CS_VREDRAW;  
    24.     // 注册窗口类  
    25.     RegisterClass(&wc);  
    26.     // 创建窗口  
    27.     HWND hwnd = CreateWindow(  
    28.         L"MyAppTest",  
    29.         L"绘画课",  
    30.         /* 使用 WS_VISIBLE 就不用调用ShowWindow了 */  
    31.         WS_VISIBLE | WS_OVERLAPPEDWINDOW,  
    32.         100,  
    33.         45,  
    34.         500,  
    35.         380,  
    36.         NULL,  
    37.         NULL,  
    38.         hThisApp,  
    39.         NULL);  
    40.     // 消息循环  
    41.     MSG msg;  
    42.     while(GetMessage(&msg, NULL, 0, 0))  
    43.     {  
    44.         TranslateMessage(&msg);  
    45.         DispatchMessage(&msg);  
    46.     }  
    47.     return 0;  
    48. }  
    49.   
    50.   
    51. LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
    52. {  
    53.     switch(msg)  
    54.     {  
    55.     case WM_DESTROY:  
    56.         PostQuitMessage(0);  
    57.         return 0;  
    58.     case WM_PAINT:  
    59.         PAINTSTRUCT ps;  
    60.         BeginPaint(hwnd, &ps);  
    61.         // 创建钢笔  
    62.         HPEN pen = CreatePen(PS_DASH, 1, RGB(0,255,50));  
    63.         // 把笔选到DC中  
    64.         SelectObject(ps.hdc, pen);  
    65.         // 设定线段的起点  
    66.         MoveToEx(ps.hdc, 15, 25, NULL);  
    67.         // 绘制线条  
    68.         LineTo(ps.hdc, 65, 49);  
    69.         LineTo(ps.hdc, 12, 120);  
    70.         LineTo(ps.hdc, 250, 78);  
    71.         LineTo(ps.hdc, 312, 185);  
    72.         // 绘制贝塞尔曲线  
    73.         pen = CreatePen(PS_DOT, 1, RGB(0,3,255));  
    74.         SelectObject(ps.hdc, pen);  
    75.         POINT* pts = new POINT[4];  
    76.         pts[0].x = 421;  
    77.         pts[0].y = 16;  
    78.         pts[1].x = 7;  
    79.         pts[1].y = 197;  
    80.         pts[2].x = 480;  
    81.         pts[2].y = 320;  
    82.         pts[3].x = 30;  
    83.         pts[3].y = 350;  
    84.         PolyBezier(ps.hdc, pts, 4);  
    85.         delete [] pts;  
    86.         // 第二段贝塞尔曲线  
    87.         POINT* pts2 = new POINT[3];  
    88.         pts2[0].x = 176;  
    89.         pts2[0].y = 84;  
    90.         pts2[1].x = 17;  
    91.         pts2[1].y = 247;  
    92.         pts2[2].x = 400;  
    93.         pts2[2].y = 490;  
    94.         // 移动当前点  
    95.         MoveToEx(ps.hdc, 395, 270, NULL);  
    96.         PolyBezierTo(ps.hdc, pts2, 3);  
    97.         delete [] pts2;  
    98.         // 复杂图形  
    99.         pen = CreatePen(PS_DASHDOTDOT, 1, RGB(80,20,160));  
    100.         SelectObject(ps.hdc, pen);  
    101.         POINT plpts[10] =  
    102.         {  
    103.             {47,3}, {11,46}, {28,199}, {203,305}, {94,22},  
    104.             {402,377}, {21,45}, {237,7}, {300,398}, {175,25}  
    105.         };  
    106.         DWORD arr[4] = { 2, 3, 3, 2};  
    107.         PolyPolyline(ps.hdc, &plpts[0], &arr[0], 4);  
    108.         DeleteObject(pen);  
    109.         EndPaint(hwnd, &ps);  
    110.         return 0;  
    111.     }  
    112.     return DefWindowProc(hwnd, msg, wParam, lParam);  
    113. }  
    114.    
posted @ 2018-03-31 13:51  史D芬周  阅读(318)  评论(0编辑  收藏  举报