您的位置:首页 > 运维架构 > 网站架构

GDI/GDI+ 绘制网站流量统计报表 总结(4)

2013-08-18 23:28 411 查看
第四讲
绘制矩形、圆和饼图
在上一讲中,我们已经完成了第二个坐标系的绘制,现在需要给每个横坐标绘制上表示数据的矩形框
首先需要在第一个横坐标上绘制一个RGB(78,207,205) 
矩形区域在(480,170,526,316)的一个单色矩形。在这里将采用GDI的方法来绘制,那么绘制矩形包括边框和内部填充两部分,则涉及到画笔和画刷这两部分。那么首先调用CreateSolidBrush来创建一个RGB(78,207,205)的画刷
,因为我们不需要绘制这个矩形的边框,所以需要创建一个空的画笔,然后把画刷和画笔都选入到当前的DC中来,之后调用Rectangle来绘制这个矩形,那么矩形绘制完了之后,第一步就要恢复之前用过的画刷和画笔,即通过SelectObject来选入,然后将不需要用的那个画刷句柄删除掉。那么具体代码如下:
首先声明用来存储老的画刷和画笔的句柄
HBRUSH hBrushOld;
HPEN hPenOlds;
然后创建一个相应的画刷
并选入
HBRUSH hbr= CreateSolidBrush(RGB(78,207,205));
hBrushOld = (HBRUSH)SelectObject(hdc,hbr);
然后创建选入库存空画笔
hPenOlds = (HPEN)SelectObject(hdc,GetStockObject(NULL_PEN));
//调用Rectangle来绘制
Rectangle(hdc,480,170,526,316);
//还原画刷和画笔
SelectObject(hdc,hBrushOld);
SelectObject(hdc,hPenOlds);
//删除不需要的句柄
DeleteObject(hbr);
 
好现在完成了第一个横坐标矩形绘制,接下来完成横坐标第四个坐标上的一个白色填充带黑色边框的矩形的绘制,这个一样的,因为画笔系统默认是黑色,1.0f宽,
所以只需要选择一个库存的白色画笔就可以完成绘制,具体代码如下:
 
hBrushOld = (HBRUSH)::SelectObject(hdc,GetStockObject(WHITE_BRUSH));
Rectangle(hdc, 687,110,733,316);
::SelectObject(hBrushOld);
因为库存的画笔和画刷是不需要我们去销毁的,
所以就完成了矩形的绘制。
 
接下来绘制第二个横坐标上的矩形,是一个渐变矩形,渐变矩形怎么绘制呢?

可以通过构建一个渐变画刷,然后用这个画刷来填充矩形便可。
那么用什么函数来构建一个渐变画刷呢?
这里我们用LinearGradientBrush来构建一个画刷,原型如下:
LinearGradientBrush(
const Point& point1,
const Point& point2,
const Color& color1,
const Color& color2
);
参数point1,
是渐变起始点,渐变从这个点为水平线开始渐变
参数point2,是渐变终止点,渐变到这里终止
color1,渐变点的起始颜色,
color2是渐变点的终止颜色
通过LinearGradientBrush来创建画刷如下:
LinearGradientBrush linGrBrush(Point(550,140),Point(550+47,140+175),Color(255,255,173,0),Color(255,255,0,0));
创建了渐变画笔之后,
还需要创建一个Grahpics对象来使用它,
这里为什么要创建一个Graphics对象来调用它呢?
为什么不是直接用Rectangle来使用呢?
因为LinearGradientBrush是GDI+库中函数不是GDI中的函数,
所以GDI+创建的这个渐变画刷在GDI中不能使用,所以还是来创建Graphics对象吧

Graphics grahpic(hdc);
然后调用FillRectangle()来填充矩形
graphic.FillRectangle(&linGrBrush, 550,140,47,175);
就绘制完了。
那么接下来就要绘制第三个矩形了,
第三个矩形是一个背景图在上面,
那这个怎么绘制呢?

加载图片,然后创建影线画刷填充到矩形中就可以,但是我们现在不用这种方法。首先把要加载的那副图片放到项目的res文件夹下,然后通过加载Bitmap资源在资源管理器中加载上来,然后通过LoadBitmap来加载到内存中来:
HBITMAP hImg = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BITMAP2));
我们最后要把这个图片拷贝到目标DC上的指定的那个矩形区域中,那么我们就还需要知道这个位图的大小,
所以接下来先声明一个位图变量
BITMAP bmp;
然后通过调用GetObject();来获取其大小
GetObject(hImg,sizeof(bmp),&bmp);
然后创建一个与目标DC兼容的内存DC
HDC hMemDC = CreateCompatibleDC(hdc);
接下来将加载进来的位图选入到内存DC中来
HBITMAP =hOldBmp = (HBITMAP)SelectObject(hMemDC,hImg);
然后我们需要通过AlphaBlend来将加载到内存DC上的这张位图混合到目的DC上去,AlphaBlend是用来显示具有指定透明度的图像。其原型如下:
BOOL AlphaBlend(
HDC hdcDest, //handle to destination DC
int nXOriginDest, //x-coord of upper-left corner
int nYOriginDest, //y-coord of upper-left corner
int nWidthDest, //destination width
int nHeightDest, //destination height
HDC hdcSrc, //handle to source DC
int nXOriginSrc, //x-coord of upper left corner
int nYOriginSrc, //y-coord of upper left corner
int nWidthSrc, //source width
int nHeightSrc, //source height
BLENDFUNCTION blendFunction //alpha-blending function
);
前面的参数就不解释了,
参数blendFunction:指定用于源位图和目标位图使用的alpha混合功能,用于整个源位图的全局alpha值和格式信息。源和目标功能当前只限为AC_SRC_OVER。其原型如下:
typedef struct_BLENDFUNCTION{
BYTE BlendOp;
BYTE BlendFlags;
BYTE SourceConstantAlpha;
BYTE AlphaFormat;
}BLENDFUNCTION,*PBLENDFUCNTION,*LPBLENDFUNCTION;
参数BlendOp:
指定源混合操作。目前,唯一的源和目标混合操作被定义为AC_SRC_OVER。

BlendFlags:必须为0.
SourceConstantAlpha:指定用于整张源位图的Alpha透明度值。SourceConstantAlpha值和每个像素的alpha值合并。如果SourceConstantAlpha为0,那么图像就为完全透明;如果为255,则图像为不透明。
AlphaFormat:该成员控制源和目标位图被解释的方式。
我们在这里简单地先定义一个BLENDFUNCTION对象并初始化为0,
然后调用SourceConstantAlpha
设置为不透明值255.
BLENDFUNCTION ble = {0};
ble.SourceConstantAlpha 
= 255;
AlphaBlend(hdc,615,137,bmp.bmWidth,bmp.bmHeight,hMemDC,0,0,bmp.bmWidth,bmp.bmHeight,ble);
这样就完成了图片矩形绘制了,
绘制完了之后,要将原先的位图选入DC,并把不需要的位图句柄和DC销毁掉。
::SelectObject(hMemDC,hOldBmp);
::DeleteObject(hImg);
::DeleteObject(hMemDC);
 
好以上是完成了对第二个坐标系中的4个矩形绘制
下面来完成圆的绘制,
这里需要绘制三个圆,它们相互重叠在一起,并且每个圆上有自己的标题。在GDI中用Ellipse函数来完成圆的绘制,而在GDI+中则可以用FillEllipse来完成一个圆的绘制,在这里前面两个圆采用GDI的方式来绘制,而第三个圆则采用GDI+的方式来绘制。
那么圆的绘制跟矩形的绘制类似,都是分为边框的绘制和内部的填充,
那么同样,创建两个画刷,然后将画刷选入到当前的DC中来,因为不需要画笔来绘制边框,所以选入库存的NULL_PEN
,然后调用Ellipse来绘制。
HBRUSH hBrushOlde;
HPEN hPenOlde;
//创建两个符合要求的画刷
HBRUSH hbrA = CreateSolidBrush(RGB(179,227,255));
HBRUSH hbrB = CreateSolidBrush(RGB(179,227,255));
 
将画刷选入DC
选择一个空画笔,
然后进行绘制,
绘制完之后,恢复画刷
并销毁不需要的画刷
hBrushOlde = (HBRUSH)SelectObject(hdc, hbrA);
hPenOlde = (HPEN)SelectObject(hdc,GetStockObject(NULL_PEN));L
Ellipse(hdc,55,380,55+250,380+250);
然后选入另一个画刷为进行第二圆的绘制做准备
销毁第一个画刷
DeleteObject(hbrA);
 
Ellipse(hdc,125,455,125+160,455+160);
SelectObject(hdc,hBrushOlde);
SelectObject(hdc,hPenOlde);
DeleteObject(hbrB);
那么当现在两个圆都画完了,
接下来画第三个圆,第三个圆我们采用GDI+来绘制
采用GDI+来绘制,同样需要创建一个画刷
SolidBrush BrushA(Color(255,78,190,255));
创建Graphics对象,

Graphics graphice(hdc);
graphice.FillEllipse(&BrushA,176,494,92,92);
那么至此
三个圆已经画完,
但是还要为每个圆绘制上它的标题。
这里先采用TextOut函数来对第一,二两个圆的标题进行绘制
TextOut(hdc,105,450,_T("20-30岁"),6);
TextOut(hdc,168,475,_T("30-40岁"),6);
接下来用GDI+的方式对第三个圆的标题进行绘制:
首先创建需要的字体
Gdiplus::Font myfont(L"Arial",10);
然后创建画刷
SolidBrush brushB(Color(255,255,255,255));
然后调用DrawString函数来进行文本的绘制,原型如下:
Status DrawString(
const WCHAR* string,
INT length,
const Font* font,
const PointF& origin,
const Brush* brush
);
参数string表示要绘制的文本
参数length表示要绘制的文本长度,如果设置为-1
表示显示以null结尾的字符串,
参数font
表示字体的属性
参数origin表示绘制的起始坐标点
参数brush
表示用来填充字体的画刷,
具体代码如下:
graphice.DrawString(L"40+岁",-1,&myfont,PointF(200,525),&brushB);
 
好到此圆也已经绘制完成,F5运行,
发现第一,二圆上的标题有背景色,
需要在TextOut前设置背景模式来解决
::SetBkMode(TRANSPARENT);
就可以解决了。
接下来还有一个饼图需要绘制,那饼图怎么绘制呢?
 饼图在GDI中采用Pie函数来绘制,
而在GDI+中则采用FillPie来绘制
下面先用GDI的方法绘制三个饼图,之后再用GDI+的方法来绘制最后一个饼图
绘制饼图和绘制矩形和圆是类似的,也是需要画笔来绘制边框,画刷来填充内部。
那么同样的
也是创建画刷,选入当前DC
,然后调用Pie函数来绘制,
绘制完了之后,
恢复画刷和画笔,然后把不需要的句柄销毁掉,
整个过程就是这样,
但是我们要绘制四个饼图,每次都要一个个对象去恢复就显得有点麻烦了,这里采用一个函数SaveDC
一次性把所有跟DC相关的属性保存起来,然后需要恢复的时候就一次性恢复,这样就比较简单了,那么下面先调用SaveDC来保存当前的DC
int nSaveDC = SaveDC(hdc);
然后创建三个画刷
HBRUSH hbrAp = CreateSolidBrush(RGB(78,207,255));
HBRUSH hbrBp = CreateSolidBrush(RGB(255,174,0));
HBRUSH hbrCp = CreateSolidBrush(RGB(199,78,255));
因为不需要绘制边框,所以选入一个空画笔
SelectObject(hdc,GetStockObject(NULL_PEN));
 
画刷创建完之后
就需要选入当前DC

//绘制饼A
SelectObject(hdc,hbrAp);
然后调用Pie这个函数来绘制饼图,原型如下:
BOOL Pie(
HDC hdc, //handle to DC
int nLeftRect, //x-coord of upper-left corner of rectangle
int nTopRect, 
//y-coord of upper-left corner of rectangle
int nRightRect, //x-coord of lower-right corner of rectangle
int nBottomRect,//y-coord of lower-right corner of rectangle
int nXRadiall, //x-coord of first radial’s endpoint
int nYRadiall,//y-coord of first radial’s endpoint
int nXRadial2, //x-coord of second radial’s endpoint
int nYRadioal2,//y-coord of second radial’s endpoint
);
参数比较简单,就不解释了
绘制饼A具体代码:
Pie(hdc, 470,390,470+220,390+220,582,391,629,600);
SelectObject(hdc,hbrB);
DeleteObject(hbrA);
 
那么饼图B,和C也是同样绘制
//画-饼ÀyB
Pie(hdc,470,390,470+220,390+220,692,500,582,391);
SelectObject(hdc,hbrC);
DeleteObject(hbrB);
 
//画-饼ÀyC
Pie(hdc,470,390,470+220,390+220,662,578,692,500);
 
绘制完了之后
下面的饼图D就需要采用GDI+方法来绘制了,
在绘制之前,我们先还原DC

RestoreDC(hdc,nSavedDC);
然后删除hbrC这个句柄
然后来绘制饼图D
Graphics graphisp(hdc);
SolidBrush brush(Color(255,156,255,0));
graphicsp.FillPie(&brush,470,390,219,219,40,25);
 
然后绘制上文本
//绘制饼上面的文字
TextOut(hdc,500,510,_T("A"),1);
TextOut(hdc,625,450,_T("B"),1);
TextOut(hdc,650,520,_T("C"),1);
TextOut(hdc,623,559,_T("D"),1);
 
好至此所有图形已绘制完毕。
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...

//Start///////////绘制第二个坐标系中横坐标上的矩形//////////////////
HBRUSH hBrushOld;
HPEN hPenOlds;

//第一个
HBRUSH hbr = CreateSolidBrush(RGB(78,207,205));
hBrushOld =(HBRUSH)::SelectObject(hdc,hbr);
hPenOlds = (HPEN)::SelectObject(hdc,GetStockObject(NULL_PEN));
Rectangle(hdc,480,170,526,316);
::SelectObject(hdc,hPenOlds);
::SelectObject(hdc,hBrushOld);
::DeleteObject(hbr);

//第四个
hBrushOld = (HBRUSH)::SelectObject(hdc,GetStockObject(WHITE_BRUSH));
Rectangle(hdc,687,110,733,316);
::SelectObject(hdc,hBrushOld);

//第二个
LinearGradientBrush linGrBrush(Point(550,140),Point(550+47,140+175),Color(255,255,173,0),Color(255,255,0,0));
Graphics graphic(hdc);
graphic.FillRectangle(&linGrBrush,550,140,47,175);

//第三个
HBITMAP hImg =::LoadBitmapW(hInst,MAKEINTRESOURCE(IDB_BITMAP1));

BITMAP bmps;
::GetObjectW(hImg,sizeof(BITMAP),&bmps);

HDC hMemDCs = ::CreateCompatibleDC(hdc);
HBITMAP hOldBmps = (HBITMAP)::SelectObject(hMemDCs,hImg);

BLENDFUNCTION ble= {0};
ble.SourceConstantAlpha = 255;
AlphaBlend(hdc,615,137,bmps.bmWidth,bmps.bmHeight,hMemDCs,0,0,bmps.bmWidth,bmps.bmHeight,ble);
::SelectObject(hMemDCs,hOldBmps);
::DeleteObject(hOldBmps);
::DeleteObject(hMemDCs);

//End/////////绘制第二个坐标系中横坐标上的矩形///////////////////////

//Start//////////绘制三个圆及其标题////////////////////////////////
HBRUSH hBrushOlde;
HPEN hPenOlde;

HBRUSH hbrA = ::CreateSolidBrush(RGB(179,227,255));
HBRUSH hbrB = ::CreateSolidBrush(RGB(128,208,255));

//第一个圆的绘制
hBrushOlde = (HBRUSH)::SelectObject(hdc,hbrA);
hPenOlde = (HPEN)::SelectObject(hdc,GetStockObject(NULL_PEN));
Ellipse(hdc,55,380,55+250,380+250);
::SelectObject(hdc,hbrB);
::DeleteObject(hbrA);

//绘制第二个圆
Ellipse(hdc,125,455,125+160,455+160);
::SelectObject(hdc,hBrushOlde);
::SelectObject(hdc,hPenOlde);
::DeleteObject(hbrB);
::DeleteObject(hBrushOlde);
::DeleteObject(hPenOlde);

//绘制第三个圆
SolidBrush BrushA(Color(255,78,190,255));
Graphics graphice(hdc);
graphice.FillEllipse(&BrushA,176,494,92,92);

//绘制文本
int bks = ::SetBkMode(hdc,TRANSPARENT);
TextOut(hdc,105,450,_T("20-30岁"),6);
TextOut(hdc,168,475,_T("30-40岁"),6);
::SetBkMode(hdc,bks);
Gdiplus::Font myfont(L"Arial",10);
SolidBrush BrushB(Color(255,255,255,255));
graphice.DrawString(L"40+岁",-1,&myfont,PointF(200,525),&BrushB);

//End//////////绘制三个圆及其标题///////////////////////

//Start/////////绘制四个饼图及其标题////////////////////

int nSavedDC = SaveDC(hdc);

HBRUSH hBrushOldp;

HBRUSH hbrAp = CreateSolidBrush(RGB(78,207,255));
HBRUSH hbrBp = CreateSolidBrush(RGB(255,174,0));
HBRUSH hbrCp = CreateSolidBrush(RGB(199,78,255));

//选入空画笔
::SelectObject(hdc,GetStockObject(NULL_PEN));

//绘制饼图A
::SelectObject(hdc,hbrAp);
Pie(hdc,470,390,470+220,390+220,582,391,629,600);
SelectObject(hdc,hbrBp);
DeleteObject(hbrAp);

//画饼B
Pie(hdc,470,390,470+220,390+220,692,500,582,391);
SelectObject(hdc,hbrCp);
DeleteObject(hbrBp);

//画饼C
Pie(hdc,470,390,470+220,390+220,662,578,692,500);

//还原DC
RestoreDC(hdc,nSavedDC);

DeleteObject(hbrCp);

//画饼D
Graphics  graphicsp(hdc);
SolidBrush brush(Color(255,156,255,0));
graphicsp.FillPie(&brush,470,390,219,219,40,25);

//绘制饼上面的文字
TextOut(hdc,520,490,_T("A"),1);
TextOut(hdc,625,450,_T("B"),1);
TextOut(hdc,650,520,_T("C"),1);
TextOut(hdc,623,559,_T("D"),1);

//End//////////绘制四个饼图及其标题/////////////

EndPaint(hWnd, &ps);
break;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: