我们这里假想搜索引擎市场在某一个时间中的占有比例情况,分别由百度搜索、搜狗搜索、360搜索以及其他搜索,确定的比例是假想的,并不是真实的,模拟一下而已。
我们可以先看看效果图:
Pie就是饼的意思,GDI中将这个函数用作绘制饼状图。Pie函数的声明如下:
BOOL Pie( HDC hdc, // handle to DC
int nLeftRect, // 矩形左上角x坐标
int nTopRect, // 矩形左上角y坐标
int nRightRect, // 矩形右下角x坐标
int nBottomRect, // 矩形右下角y坐标
int nXRadial1, // 第一条从中心到起始弧的线与矩形相交的点的x坐标
int nYRadial1, // 第一条从中心到起始弧的线与矩形相交的点的y坐标
int nXRadial2, // 第二条从中心到起始弧的线与矩形相交的点的x坐标
int nYRadial2 // 第二条从中心到起始弧的线与矩形相交的点的y坐标
Pie函数参数原理图如下:这里的饼状图的一部分就是椭圆的一部分,所以,我们是在画椭圆的一部分,因此需要定义一个椭圆的大小。而椭圆大小的定义是以椭圆外切矩形的左上点和右下点的坐标来定义的。这就是前面四个坐标的矩形坐标的由来。
而饼状图的起始边右椭圆的中心向外射出与椭圆边相交而得,要确定好这个线就可以确定饼状图的一边了。顺势而为,就直接将射线延伸到与矩形相交,这样就更好得到另外一个点,这样就由相交的矩形的一个点和中心点得到了一条直线,直线将椭圆切开,就是饼的一边了。这就是nXRadial1和nYRadial1参数的由来。
Pie函数定义确定第二个边是逆时针旋转的,所以同样找到逆时针旋转后的位置的一个点与椭圆中心连线,与矩形相交一点,来确定最后两个参数。
如此,所有参数就确定了。这是Pie函数的基本参数确定方法。那么要画出完整的饼状图,还需要进一步分析。
为了好看,饼状图一般用圆来画。我们知道圆就是椭圆的一个特例而已,也就是外切的矩形是正方形的时候,所以,我们将外切矩形的右下角的坐标的x和y设置为一样的即可实现绘制圆了。
因为Pie使用默认的白色的画刷来填充饼的内部区域,所以如果窗口是白色的,你看上去我觉得Pie函数只是划线而已。然而你把窗口背景设置为黑色就发现不对。现在我们要填充成好看的颜色,所以我们需要设置画刷的颜色。只需要调用SelectObject函数将你创建的画刷与hdc关联起来,或者说叫做将画刷选进DC中,就可以使用画刷定义的颜色来填充饼图了。而创建画刷比较简单的就是CreateSolidBrush,它只有一个参数,就是颜色值。关于颜色的使用,参考《COLOR和COLORREF之间的理解与相互转换》。
然后用完画刷后要删掉,避免资源泄露,让程序运行时间长了就卡了。然后就是在饼图画完后在饼上输出文字。这里注意,后输出的在先输出的上面。所以文字要在饼图画好后再输出,而输出的位置,我这里都手动设置的,你可以自己调整坐标。
而一个完整的饼图有很多个小的部分组成,我们要画出所有的饼块,就要绘制多次,按照逆时针旋转,将所有饼块画出来。
实现的完整代码如下:
#include "windows.h"
#include <Windowsx.h>//GET_X_LPARAM,GET_Y_LPARAM宏需要这个头文件
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
TCHAR Info[100]=_T("某年某月的搜索引擎市场占用率饼状图 - 【C++技术网http://www.cjjjs.com】");
HBRUSH hbrush;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
SetBkMode(hdc,TRANSPARENT);
hbrush = CreateSolidBrush(RGB(105,100,0));
SelectObject(hdc,hbrush);
Pie(hdc,0,0,400,400,80,0,0,200);
DeleteObject(hbrush);
SetTextColor(hdc,RGB(255,255,255));
TextOut(hdc,35,150,_T("360搜索"),lstrlen(_T("360搜索")));
TextOut(hdc,35,170,_T("市场份额:20%"),lstrlen(_T("市场份额:20%")));
hbrush = CreateSolidBrush(RGB(200,255,10));
SelectObject(hdc,hbrush);
Pie(hdc,0,0,400,400,0,200,0,280);
DeleteObject(hbrush);
SetTextColor(hdc,RGB(0,0,0));
TextOut(hdc,10,200,_T("其他搜索"),lstrlen(_T("其他搜索")));
TextOut(hdc,10,220,_T("市场份额:10%"),lstrlen(_T("市场份额:10%")));
hbrush = CreateSolidBrush(RGB(200,180,255));
SelectObject(hdc,hbrush);
Pie(hdc,0,0,400,400,0,280,400,200);
DeleteObject(hbrush);
SetTextColor(hdc,RGB(0,0,0));
TextOut(hdc,210,300,_T("百度搜索"),lstrlen(_T("百度搜索")));
TextOut(hdc,210,320,_T("市场份额:40%"),lstrlen(_T("市场份额:40%")));
hbrush = CreateSolidBrush(RGB(160,100,255));
SelectObject(hdc,hbrush);
Pie(hdc,0,0,400,400,400,200,80,0);
DeleteObject(hbrush);
SetTextColor(hdc,RGB(0,0,0));
TextOut(hdc,210,100,_T("搜狗搜索"),lstrlen(_T("搜狗搜索")));
TextOut(hdc,210,120,_T("市场份额:30%"),lstrlen(_T("市场份额:30%")));
SetTextColor(hdc,RGB(255,255,0));
TextOut(hdc,50,410,Info,lstrlen(Info));
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
TCHAR ClassName[] = _T("MyClass");
TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
WNDCLASS wndClass;
wndClass.cbClsExtra=0;
wndClass.cbWndExtra=0;
wndClass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc = WinProc;
wndClass.lpszClassName = ClassName;
wndClass.lpszMenuName=NULL;
wndClass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wndClass))
{
return 0;
}
HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,600,600,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}