深入浅出CChart 每日一课——快乐高四第六课 二丫的青梅,返璞归真之普通窗口多区域绘图

有好些朋友给我反映,就是一个窗口中添加好几个CChartWnd之后,工作不正常。这个的确是这样,CChartWnd会接管原来窗口的消息循环,添加多个CChartWnd之后,就相当于出租房转手好几道,消息循环乱套了。虽然道理上可以给二房东立规矩,但笨笨尚未想到一个万全之策,所以在目前的状况下,请大家不要在一个窗口上Attach多个CChartWnd。

(笨笨注:上述描述已经是老黄历了,新版本的CChart已经实现了在一个窗口上多次Attach,不过这里的方法仍然非常具有参考价值。)

但是不是就不能在一个窗口的多个区域同时绘图呢?非也非也。请不要忘了,CChartWnd的基础是CChart类,往往越是原始的东西功能就越强大。

下面笨笨就给大家简单示范一下利用CChart在单窗口的多个区域绘图。计划分三种情况,即普通窗口,对话框窗口,duilib窗口,供大伙参考。

本课先介绍在普通窗口下分区域绘图。

笨笨已经提供了一种分裂视图,实际就是一种分区域绘图的方式。但目前分裂视图的各个子视图的类型是一样的,如果想在一个子视图画曲线图,另一个子视图画饼图,笨笨只能说抱歉了。

本课介绍的分区域绘图可以克服这个缺点。

笨笨新近在CChart中增加了一种绘图类型,就是等高线图和云图的合体版,顺便在本课一起介绍了。

本课的示例代码将在一个MFC窗口中分两块区域绘图,一块绘制饼图,一块绘制等高线云图。

现在开始。

仍然以实例的形式。

第一步,打开VC,建立一个基于MFC AppWizard(exe)向导的项目LessonA06,向导中不做任何更改,直接点Finish。

第二步,拷贝库文件到LessonA06文件夹。

第三步,在VC中打开LessonA06View.h文件,在其头部添加如下代码。

 

#include "Chart.h"
#if defined(_UNICODE) || defined(UNICODE)
#	pragma comment(lib,"CChartu.lib")
#else
#	pragma comment(lib,"CChart.lib")
#endif
 using namespace NsCChart;

第四步,在LessonA06View.h文件中,给CLessonA06View类添加两个CChart变量。

CChart m_Chart1, m_Chart2;

第五步,利用ClassWizard给CLessonA06View类添加OnCreate消息处理函数,并修改OnCreate函数如下。

int CLessonA06View::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here
	m_Chart1.SetType(kTypePie);
	m_Chart1.AddPie(4, "王菲");
	m_Chart1.AddPie(3, "张柏芝");
	m_Chart1.AddPie(2, "Irene");

	m_Chart2.SetType(kTypeContour);
	m_Chart2.SetContourByPoints();
	m_Chart2.AddContourPoint(-1, -1, 5);
	m_Chart2.AddContourPoint(-1, 1, 5);
	m_Chart2.AddContourPoint(1, -1, 5);
	m_Chart2.AddContourPoint(1, 1, 5);
	m_Chart2.AddContourPoint(-1, 0, -5);
	m_Chart2.AddContourPoint(0, -1, -5);
	m_Chart2.AddContourPoint(1, 0, -5);
	m_Chart2.AddContourPoint(0, 1, -5);
	m_Chart2.AddContourPoint(0, 0, 10);
	m_Chart2.SetPlotRange(-1.5, 1.5, -1.5, 1.5);
	m_Chart2.SetContourPrecision(8);
	m_Chart2.SetContourLineNum(20);
	m_Chart2.SetUseLegend(false);
	
	return 0;
}

这里请大家注意等高线云图的用法。

首先,它的代码是kTypeContour。

其次,画等高线云图和等高线图、云图一样,需要一个原型为double f(double x, double y);的场函数。

由于好几位朋友问到,他们只有数据点,能不能画等高线图。一直在道理上都是可以的,就是需要编写一个场函数,在场函数里面用数据点插值即可。但这个可能比较麻烦。最近笨笨在CChart中内置了插值函数,采用双线性的方式插值,精度可能没有二次以上的方式的高,但够用就行吧。注意到这一行了吗。

m_Chart2.SetContourByPoints();

这就是表示等高线采用笨笨内置的插值函数绘制,不需要再提供场函数,但需要提供数据点。提供数据点的函数如下。

void	CChart::AddContourPoint(double x, double y, double h);

其中x,y就是坐标,h是高度。

下面这个函数表示等高线的绘制范围。

void	CChart::SetPlotRange(double xl, double xu, double yl, double yu);

下面这个函数表示等高线的绘制精度,在以前的课程中已经介绍了。

 

void	CChart:: SetContourPrecision (int precision);


下面这个函数表示等高线的绘制时的高度数,在以前的课程中也已经出现了。

 

void	CChart::SetContourLineNum(int num);

等高线的新功能介绍就结束了。

第六步,重载OnSize函数如下。

void CLessonA06View::OnSize(UINT nType, int cx, int cy) 
{
	CView::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
	CRect rect;
	GetClientRect(&rect);
	CRect rt1, rt2;
	rt1 = rect;
	rt1.right = (rect.left + rect.right)/2;
	m_Chart1.SetConfineRect(rt1);
	rt2 = rect;
	rt2.left = (rect.left + rect.right)/2;
	m_Chart2.SetConfineRect(rt2);
}


这里就是分配各个视图所占的窗口区域。在本例中,m_Chart1占据窗口的左半,m_Chart2占据窗口的右半。主要需要利用到这个函数。

void CChart::SetConfineRect(RECT rect);


第七步,修改OnDraw如下。

void CLessonA06View::OnDraw(CDC* pDC)
{
	CLessonA06Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	m_Chart1.OnDraw(pDC->m_hDC);
	m_Chart2.OnDraw(pDC->m_hDC);
}


现在可以运行了,效果如下。

 

刚启动的时候可能有点慢,因为需要初始化等高线。

有同学要问了,鼠标没有反应呀?我们这里没有采用CChartWnd,所以需要自己处理消息。

第八步,重载OnLButtonDown,OnLButtonUp,OnLButtonDblClk,OnMouseMove,OnContextMenu,OnEraseBkgnd这几个函数,并修改如下。

void CLessonA06View::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_Chart1.OnLButtonDownR(m_hWnd, point, nFlags);
	m_Chart2.OnLButtonDownR(m_hWnd, point, nFlags);
}

void CLessonA06View::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_Chart1.OnLButtonUpR(m_hWnd, point, nFlags);
	m_Chart2.OnLButtonUpR(m_hWnd, point, nFlags);
}

void CLessonA06View::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_Chart1.OnLButtonDblClkR(m_hWnd, point, nFlags);
	m_Chart2.OnLButtonDblClkR(m_hWnd, point, nFlags);
}

void CLessonA06View::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_Chart1.OnMouseMoveR(m_hWnd, point, nFlags);
	m_Chart2.OnMouseMoveR(m_hWnd, point, nFlags);
}

void CLessonA06View::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	// TODO: Add your message handler code here
	m_Chart1.OnContextMenuR(NULL, m_hWnd, point);
	m_Chart2.OnContextMenuR(NULL, m_hWnd, point);
}

BOOL CLessonA06View::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	return TRUE;
	//return CView::OnEraseBkgnd(pDC);
}

消息响应回来了!!

大家可以比较一下这里和第15课里面消息响应代码的异同。

实际上,就是在各个消息的响应代码里面,把每个CChart对象都处理一遍就可以了。

好了,现在下课喽。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值