2024年2月19日发(作者:)

MFC中保存数据为TXT的方法

1. 首先:创建MFC工程,工程名XX,基于对话框的文件,最后完成。

2. 在对话框中添加控件两个Edit Box、。 用ClassWizard向导,设置Edit Box的ID为XXXXX。添加Button消息响应为void XXXXX::OnSave()

3. 在void XXXXX::OnSave()中添加如下代码:

CString strText(_T(""));

GetDlgItemText(IDC_EDIT, strText); //获取edit box中的数据

try

{

CStdioFile file;

(_T("D:"), CFile::modeCreate | CFile::modeWrite

CFile::typeText);

//打开D盘的txt文件

tring(strText); //写入edit box中的数据

();

}

catch (CFileException* e)

{

e->ReportError();

e->Delete();

}

|

CString path = "d:";

CString temp;

CFile file;

float a = 12.2, b = 123.3, c = 1234.4;

(path, CFile::modeCreate | CFile::modeReadWrite);

temp = "通道1 通道2 通道3rn";

(temp, gth());

CString m_str;

for(int i = 0; i < 1; i++)

{

();

m_("%.1f ", a);

temp += m_str;

m_("%.1f ", b);

temp += m_str;

m_("%.1f ", c);

temp += m_str;

temp += "rn";

(temp, gth());

}

();

MFC绘制动态曲线,用双缓冲绘图技术防闪烁

2011-07-14 10:34:54| 分类: 学习笔记 | 标签:双缓冲绘图技术 mfc 动态曲线 |举报|字号 订阅

先上效果图

随着时间的推移,曲线向右平移,同时X轴的时间坐标跟着更新。

一、如何绘制动态曲线。

所谓动画,都是一帧一帧的图像连续呈现在用户面前形成的。所以如果你掌握了如何绘制静态曲线,那么学会绘制动态曲线也不远啦,只需要创建一个定时器(比如调用MFC中的SetTimmer函数),每隔一定时间(比如1ms),调用OnPaint或者OnDraw函数,绘制当前帧图像即可。

这里需要注意的是,绘制图像的代码需要写在OnPaint或者OnDraw函数中,因为当窗口失效(比如最小化)恢复后,会重新绘制当前窗口,窗口之前的自绘图像会丢失。而把绘图代码写在OnPaint或者OnDraw中就是为了让窗口每次重绘时也能重绘你自己画的图像,避免出现窗口最小化再恢复后,自己画的图像丢失的尴尬情况。

另外绘制当前帧图像之前,记得用InvalidateRect函数清除上一帧图像,不然各帧图像会背景的堆叠。

比如我想清除窗口中(0,0)和(100,100)这两点确定的矩形中的图像,代码如下:

CRect Rect;

= 0;

= 0;

= 100;

= 100;

InvalidateRect(Rect);

根据上面的思路,我们每隔一定时间绘制一幅图像,可是如果每次绘制的图像都是完全相同的,那么图像看起来也是静态的。如何让曲线动起来呢?我们需要为自己绘图的代码设计一个输入,即在当前时刻曲线上各个点的坐标信息。随着时间的推移,令曲线上各个点的坐标随之变化,这样每次绘图都是基于当前时刻的曲线坐标绘制的,控制好曲线坐标的变化,也就能让你绘制的曲线乖乖的动起来。

上面提到了曲线上各个点的坐标信息,这个信息可以用多种数据结构储存,不过笔者推荐使用STL中的deque数据结构储存。为什么呢?需求决定选择。让我们先想想在绘制图像的过程中需要对这个数据进行哪些操作。

1、需要遍历这个数据,获取各个点的坐标以便绘图,所以选择的数据结构必须有较高的遍历效率。

2、当曲线上的点横向上充满了横坐标轴提供的显示范围,需要将曲线最右边的点的坐标移除,然后在曲线最左边添加下一个新点的坐标,以实现曲线向右平移的效果。所以选择的数据结构需要支持前端和后端元素的添加删除操作,大家很自然会想到队列。

STL中的list容器也能很轻松的实现队列功能,但是list还支持任意位置元素的添加和删除操作,功能上的冗余决定了list需要花费更多的时间来实现我们的需求,事实上遍历一个deque常常比遍历一个list快几十倍,原因在这里就不赘述啦。

于是,笔者构建了这样的数据结构deque>

m_dqDisplayData;队列中的每个元素是一个pair,pair中存放坐标。维护这个数据结构的核心代码如下:

//如果队列长度超过了X轴方向上可绘的所有点的数量

if (m_() >= XPointNum)

{

//将队列前端的坐标移除

m__front();

//在队列后端添加新的坐标

m__back(make_pair(time, value));

}

else

{

m__back(make_pair(tiem, value));

}

前面介绍了如何让静态的曲线动起来,下面具体介绍绘制静态图像的主要技能。

1、画图首先需要找一位画家,MFC是这样获取一位画家的。

CDC *pDC = GetDC();

记得这位画家画完本帧图像之后,打发他走人,闲人咱们养不起。

即必须用ReleaseDC(pDC);释放资源,否则会造成内存泄漏,因为GetDC();函数中分配了一些资源,这些资源关联在pDC指向的内存中,如果不调用ReleaseDC,当pDC出作用域后,只是pDC这个32位的指针变量(也可以说它是一个整数变量)的内存释放了,pDC指向的内存没有机会得到释放。这里也反映出MFC的一个原则,Get之后需要Release,这两个函数往往是成对定义好的。

另外,GetDC和ReleaseDC都是CWnd的成员函数,我们需要在哪个窗口上画图,就在那个窗口类的OnPaint或者OnDraw函数中创建一位会在该窗口上画画的画家,其实GetDC中隐含的操作是,创建一位画家,将自己所在的窗口的绘图区作为画纸交给这位画家,然后再把画家返回给用户。当我们直接建立CDC对象时(比如:CDC MemDC;),就需要用其他方法(比如:SelectObject函数)为其选择画纸了。

2、画家画图之前,首先要准备好画图工具。

MFC提供了很多画图工具,比如画刷(CBrush),画笔(CPen)等。(呵呵,其实笔者也没用过几种)

//下面就实例化了一个画实线,宽度为1,颜色为RGB(0, 128, 64)的画笔

CPen PenForDrawAxis(PS_SOLID, 1, RGB(0, 128, 64));

//画家使用SelectObject技能,将画笔握入手中

pDC->SelectObject(PenForDrawAxis);

另外说明一点:关于画笔不再使用后,是否需要调用Object();释放资源的问题,网上说法不一。各大书籍上,作者们都常常下意识的显式地调用了DeleteObject函数,以体现释放资源的动作。

如果需要及时释放内存资源,为后面的程序运行扫清障碍,那显式的调用DeleteObject函数我觉得没有问题。但是如果说不调用DeleteObject函数,CPen对象分配的资源就无法释放,就会造成内存泄漏,这点我深表怀疑。

因为CPen对象的资源在构造函数中分配,自然在其析构函数中应该有对应的释放函数,因为作为MFC用户来说, 在使用CPen时,根本不知道是否分配了需要显式释放的资源。对象应该对自己负责,不应该将冗余责任移交给用户,这是设计C++类的基本原则。通俗的说就是,自己干了哪些好事自己心理清楚,走人的时候自己要收拾干净。微软在代码上不会耍流氓吧(虽然其他地方经常流氓)。

MSDN上的原话是:When an application no longer requires a given pen, it

should call the CGdiObject::DeleteObject member function or destroy the

CPen object so the resource is no longer in use. An application should not

delete a pen when the pen is selected in a device context.

要释放CPen资源,微软给我们指了两条明路,第一是:call the

CGdiObject::DeleteObject member function,第二是:destroy the CPen object。何为destroy the CPen object,一种方法就是让对象出作用域,自动调用析构函数把自己给了结了。

可见,CPen对象即使不调用DeleteObject,也能在自己出作用域被C++摧毁时,释放资源。

扯远啦,扯远啦。。。。。。下面继续。

3、画家开始挥笔啦~

//将笔移动到(60,220)这个坐标指示的位置(只是选地方,还没落笔)

pDC->MoveTo(60, 220);

//将笔在纸上从(60,220)拉到(520,550),一条直线诞生了

pDC->LineTo(520, 220);

//将笔在纸上从(520,220)移动到(510,223),另外一条直线跃然纸上

pDC->LineTo(510, 223);

怎么只能画直线?

曲线是什么?不过是无数小段的直线。

另外,MoveTo和LineTo不必要成对出现,一般一条连续的曲线只需要调用一次MoveTo。

二、如何使用双缓冲技术防止画面闪烁

上面介绍了如何绘制动态曲线,但是这样绘制动态曲线往往会出现画面闪烁的问题。

不管是用什么语言什么构架画图,出现闪烁的根本原因都在于画面变化不连贯。

也许你要问,我每次画的一帧图像都只是在上帧图像的基础上变化了一点点,怎么就不连贯了。确实如此,不过别忘了我们在画每帧图像之前,还调用了InvalidateRect来清除前一帧图像,所谓清除,就是用窗口默认背景色填充指定矩形区域,相当于在每两帧图像之间,实际还插入了一副大煞风景的纯色背景图。

终于,大家想到了一种办法,不使用InvalidateRect来清除前一帧图像,直接重新请一位会在内存上画画的画家,将该帧图像画在内存中的一张新的纸上,然后在窗口上画画的画家使用自己的终极技能BOOL BitBlt( int x, int y, int nWidth,

int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop );将在内存里面画画的老实画家手上的画直接复制过来(剽窃可耻,但很管用~)。于是,问题解决啦,爱装B的程序员们给这种方法取了个很拉风的名字 ------ 双缓冲技术。

这个方法涉及到了以下几个主要技能:

1、谁会在内存上画画啊?

//创建一个会在内存中画画的画家

CDC MemDC;

CompatibleDC(NULL);

2、内存里面说好给的那种新的纸在哪啊?

//创建一个内存中的图纸

CBitmap MemBitmap;

CompatibleBitmap(pDC, 800, 600);

为什么上面要传入一个当前窗口类中通过GetDC得到的pDC?

因为CreateCompatibleBitmap初始化了一个与pDC指定的设备上下文兼容的位图,位图与指定的设备上下文具有相同的颜色位面数或相同的每个像素的位数。你可以试一试,如果此处传入&MemDC,完啦完啦,画家怎么画,图上都是灰色的线条,郁闷死啦。

至于CreateCompatibleBitmap的后面两个参数,指定的是图纸的大小,具体指你可以根据自己窗口大小等实际情况确定,大了无所谓,用不完后面复制的时候可以截取指定尺寸。

3、怎么让画家在这张纸上画画?

//呵呵,酱紫就搞定啦~

Object(&MemBitmap);

4、内存中的画家如何画画?

完全一样,只不过是MemDC在挥笔。

(60, 220);

(520, 220);

(510, 223);

对啦,温馨提示,大家多半想用一种颜色填充指定矩形区域,因为InvalidateRect就是干的这事嘛,你把人家挤下来了,自然这事就得自己做啦。

lidRect(0, 0, 580, 250, RGB(1,4,1));

上面这个函数表示的是,以图纸的(0,0)位置(也就是图纸的最左上角)作为矩形的左上角坐标,画一个颜色为RGB(1,4,1),长为580,宽为250的矩形。尺寸什么的大家不必过于纠结,根据自己的窗口大小,多试几种尺寸和坐标,就能找出最合适的参数了。

需要注意的是,MemDC是在MemBitmap上画画,所以MemDC调用函数传入的坐标是MemBitmap这个图纸上的坐标,不是窗口上的坐标。

4、如何让在窗口蹲点的那位画家直接从内存画家手上复制图纸?

//下面函数的意思是:在MemDC手中的画纸上,以(0,0)处作为矩形框的左上角坐标,拉一个长为580,宽为250的复制矩形框,这个框框里面框中的图像复制到窗口中,复制矩形框的左上角与窗口的(20,50)处重合。580,250决定了复制框框的大小,(0,0)决定了复制框框在MemBitmap上的位置,(20,50)决定了复制框框在窗口上的位置。

pDC->BitBlt(20, 50, 580, 250, &MemDC, 0, 0, SRCCOPY);

下面是部分画图代码,删除了很多周边功能,如果不小心多删到了什么还请大家海涵,主要留着看个思路和框架。

1、画坐标轴的函数,你们看,我就是让 ”内存画家“ --- MemDC 画画的,表示用了双缓冲的哦,呵呵。

void CXXXDlg::DrawAxis(CDC &MemDC, LPTSTR TitleForX, LPTSTR

TitleForY)

{

//选择画坐标轴的画笔

CPen PenForDrawAxis(PS_SOLID, 1, RGB(0, 128, 64));

Object(PenForDrawAxis);

//绘制X轴

(60, 220);

(520, 220);

//绘制箭头

(510, 223);

(510, 217);

(520, 220);

//绘制Y轴

(60, 220);

(60, 30);

//绘制箭头

(57, 40);

(63, 40);

(60, 30);

//设置文本的颜色

COLORREF OldColor = tColor(RGB(255, 255, 0));

//绘制标注

t(480, 230, TitleForX);

t(40, 10, TitleForY);

//还原文本颜色

tColor(OldColor);

}

2、画图例的函数

void CXXXDlg::DrawLegend(CDC &MemDC, CPen &PenForDraw, CPen

&PenForDrawAB, CPen &PenForDrawBE)

{

//设置文本的颜色

COLORREF OldColor = tColor(RGB(0, 128, 64));

//绘制图例

Object(PenForDraw);

t(530, 30, _T("Global"));

(530, 50);

(570, 50);

Object(PenForDrawAB);

t(530, 70, _T("AB"));

(530, 90);

(570, 90);

Object(PenForDrawBE);

t(530, 110, _T("BE"));

(530, 130);

(570, 130);

//还原文本颜色

tColor(OldColor);

}

3、画曲线的函数

void CXXXDlg::DrawDynamicCurve(CDC &MemDC, CPen &Pen,

deque> &DisplayData, double Proportion)

{

//选择画笔

Object(Pen);

//进入临界区

EnterCriticalSection(&(m_cControllingParameters.m_cCriticalSection));

//绘制曲线

if (() >= 2)

{

COORDINATE XPos = 60;

for (UINT PointIndex = 1; PointIndex != ();

PointIndex++)

{

(XPos++, 220 -

(COORDINATE)((double)(DisplayData[PointIndex - 1].second) / Proportion));

(XPos, 220 -

(COORDINATE)((double)(DisplayData[PointIndex].second) / Proportion));

}

}

//离开临界区

LeaveCriticalSection(&(m_cControllingParameters.m_cCriticalSection));

//还原文本颜色

tColor(OldColor);

}

4、重点来啦,Onpaint函数,有双缓冲技术的主流程

void CXXXDlg::OnPaint()

{

CDC *pDC = GetDC();

//创建一个内存中的显示设备

CDC MemDC;

CompatibleDC(NULL);

//创建一个内存中的图像

CBitmap MemBitmap;

CompatibleBitmap(pDC, 580, 250);

//定义各种类型的画笔

CPen PenForDraw(PS_SOLID, 1, RGB(0, 232, 255));

CPen PenForDrawAB(PS_SOLID, 1, RGB(0, 98, 0));

CPen PenForDrawBE(PS_SOLID, 1, RGB(221, 0, 221));

//指定内存显示设备在内存中的图像上画图

Object(&MemBitmap);

//先用一种颜色作为内存显示设备的背景色

lidRect(0, 0, 580, 250, RGB(1,4,1));

//绘制坐标轴

DrawAxis(MemDC, _T("time(s)"), _T("length(kbit)"));

//绘制图例

DrawLegend(MemDC, PenForDraw, PenForDrawAB, PenForDrawBE);

//绘制曲线

DrawDynamicCurve(MemDC, PenForDraw, m_dqDisplayData, 1000);

//将内存中画好的图像直接拷贝到屏幕指定区域上

pDC->BitBlt(20, 50, 580, 250, &MemDC, 0, 0, SRCCOPY);

//释放相关资源

ReleaseDC(pDC);

}

实时波形显示界面

通常计算机需要接收外部实时发送的数据并用十分形象的方式显示出来。例如柱状图、饼图等等。本应用程序则采用波形的形式显示,并接将之设计为可以接收多路数据的波形显示界面。本应用程序在VS2008环境下调试通过。如果需要源码,请联系我,QQ:726921679,E-mail:********************.一.程序界面

点击该图放大

上图中显示了两路波形即三角波和正弦波,当然这两路波形是由程序计算出来的并不是从外部接收的。实际工作中则可以配合串口通讯设备接收它发来的数据并显示出来。

二.波形控件类介绍

本程序的实现主要依赖于那个波形显示控件。从下载连接那里可以下载该源码,里面的文件中,2DPushGraph.h和即是该控件的类的定义文件和实现文件。分析之后得到该类的一些信息。

其成员函数包括:

程序代码:

COLORREF m_crTextColor;//标签文字颜色

COLORREF m_crBGColor;//背景颜色

COLORREF m_crGridColor;//栅格颜色

CString m_strMaxLabel;//最大值之处的标签

CString m_strMinLabel;//最小值之处的标签

bool m_bShowMinMax;//最小最大值显示

bool m_bShowGrid;//是否显示栅格

bool m_bStylesModified;//是否被修改

int m_nMoveOffset;//偏移

int m_nMaxCoords;//最大缓冲

int m_nMaxPeek;//显示数据的最大值

int m_nMinPeek;//显示数据的最小值

int m_nGridSize;//栅格间距

int m_nPeekOffset;//峰值偏移

其实现方法包括:

程序代码:

bool CreateFromStatic( UINT nStaticID, CWnd* pParent );//该方法用于创建控件实例,通常在对话框初始化函数中调用,nStaticID为控件ID,pPatent为创建在那个窗口中的ID。

LPCTSTR GetLabelForMax() const;//获取最大值处的标签

LPCTSTR GetLabelForMin() const; //获取最大值处的标签

COLORREF GetBGColor() const;//获得背景色

COLORREF GetGridColor() const;//获得栅格颜色

void SetBGColor(COLORREF crColor);

void SetGridColor(COLORREF crColor);

void SetTextColor(COLORREF crColor);

COLORREF GetLineColor( UINT uiLineID );//该方法用于获得ID号为uiLineID的波形的线条颜色,因为要在波形控件中画线必须先调用bool AddLine( UINT uiLineID, COLORREF crColor );创建一个波形,ID号为uiLineID。

bool SetLineColor( COLORREF crColor, UINT uiLineID );

COLORREF GetTextColor() const;//获得标签文本的颜色

int GetGridSize() const;//获得栅格间隔

void SetGridSize( unsigned short usWidthAndHeight );

int GetMaxPeek() const;//获得最大值纵坐标

int GetMinPeek() const; //获得最小值纵坐标

void SetPeekRange(int nMin, int nMax);

void SetMaxPeek(int nMax);

void SetMinPeek(int nMin);

unsigned short GetInterval() const; //获得横坐标间距

void SetInterval( unsigned short usInterval );

void SetLabelForMax( LPCTSTR lpszLabel );

void SetLabelForMin( LPCTSTR lpszLabel );

bool AddLine( UINT uiLineID, COLORREF crColor );//该方法用于在该控件上创建一个波形。

void RemoveLine( UINT uiLineID );//清除ID号为uiLineID的波形

bool Push( int nMagnitude, UINT uiLineID );//在ID号为uiLineID号的波形上添加一个数据点,nMagnitude为幅度

void ShowAsBar( UINT uiLineID, bool bAsBar );//柱状图显示

void Update();//更新

三.应用编程

运用该控件在VS2008环境下的编程步骤如下:

1.建立一个对话框的MFC工程,在对话框上按照上图所示的界面布置控件。其中波形控件那里布置一个Picture Control控件将其Modal Frame和Type均属性设置为true,其他均设置为False。注意给Picture

Control取的ID!后面编程将会用到。

2.将波形控件类的定义文件和实现文件拷贝至你的工程目录下。但这实际上并没有将该类真正添加到你的工程下,需手动添加类。常规操作,不详述。

3.在对话框的定义和实现文件中分别添加如下代码:

程序代码:

#include "2DPushGraph.h"

4.在对话框定义文件中(我给的供下载的例程中的是DataRealTimeDlg.h这个文件)中定义一个该控件类的变量:

程序代码:

private:

C2DPushGraph m_PushGraph;

5.在对话框的实现文件中(我给的供下载的例程中的是这个文件)的对话框初始化函数中添加如下代码:

程序代码:

m_FromStatic(IDC_REALCTRL, this); //这个IDC_REALCTRL即是那个Picture Control控件的ID号。

m_Style(0, WS_THICKFRAME); //设置风格

6.现在不妨试着运行以下该程序,应该可以观察到那个控件显示出来了吧。在添加以下代码:

程序代码:

m_e(m_sin, RGB(255,255,255));

m_e(m_tra, RGB(255,0,0))

这两行代码分别添加了一个正弦波形,ID号为m_sin,一个三角波形,ID号为m_tra。不过运行之后并没有数据点绘制出来。那是应为还没有调用bool Push( int nMagnitude, UINT uiLineID )函数添加数据点。试着添加几个数据点再运行即可观察到波形。

7.还有一些控件的响应代码看看那个下载的例程吧。

四.结束语

成功了吧,Any Problem,Contact me please!

注意这边帖子的源代码作者已经删除了,如果需要可以看一下作者写的类似的帖子,那些源码还在。

/

/

在View中使用PlotLab

最近一直在钻研PlotLab_VC库,发现PlotLab_VC帮助文档里只给出了如何在对话框里使用PlotLab的例程,没有在View中使用的例子,今晚试了一些,终于在View下试验成功了。先上图看看。

我建立了一个SDI工程,名为Test。

第一步,在TestView.h中该如下代码

程序代码:

// TestView.h : interface of the CTestView class

//

/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_TESTVIEW_H__63DC1CE4_B0BF_4911_B9F3_1644DD0D5E10__INCLUDED_)

#define AFX_TESTVIEW_H__63DC1CE4_B0BF_4911_B9F3_1644DD0D5E10__INCLUDED_

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include //////////////添加的代码

class CTestView : public CView

{

protected: // create from serialization only

CTestView();

DECLARE_DYNCREATE(CTestView)

// Attributes

public:

CTestDoc* GetDocument();

// Operations

public:

CTSLScope scope;/////////添加的代码

bool bScopeCreated;//////////添加的代码

int counter;/////////////添加的代码

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CTestView)

public:

virtual void OnDraw(CDC* pDC); // overridden to draw this view

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

virtual void OnInitialUpdate();

protected:

virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

//}}AFX_VIRTUAL

// Implementation

public:

virtual ~CTestView();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Generated message map functions

protected:

//{{AFX_MSG(CTestView)

afx_msg void OnSize(UINT nType, int cx, int cy);

afx_msg void OnDatadraw();

afx_msg void OnDataclear();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

#ifndef _DEBUG // debug version in

inline CTestDoc* CTestView::GetDocument()

{ return (CTestDoc*)m_pDocument; }

#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_TESTVIEW_H__63DC1CE4_B0BF_4911_B9F3_1644DD0D5E10__INCLUDED_)

第二步,初始化,重写OnInitialUpdate()

程序代码:

void CTestView::OnInitialUpdate()

{

CView::OnInitialUpdate();

// TODO: Add your specialized code here and/or call the base class

//VCL_InitControls(AfxGetApp()->m_pMainWnd->GetSafeHwnd());

VCL_InitControls(this->GetSafeHwnd());

(this->GetSafeHwnd());

="";//设置示波器标题

="采样点";//设置坐标轴标签

="幅度";

=RGB(0,0,20);//设置背景颜色

();//添加通道

ls[0].Name="通道一";

ls[1].Name="通道二";

VCL_Loaded();

bScopeCreated=true;

counter=0;

}

第三步,响应WM_SIZE消息

程序代码:

void CTestView::OnSize(UINT nType, int cx, int cy)

{

CView::OnSize(nType, cx, cy);

// TODO: Add your message handler code here

if(bScopeCreated)

{

=cx;

=cy;

}

}

第四步,绘制数据,在菜中添加数据|绘制和清除菜单,分别添加响应函数

程序代码:

void CTestView::OnDatadraw()//绘制数据曲线

{

// TODO: Add your command handler code here

float SampleDatas[1000];

for (int i=0;i<1000;i++)

{

SampleDatas[i]=rand()-1000;

}

ls[0].ta(SampleDatas,1000);

for(i=0;i<1000;i++)

{

SampleDatas[i]=(float)(counter++%120)*300-1000;

}

ls[1].ta(SampleDatas,1000);

}

void CTestView::OnDataclear() //清除数据曲线

{

// TODO: Add your command handler code here

ls[0].();

ls[1].();

=false;

}

动态数据曲线绘制

大概有一年之久没在bccn上发帖了,最近几天频繁有人向我索要关于数据曲线绘制的例程。

其实,当中的大多数人想从下位机的硬件上获取数据然后通过串口或USB口送入PC后显示出来。

本人曾经在本论坛上发表过一片类似的帖子——实时曲线绘制/。

今天再写一篇这样的帖子,希望对大家有所帮助。由于本人没有下位机硬件,所以下面给大家展示的Demo例程中数据是由随机数生成的。

先看效果图:

这篇文章也被写在了我在CSDN的博客上,链接地址为/onlymydreams_mfc/article/details/7378094

作为一个电子类专业的学生,下位机硬件是我们所擅长的,但是PC机从下位机获取数据后显示出来成为我们的一大难题,今天给大家展示了一个能实现上述功能的Demo例程。

首先,声明两点。第一,该例程中的曲线类是重用别人的;第二,由于没有下位机,该例程的数据是通过随机函数生成的,自己在使用时换成通过串口或USB口从下位机取得的数开始。下面简要叙述一下开发过程。

Step1:在vc++6.0下建立一个基于对话框的程序,我的Demo取名为OscDemo,在对话框中加入一个图片控件,根据你的需要调整该图片大小,设置该图片的ID号,该例程设置为IDC_OSC.另外添加一个控制曲线绘制的按钮。

Step2:将和COscopeCtrl.h加入到你的工程中。这两个文件在我给的我的Demo例程中有。

Step3:在COscDemoDlg.h中添加一个曲线控件变量

程序代码:

COScopeCtrl m_Osc;

Step4:在COscDemoDlg.h中加入头文件的包含

程序代码:

#include "OScopeCtrl.h"

Step5:在的初始化函数中初始化曲线控件的代码

程序代码:

COscDemoDlg::OnInitDialog()

02.{

03. CDialog::OnInitDialog();

01. // TODO: Add extra initialization here

02. //初始化曲线控件

03. CRect rt;

04. GetDlgItem(IDC_OSC)->GetWindowRect(rt);

05. ScreenToClient(rt);

06. m_(WS_VISIBLE | WS_CHILD,rt,this);

07. //配置曲线控件

08. m_ge(-10.0, 10.0, 1) ;

09. m_its("电压") ;

10. m_its("采样点 (采样频率: 10sps)") ;

11. m_kgroundColor(RGB(0, 0, 64)) ;

12. m_dColor(RGB(192, 192, 255)) ;

13. m_tColor(RGB(255, 255, 255)) ;

14.

15. return TRUE; // return TRUE unless you set the focus to a control

16.}

Step6:通过定时器产生随机数据供显示。该例程通过单击开始按钮启动定时器,产生随机数并用于显示。详细代码可以看Demo