MFC里多文档多视图+多线程动态计算、绘制曲线

来源:互联网 发布:java rs232c 编辑:程序博客网 时间:2024/06/03 12:12

对于初学MFC多线程的,我建议看一看《Windows环境下的多线程编程原理与应用--王险峰》一书,里面代码实例较多,适合初学者理解MFC里的工作、界面多线程及线程间通信。

对于MFC里多线程的原理,不做过多介绍,可以看书获得。下面是我在MFC里,使用MDI框架,多文档/多视图(View)里同步绘制动态数据曲线的实现。

对应MFC里多文档/多视图的学校,推荐看侯捷的《深入浅出MFC》。

(本实例主要完成以下工作:

(1)、利用VS2010创建MDI工程;

(2)、在主.cpp文件中注册多个文档模板

(3)、重新OnFileNew()函数,使得重新执行或New时显示自己要求的View视图窗口;

(4)、利用MFC的界面多线程CWinThread类进行界面多线程的建立;

(5)、利用全局数组的形式在和类之间传递数据;

该工程是基于VS2010的,完整源代码可在我得Github里下载:https://github.com/LuoKuanH/MultiThread

1、  利用VS2010创建MDI工程项目


2、在主cpp里注册多文档模板

// Draw.h : Draw 应用程序的主头文件//#pragma once#ifndef __AFXWIN_H__#error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"#endif#include "resource.h"       // 主符号// CDrawApp:// 有关此类的实现,请参阅 Draw.cpp//class CDrawApp : public CWinAppEx{public:CDrawApp();CMultiDocTemplate* m_pTemplateTime;//创建文档模板1,用于绘制时域图CMultiDocTemplate* m_pTemplateDFT;//创建文档模板2,用于绘制实时DFT图// 重写public:virtual BOOL InitInstance();virtual int ExitInstance();// 实现UINT  m_nAppLook;BOOL  m_bHiColorIcons;virtual void PreLoadState();virtual void LoadCustomState();virtual void SaveCustomState();afx_msg void OnAppAbout();afx_msg void OnFileNew();DECLARE_MESSAGE_MAP()afx_msg void OnDraw();};extern CDrawApp theApp;
BOOL CDrawApp::InitInstance(){......        // 注册应用程序的文档模板。文档模板// 将用作文档、框架窗口和视图之间的连接//CMultiDocTemplate* pDocTemplate;m_pTemplateTime = new CMultiDocTemplate(IDR_DrawTYPE,   //注册时域视图模板RUNTIME_CLASS(CDrawDoc),RUNTIME_CLASS(CChildFrame), RUNTIME_CLASS(CMainView));if (!m_pTemplateTime)return FALSE;AddDocTemplate(m_pTemplateTime);m_pTemplateDFT = new CMultiDocTemplate(IDR_DrawTYPE,   //注册频域视图域模板RUNTIME_CLASS(CMainDoc),RUNTIME_CLASS(CChildFrame), RUNTIME_CLASS(CDFTView));if (!m_pTemplateDFT)return FALSE;AddDocTemplate(m_pTemplateDFT);......}

然后在主cpp里重写OnFileNew()函数,使得新建文件时,同时打开两个用于绘图的View视图

ON_COMMAND(ID_FILE_NEW, OnFileNew)void CDrawApp::OnFileNew(){//CDrawApp *pMyApp = (CDrawApp * )AfxGetApp();//CMultiDocTemplate* m_pTemplateTime = pMyApp->m_pTemplateTime;m_pTemplateTime->OpenDocumentFile(NULL);m_pTemplateDFT->OpenDocumentFile(NULL);}
此时当开始执行程序,或者新建时,灰同时显示两个View视图:

3、在菜单栏添加菜单命令:

CaptionID设置Prompt更新数据ID_REDATA默认两个View同时绘图在Drawdoc里添加该菜单命令的响应函数:

DrawDoc.cpp

BEGIN_MESSAGE_MAP(CDrawDoc, CDocument)ON_COMMAND(ID_REDATA, &CDrawDoc::OnRedata)END_MESSAGE_MAP()void CDrawDoc::OnRedata(){// TODO: 在此添加命令处理程序代码pDFTThread = AfxBeginThread(RUNTIME_CLASS(CMainThread));pDrawThread = AfxBeginThread(RUNTIME_CLASS(CViewThread));pThread = AfxBeginThread(Calculate,this);

UINT Calculate(LPVOID pParam){CDrawDoc *pdoc = (CDrawDoc*)pParam;CViewThread *pdrawThrd = (CViewThread*)(pdoc->pDrawThread);CMainThread *pUIThrdd = (CMainThread*)(pdoc->pDFTThread);//CViewThread *pdlgThrd = (CViewThread*)(pdoc->pPROSThread);for (int i =0; i<100; i++){datax[i] = i;datay[i] = i*i/2;data = i;pdrawThrd->PostThreadMessage(WM_SHOW_VI,NULL,NULL);//pdlgThrd->PostThreadMessage(WM_PROS,NULL,NULL);pUIThrdd->PostThreadMessage(WM_SHOW_DFT,NULL,NULL);Sleep(10);}return 0;}

响应该菜单命令的函数主要是创建两个界面多线程和一个工作线程,其中Calculate()函数是工作线程,用于实时计算数据,然后利用两个界面线程,实现显示计算出来的数据。

4、由MFC的界面多线程类CWinThread派生class CMainThread : public CWinThread,线程间通信采用消息传递法方式。

线程间通信采用消息传递法,在两个派生的界面线程中,添加对应的消息响应函数

CMainThread

#define WM_SHOW_DFT WM_USER + 3...afx_msg void ShowDFT(WPARAM wParam,LPARAM lParam);...BEGIN_MESSAGE_MAP(CMainThread, CWinThread)ON_THREAD_MESSAGE(WM_SHOW_DFT,ShowDFT)END_MESSAGE_MAP()...// CMainThread 消息处理程序void CMainThread::ShowDFT(WPARAM wParam,LPARAM lParam){POSITION curTemplatePos = theApp.GetFirstDocTemplatePosition();CDocTemplate *m_doc=theApp.GetNextDocTemplate(curTemplatePos);CDocTemplate *m_doc1=theApp.GetNextDocTemplate(curTemplatePos);//文档模板//获得文档:curTemplatePos=m_doc1->GetFirstDocPosition();CMainDoc *m_pdoc=(CMainDoc*)m_doc1->GetNextDoc(curTemplatePos);//获得视图:curTemplatePos=m_pdoc->GetFirstViewPosition();CDFTView *m_dview;while(curTemplatePos !=NULL){m_dview = (CDFTView*)m_pdoc->GetNextView(curTemplatePos);if (m_dview->IsKindOf(RUNTIME_CLASS(CDFTView))){m_dview->drawline();//调用相应视图的绘图函数进行曲线绘制}else{}}}
上述的ShowDFT()函数里,主要功能是遍历程序的文档模板及文档视图,遍历找到需要的View类,并利用对应的View类调用该View对应的drawline()函数进行曲线绘制。

线程间的数据传递采用全局变量的方式:

定义两个全局数组int datax[100];int datay[100];用于保存计算的数据,同时用于数据传递至界面线程里面进行曲线绘制(本实例较简单,通过Calculate()函数实现更新数据,然后两个界面线程利用此数据进行简单的直线绘制);

本例中,两个界面线程分别使用MainView和DFTView进行曲线绘制,因此,在这两个View中,分别加入函数drawline();

MainView.cppj及DFTview.cpp

// CMainViewextern int datax[100];extern int datay[100];void CMainView::drawline(){CClientDC dc (this);CPen pen1(PS_SOLID,1,RGB(0,255,0)); ////建立一个画笔类对象,构造时设置画笔属性dc.SelectObject(&pen1);for (int i=0; i<100; i++){dc.MoveTo(datax[i],150);dc.LineTo(datay[i],150);//Sleep(10);}}

5、结果显示

当我们把鼠标单击上面一个视图后,点击菜单栏的更新数据命令,便可以看到两个View里的直线同步绘制,从左至右。

注意:由于本实例代码中使用了两个文档注册文档模板,而菜单命令只在DrawDoc文档里进行的响应,因此,我们绘图是需要将焦点定位于与DrawDoc关联的View(及上面一个View里,才能响应我们的“更新数据”菜单命令);

总结:这只是我自己实现的一个例子,可能有很多问题,希望指正。刚开始学习写博客,感觉好多话说不清楚。该实例的完整源码可在我的GitHub里下载,链接在上方。

对应MFC实现多文档多视图,首先需要在主cpp里注册多个文档模板,然后如果想要程序开始时或新建时显示特定View,需要重新主cpp里的OnFileOpen()和OnFileNew()函数。对应变量的传递,我苦于只想到使用全局变量的方式,应该还有更好的方式。



2 0
原创粉丝点击