跟我一起玩Win32开发(10):绘图(C)

摘要:
今天,让我们来欣赏一下用于填充图形的函数。当然,我不会逐一介绍它们,因为我们可以通过引用MSDN直接设置参数。[cpp]viewplaincopycaseWM_PARTIN:{BeginPaint;SelectObject;SetDCBrushColor;矩形;SetDCBrushColor;矩形;每次调用SetDCBrushColor都会更改笔刷的颜色。因此,如果要绘制蓝色矩形,请在调用矩形之前调用SetDCBrushColor修改画笔颜色,然后绘制矩形。接下来,让我们制作人类历史上最简单的绘图程序。响应WM_创建消息时创建菜单。

今天我们来欣赏一下用于填充图形的函数,当然我不会逐个去介绍,因为我们参考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修改画刷颜色,然后再画矩形。我们可以看看上面代码的最终效果。

跟我一起玩Win32开发(10):绘图(C)第1张


 

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

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

跟我一起玩Win32开发(10):绘图(C)第2张

这样一来,选择了哪个菜单就直接用这个菜单的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关键字来声明变量,这样这些变量的生命周期就与整个应用程序相同了。

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

跟我一起玩Win32开发(10):绘图(C)第3张

跟我一起玩Win32开发(10):绘图(C)第4张

免责声明:文章转载自《跟我一起玩Win32开发(10):绘图(C)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇数据库(增、删、改、查)用批处理文件删除n天前的文件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java调用Http/Https接口(8,end)OkHttp调用Http/Https接口

OkHttp是一个高效的HTTP客户端,在Android中用的比较多,也可以用在Java中;本文主要介绍OkHttp在java中的使用,文中所使用到的软件版本:Java 1.8.0_191、SpringBoot2.2.1.RELEASE。 1、OkHttp特点 a、支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接b、连接池减少请求延...

OHC Java堆外缓存详解与应用

1、背景   在当前微服务体系架构中,有很多服务例如,在 特征组装 与 排序等场景都需要有大量的数据支撑,快速读取这些数据对提升整个服务于的性能起着至关重要的作用。   缓存在各大系统中应用非常广泛。尤其是业务程序所依赖的数据可能在各种类型的数据库上(mysql、hive 等),那么如果想要获取到这些数据需要通过网络来访问。再加上往往数据量又很庞大,网络传...

【学习】026 Zookeeper

什么Zookeeper Zookeeper是一个分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization)、命名服务(Naming Service)、集群维护(Group Maintenance)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务。ZooKe...

[转载]非常完善的Log4net详细说明

前言此篇文章是我见过写得最好的一片关于Log4Net的文章,内容由简入难,而且面面俱到,堪称入门和精通的佳作,特从懒惰的肥兔的转载过来。 1、概述log4net是.Net下一个非常优秀的开源日志记录组件。log4net记录日志的功能非常强大。它可以将日志分不同的等级,以不同的格式,输出到不同的媒介。本文主要是介绍如何在Visual Studio2008中使...

手把手教学在Springboot中搭建使用Guava cache,包教包会,不会我输一包辣条给你

 guava cache使用简介   概述   缓存是日常开发中经常应用到的一种技术手段,合理的利用缓存可以极大的改善应用程序的性能。   Guava官方对Cache的描述连接   缓存在各种各样的用例中非常有用。例如,当计算或检索值很昂贵时,您应该考虑使用缓存,并且不止一次需要它在某个输入上的值。   缓存ConcurrentMap要小,但不完全相同。最...

WMI获取驱动版本

WMI获取驱动版本 // public string GetDriverVersion(string HardwareID) //找出驱动版本// { // string queryString = "SELECT HardwareID, DriverVersion FROM Win32_PnPSignedDriver"; // SelectQuery s...