C++ MFC学习笔记(第三课)绘制统计直方图

绘制统计直方图

在第二节课,用单文档程序实现鼠标画线画图后,第三节课学习了用单文档程序画统计直方图。最终效果如下。这里以统计成绩人数的为例。
C++ MFC学习笔记(第三课)绘制统计直方图_第1张图片

1.限定直方图大小

我们先创建绘制直方图的函数,下面的代码都在函数中实现,然后在View类中调用函数就可以实现绘制直方图的功能。因为要在客户区绘制图形,所以我们需要一个CDC类型的参数,我们到时需要从文件中获取多个double类型的数据,为了方便,需要一个vector

void CScoresView::DrawScore(CDC *dc,std::vector<double>,int number)

在图形绘制前,我们先限定整个直方图的大小。先创建一个矩形对象,并用GetClientRect函数获取当前客户区的大小。

函数 功能
GetClientRect 获取当前客户区的大小
DeflateRect(int x,int y) 朝CRect的中心移动以缩小,矩形宽度缩小2x,高度缩小2y
	CRect rc;
	GetClientRect(rc);
	rc.DeflateRect(40, 40);

2.画笔预设

在MFC中,CGdiObject类是GDI(图形设备接口)对象的基类,有以下派生类:CBitmap、CPalette、CRgn、CBrush、CFont和CPen,我们在此了解CBrush,CPen。

2.1 CBrush类

CBrush类的设置,可以对矩形进行填充。

函数 功能
CBrush 标识符(画刷类型,颜色RGB) 创建画刷
dc.SelectObject(画刷) 选择画刷作当前画刷,返回旧画刷

颜色一般用16进制表示,如#66CCFF,转化颜色值就是(96, 192, 255)
画刷类型:
C++ MFC学习笔记(第三课)绘制统计直方图_第2张图片

2.2 CPen类

CPen类的设置,用于绘制矩形的边缘。

函数 功能
CPen 标识符(笔的类型,宽度,颜色RGB) 创建画笔
dc.SelectObject(画笔) 选择画笔作为当前画笔,返回旧画笔

画笔类型:
C++ MFC学习笔记(第三课)绘制统计直方图_第3张图片
一些注意事项详细可参考:https://baike.baidu.com/item/CPen/7827245?fr=aladdin
内框线的特点:https://www.cnblogs.com/cgwolver/archive/2009/12/29/1635358.html

2.3 本例代码

	CBrush brush1(HS_BDIAGONAL, RGB(96, 192, 255));
	CBrush brush2(HS_FDIAGONAL, RGB(96, 192, 255));
	CPen pen(PS_INSIDEFRAME, 2, RGB(96, 192, 255));

3.数据预处理

在绘制直方图过程中,我们需要知道区间的宽度为多少,直方图中一个人代表的矩形高度为多少,接下来我们就先处理这些数据。

	int n = 5;//定义有五个区间
	int width = rc.Width() / n;//一个区间的宽度
	
	int s[] = { 0,0,0,0,0 };//区间人数置初值
	for (int i = 0; i < number; i++)
	{
		int td = (int)db[i] / 10;
		if (td < 6) s[0]++;
		else if (td < 7) s[1]++;
		else if (td < 8) s[2]++;
		else if (td < 9) s[3]++;
		else s[4]++;
	}//统计各区间人数
	int max_s = s[0];
	for (int i = 0; i < n; i++)
		if (max_s < s[i]) max_s = s[i];//找出人数最大的区间
	int per_Height = rc.Height() / max_s;//算出一个人代表的矩形高度

4.绘制直方图

4.1CString类型

CString类型是MFC中最常见的类之一,用于封装字符串数据结构。字符串的连接可以用+,+=号实现,

函数 功能
CString str0(const CString& str1) 将str1复制到str0
CString str0(const CString& str1,n) 将str1的前n个字符复制到str0
str0.Format(_T("%d"),i) 将int类型的i以十进制转化为CString并赋值str0
int i = _ttoi(str) 将str转化为int类型并赋值给i
float f =_ttof(str) 将str转化为float类型并赋值给f

Format函数中的格式字符

格式字符 含义
%c 单个字符
%d 十进制整型(int)
%ld 十进制长整型(long)
%f 十进制浮点数(float)
%lf 十进制浮点数(double)
%o 八进制
%x 十六进制
%s 字符串
%u 无符号十进制数

_T是使用宏,自动加载当前环境的字符环境(Unicode或其他),是当前代码具有可移植性。

4.2绘制直方图相关函数

函数 功能
CRect rect(rc) 用矩形rc来初始化rect,rect获得rc的参数
rect.OffsetRect(int x,int y) 将rect向右移动x,向下移动y(负值反向)
dc->Rectangle(rect) dc为cdc *类型,在客户区绘制rect矩形
dc->DrawText(str,rect,格式) 在矩形位置写入格式化文本

DrawText中的常用格式

格式符号 意义
DT_BOTTOM 将正文调整到矩形底部。此值必须和DT_SINGLELINE组合。
DT_SINGLELINE 显示正文的同一行
DT_CENTER 使正文在矩形中水平居中
DT_VCENTER 使正文在矩形中垂直居中
DT_LEFT 正文左对齐
DT_RIGHT 正文右对齐
DT_TOP 正文顶端对齐

详细参考:https://www.cnblogs.com/spiritofcloud/p/3982652.html

	CRect ps_rect(rc);	//直方图的矩形
	CRect str_rect(rc);	//各区间注释矩形,用于定位
	ps_rect.right = ps_rect.left + width;
	CBrush* oldBrush = dc->SelectObject(&brush1);//保存旧的画刷设置
	CPen* oldPen = dc->SelectObject(&pen);//保存旧的画笔设置
	CString str[5] = { _T("<60"),_T("60-70"),_T("70-80"),_T("80-90"),_T(">=90") };//将每个区间的注释先存储
	for(int i=0;i<n;i++)
	{
		ps_rect.top = ps_rect.bottom - per_Height * s[i] - 2;	//该区间的高度
		if (i % 2)  dc->SelectObject(&brush2);
		else dc->SelectObject(&brush1);	//每隔一个区间用不同的斜线,左斜或右斜
		dc->Rectangle(ps_rect);	//绘制矩形
		if (s[i] > 0)
		{
			CString str1;
			str1.Format(_T("%d人"), s[i]);//设置str1的内容
			dc->DrawText(str1, ps_rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形中间显示人数
		}
		str_rect = ps_rect;
		str_rect.bottom = ps_rect.bottom + 20;
		str_rect.top = ps_rect.bottom + 2;
		dc->DrawText(str[i], str_rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
		ps_rect.OffsetRect(width, 0);//移动矩形框的位置,水平方向移动width
	}
	dc->SelectObject(&oldBrush);
	dc->SelectObject(&oldPen);	//将画刷,画笔设置回原来的样子

在这里左边与平时坐标有点不同,坐标的加减是下面这个方向的。
C++ MFC学习笔记(第三课)绘制统计直方图_第4张图片

5.读取文件数据

绘制直方图的函数已经写完,接下来在View类中的OnDraw函数中调用绘制直方图的函数便可以了。我们在调用前需要先获得数据,这里可以用回输入输出流的方法读取文件,需要包含相应的头文件

void CScoresView::OnDraw(CDC* pDC)
{
	CScoresDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	//添加部分如下
	std::ifstream file("D:\\score.txt", std::ios::in);
	std::vector<double> datas;
	double data;
	while (file >> data)
		datas.push_back(data);
	DrawScore(pDC, datas, datas.size());
}

6.测试

文本中如下
在这里插入图片描述
直方图结果
C++ MFC学习笔记(第三课)绘制统计直方图_第5张图片

你可能感兴趣的:(#,C++,MFC)