zoukankan      html  css  js  c++  java
  • 跟我一起玩Win32开发(10):绘图(C)

    今天我们来欣赏一下用于填充图形的函数,当然我不会逐个去介绍,因为我们参考MSDN直接套参数就可以了。

    SetDCBrushColor函数有必要扯一下,它的声明如下:

    [cpp] view plain copy
     
    1. COLORREF SetDCBrushColor(  
    2.   __in  HDC hdc,  
    3.   __in  COLORREF crColor  
    4. );  

    第二个参数,通过RGB宏产生COLORREF传进去就可以了,比如这样:

    [cpp] view plain copy
     
    1. SetDCBrushColor(ps.hdc,RGB(211,254,41));  

    但是,如果只是调用这个函数,你会发现在绘图的时候,画刷的颜色还是没有变化,因为我们还没有将HBRUSH的默认画刷DC_BRUSH选到DC中去。所以,在调用SetDCBrushColor之前,要把默认的画刷先放到设备上下文,默认画刷可以通过GetStockObject(DC_BRUSH)获得。

    [cpp] view plain copy
     
    1. SelectObject(ps.hdc,GetStockObject(DC_BRUSH));  

    接下来我们可以尝试填充几个图形试试,如矩形、椭圆、饼图等。

    [cpp] view plain copy
     
    1. case WM_PAINT:  
    2.     {  
    3.         BeginPaint(hwnd,&ps);  
    4.         SelectObject(ps.hdc,GetStockObject(DC_BRUSH));  
    5.         SetDCBrushColor(ps.hdc,RGB(0,0,255));  
    6.         Rectangle(ps.hdc,20,18,68,50);  
    7.         SetDCBrushColor(ps.hdc,RGB(220,32,70));  
    8.         Rectangle(ps.hdc,125,100,230,300);  
    9.         SetDCBrushColor(ps.hdc,RGB(30,235,12));  
    10.         Ellipse(ps.hdc,270,80,390,223);  
    11.         SetDCBrushColor(ps.hdc,RGB(35,160,242));  
    12.         Chord(ps.hdc,185,260,420,480,190,260,405,479);  
    13.         SetDCBrushColor(ps.hdc,RGB(211,254,41));  
    14.         Pie(ps.hdc,35,320,300,600,56,470,60,360);  
    15.         EndPaint(hwnd,&ps);  
    16.     }  
    17.     return 0;  


    每一次调用SetDCBrushColor都会改变画刷的颜色,所以,比如你希望绘制蓝色的矩形,在调用Rectangle之前就要调用SetDCBrushColor修改画刷颜色,然后再画矩形。我们可以看看上面代码的最终效果。


     

    下面,我们做一个人类历史上最简单的画图程序。

    我们为程序提供几种可选的线条风格,通过菜单来选择,如实线,虚线等,鼠标按下左键后开始,鼠标左键弹起就完成一条直线的绘制。为了简化,我们把相应菜单的ID设置的值与CreatePen中的线型的宏的值一致。

    这样一来,选择了哪个菜单就直接用这个菜单的ID来创建画笔,就省去了许多代码。

    在响应WM_CREATE消息时,创建菜单。

    [cpp] view plain copy
     
    1. case WM_CREATE:  
    2.     {  
    3.         // 创建菜单  
    4.         HMENU menubar = CreateMenu();  
    5.         HMENU menuPop = CreatePopupMenu();  
    6.         AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_SOLID,L"实线");  
    7.         AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DASH,L"虚线");  
    8.         AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DOT,L"点线");  
    9.         AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DASHDOT,L"点虚线");  
    10.         AppendMenu(menubar, MF_STRING | MF_POPUP, (UINT_PTR)menuPop, L"选择线型");  
    11.         SetMenu(hwnd, menubar);  
    12.     }  
    13.     return 0;  

    现在我们来想一下,绘制直线的大概思路。

    1、鼠标左键按下,记录线条的起点。

    2、鼠标左键弹起时,记录线条的终点,并画出整条线。

    3、当窗口发生重绘时,前面画的所有线条被清除,要希望保留前面画的线条,就要响应WM_PAINT消息,把所有线条重新画一次。

    4、由于我们会在窗口上画出多条线,程序需要定义一个结构体用来保存线条的起点、终点和所使用的线型。

    5、正因为需要保存多条线的数据,故可以把每一条线的相关数据放到一个vector中。

    根据上面的分析,完成程序的代码如下:

    [cpp] view plain copy
     
    1. #include <Windows.h>  
    2. #include <WindowsX.h>  
    3. #include <vector>  
    4.   
    5. using namespace std;  
    6.   
    7. typedef struct tagData  
    8. {  
    9.     int ptBeginX, ptBeginY;//起点  
    10.     int ptEndX, ptEndY;//终点  
    11.     int penStyle;//画笔的线型  
    12. } PAINTDATA;  
    13.   
    14. LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
    15.   
    16. int WINAPI WinMain(  
    17.     HINSTANCE hThisApp,  
    18.     HINSTANCE hPrevApp,  
    19.     LPSTR lpsCmd,  
    20.     int nShow)  
    21. {  
    22.     WNDCLASS wc = {};  
    23.     wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));  
    24.     wc.hInstance = hThisApp;  
    25.     wc.lpfnWndProc = WindowProc;  
    26.     wc.lpszClassName = L"My";  
    27.     wc.style = CS_HREDRAW | CS_VREDRAW;  
    28.     RegisterClass(&wc);  
    29.     HWND hwnd = CreateWindow(  
    30.         L"My",  
    31.         L"应用程序",  
    32.         WS_OVERLAPPEDWINDOW,  
    33.         50,  
    34.         20,  
    35.         600,  
    36.         480,  
    37.         NULL,  
    38.         NULL,  
    39.         hThisApp,  
    40.         NULL);  
    41.     if(hwnd == NULL)  
    42.         return -1;  
    43.     ShowWindow(hwnd, nShow);  
    44.     UpdateWindow(hwnd);  
    45.     MSG msg;  
    46.     while(GetMessage(&msg,NULL,0,0))  
    47.     {  
    48.         TranslateMessage(&msg);  
    49.         DispatchMessage(&msg);  
    50.     }  
    51.     return 0;  
    52. }  
    53.   
    54. LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
    55. {  
    56.     static vector<PAINTDATA> datas;  
    57.     static int penStyle = PS_SOLID;  
    58.     static PAINTDATA *pCurrentData = NULL;//指向当前PAINTDATA的指针  
    59.     switch(msg)  
    60.     {  
    61.     case WM_CREATE:  
    62.         {  
    63.             // 创建菜单  
    64.             HMENU menubar = CreateMenu();  
    65.             HMENU menuPop = CreatePopupMenu();  
    66.             AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_SOLID,L"实线");  
    67.             AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DASH,L"虚线");  
    68.             AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DOT,L"点线");  
    69.             AppendMenu(menuPop,MF_STRING,(UINT_PTR)PS_DASHDOT,L"点虚线");  
    70.             AppendMenu(menubar, MF_STRING | MF_POPUP, (UINT_PTR)menuPop, L"选择线型");  
    71.             SetMenu(hwnd, menubar);  
    72.         }  
    73.         return 0;  
    74.     case WM_COMMAND:  
    75.         {  
    76.             //为选中的菜单加上单选标记  
    77.             HMENU mnbar = GetMenu(hwnd);  
    78.             HMENU hmnPop = GetSubMenu(mnbar, 0);  
    79.             CheckMenuRadioItem(hmnPop, PS_SOLID, PS_DASHDOT, LOWORD(wParam), MF_BYCOMMAND);  
    80.             //记录用户选择的线型  
    81.             penStyle = (int)LOWORD(wParam);  
    82.         }  
    83.         return 0;  
    84.     case WM_LBUTTONDOWN:  
    85.         {  
    86.             pCurrentData = new PAINTDATA;  
    87.             //获取起点  
    88.             pCurrentData ->penStyle = penStyle;  
    89.             pCurrentData->ptBeginX = GET_X_LPARAM(lParam);  
    90.             pCurrentData->ptBeginY = GET_Y_LPARAM(lParam);  
    91.         }  
    92.         return 0;  
    93.     case WM_LBUTTONUP:  
    94.         {  
    95.             if(pCurrentData != NULL)  
    96.             {  
    97.                 //获取终点  
    98.                 pCurrentData->ptEndX = GET_X_LPARAM(lParam);  
    99.                 pCurrentData->ptEndY = GET_Y_LPARAM(lParam);  
    100.                 //画出线条  
    101.                 HDC hdc = GetDC(hwnd);  
    102.                 HPEN pen = CreatePen(pCurrentData->penStyle,1,RGB(0,255,0));  
    103.                 HPEN oldpen = (HPEN)SelectObject(hdc,pen);  
    104.                 MoveToEx(hdc,pCurrentData->ptBeginX,pCurrentData->ptBeginY,NULL);  
    105.                 LineTo(hdc,pCurrentData->ptEndX,pCurrentData->ptEndY);  
    106.                 SelectObject(hdc,oldpen);  
    107.                 DeleteObject(pen);  
    108.                 ReleaseDC(hwnd,hdc);  
    109.                 //把当前数据添加到vector中  
    110.                 datas.push_back(*pCurrentData);  
    111.             }  
    112.         }  
    113.         return 0;  
    114.     case WM_PAINT:  
    115.         {  
    116.             PAINTSTRUCT ps;  
    117.             BeginPaint(hwnd,&ps);  
    118.             //将所有线条重新画一遍  
    119.             vector<PAINTDATA>::const_iterator item;  
    120.             for(item = datas.begin(); item != datas.end(); item++)  
    121.             {  
    122.                 HPEN pen = CreatePen(item->penStyle, 1, RGB(0,255,0));  
    123.                 SelectObject(ps.hdc, pen);  
    124.                 MoveToEx(ps.hdc, item->ptBeginX, item->ptBeginY, NULL);  
    125.                 LineTo(ps.hdc, item->ptEndX, item->ptEndY);  
    126.                 DeleteObject(pen);  
    127.             }  
    128.             EndPaint(hwnd,&ps);  
    129.         }  
    130.         return 0;  
    131.     case WM_DESTROY:  
    132.         PostQuitMessage(0);  
    133.         return 0;  
    134.     default:  
    135.         return DefWindowProc(hwnd,msg,wParam,lParam);  
    136.     }  
    137.     return 0;  
    138. }  


     

    结构体PAINTDATA用来保存每一条线的起点坐标、终点坐标、线型。为了避免在跳出WindowProc后所有数据被回收,可以使用static关键字来声明变量,这样这些变量的生命周期就与整个应用程序相同了。

    运行程序后,在菜单中选择一种线型,然后在窗口上画线,效果如图所示。

  • 相关阅读:
    线程
    开启程序子进程的方式
    multiprocess模块
    计算机网络小知识
    解决粘包问题
    网络编程相关
    反射与元类
    多态相关
    封装相关与接口
    类的继承和组合
  • 原文地址:https://www.cnblogs.com/weekbo/p/8681910.html
Copyright © 2011-2022 走看看