MFC编程例子.doc_第1页
MFC编程例子.doc_第2页
MFC编程例子.doc_第3页
MFC编程例子.doc_第4页
MFC编程例子.doc_第5页
已阅读5页,还剩26页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

例程1. MFChello步骤1.选择新建-项目,打开后出现如果1所示对话框。选择VC+中的智能设备,在右边选择MFC智能设备应用程序。在下方的名称中输入MFChello,点击确定。步骤2.点击下一步步骤3.将Mini2440-CE6-SDK移到右边,点击下一步。步骤4.在应用程序类型选择基于对话框,直接点击完成。步骤5.选择类视图,点击CMFChelloApp,在下方可以看到InitInstance(void)函数,双击该函数。步骤6在BOOL CMFChelloApp:InitInstance()添加如下代码AfxEnableControlContainer(); /调用此函数的目的是为了使程序支持包含OLE控件MessageBox(NULL,_T(一个简单的MFC程序),_T(你好),MB_OK); /谈出对话框例程2.鼠标测试程序同例程1一样,建立一个基于对话框的MouseTest程序。在右边的对话框编辑器中选择Static Text,添加到对话框中一个静态文本,然后更改右下角的静态文本的属性,Caption改为提示:点一下鼠标右键或左键,ID改为IDC_STATIC点击对话框,在右下角点击消息按钮,出现下图。找到WM_LBUTTONDOWN消息,添加OnLButtonDown函数。在函数中添加代码如下MessageBox(NULL,_T(你点的是左键),_T(The first Dialog),MB_OK);同样操作在WM_RBUTTONDOWN消息,添加OnRButtonDown函数。在函数中添加代码如下MessageBox(NULL,_T(你点的是右键),_T(The first Dialog),MB_OK);进行仿真即可。例程3.添加图标创建一个基于对话框的IconTest程序。切换到资源视图。右键点击Icon,选择添加资源,弹出下图。选择导入,导入一个图标文件(.ico)文件,如下图。点击CIconTestDlg类,找到CIconTestDlg函数。找到下面的语句:m_hIcon = AfxGetApp()-LoadIcon(IDR_MAINFRAME);改为下面的语句:m_hIcon = AfxGetApp()-LoadIcon(IDI_ICON1);点击仿真可看到对话框左上角的图标已经改变。例程4.简单计算机1.0创建基于对话框的calculator项目。点击Dialog,添加如下控件。在加数编辑框右击添加变量。变量名称是m_editSummand,变量类型是double,类别为value。同样操作添加被加数编辑框变量。变量名称是m_editAddend,变量类型是double,类别为value。和编辑框变量。变量名称是m_editSum,变量类型是double,类别为value。将计算按钮的ID设为IDC_ADDBUTTON。双击该按钮,进入void CcalculatorDlg:OnBnClickedAddbutton()函数。添加如下代码:UpdateData(TRUE);m_editSum = m_editSummand + m_editAddend;UpdateData(FALSE);将退出按钮的ID设为IDC_QUT。双击该按钮,进入void CcalculatorDlg:OnBnClickedQut()函数。添加如下代码:ShowWindow(SW_HIDE);/将非模态对话框隐藏仿真即可。在这个程序中对话框基本是由MFC自己创立的,下面说一下它是在哪里弹出的。打开calculator.cpp文件,可以看到有个InitInstance()函数。对话框就是在这里产生的。下面是这段代码的注释程序。BOOL CcalculatorApp:InitInstance()/ 标准初始化/ 如果未使用这些功能并希望减小/ 最终可执行文件的大小,则应移除下列/ 不需要的特定初始化例程/ 更改用于存储设置的注册表项/ TODO: 应适当修改该字符串,/ 例如修改为公司或组织名SetRegistryKey(_T(应用程序向导生成的本地应用程序);CcalculatorDlg dlg; /定义对话框类CcalculatorDlg的对象m_pMainWnd = &dlg; /将dlg设为主窗口INT_PTR nResponse = dlg.DoModal(); /弹出对话dlg,并将DoModal函数的返回值(退出时点击/按钮的ID)赋值给nResponseif (nResponse = IDOK) /判断返回值是否为OK按钮/ TODO: 在此处放置处理何时用“确定”来关闭/ 对话框的代码 Else if(nResponse = IDCANCEL) /判断返回值是否为Cancel按钮 / 由于对话框已关闭,所以将返回FALSE 以便退出应用程序,/ 而不是启动应用程序的消息泵。return FALSE;弹出对话框比较关键的一个函数,就是对话框类的DoModal()函数。CDialog:DoModal()函数的原型为: Virtual INT_PTR DoModal(); 返回值:整数值,指定了传递给CDialog:EndDialog(该函数用于关闭对话框)的nResult函数值。如果函数不能创建对话框,则返回-1;如果出现其他错误,则返回IDABORT。调用了它对话框就会弹出,返回值是退出对话框时所点的按钮的ID,比如,我们点了“退出”按钮,那么DoModal返回值为IDCANCEL。添加一个新的对话框并弹出它切换到资源视图,右击Dialog,选择插入Dialog,将新插入的Dialog的ID改为IDD_TIP_DIALOG,添加一个静态文本。如下图右击该对话框,选择添加类,类的名字为CTipDlg,点OK。在calculator.cpp中添加头文件:#include “TipDlg.h”.修改void CcalculatorDlg:OnBnClickedAddbutton(),代码如下INT_PTR nRes; /用于保存DoModal函数的返回值CTipDlg tipDlg; /构造对话框类CTipDlg的实例nRes = tipDlg.DoModal(); /弹出对话框if(IDCANCEL = nRes) /判断对话框退出后返回值是否为IDCANCEL,如果是则return,否则继续return;仿真即可。创建及显示非模态对话框的步骤1.在calculatorDlg.h中包含CTipDlg类型的指针成员变量。详细操作方法是,在calculatorDlg.cpp中删除之前添加的#include”TipDlg.h”,而在calculatorDlg.h中添加#include” TipDlg.h”,这是因为我们需要在calculatorDlg.h中定义CTipDlg类型的指针变量,所以要先包含它的头文件,然后再calculatorDlg.h中为CcalculatorDlg类添加private成员变量CTipDlg *m_pTipDlg.2.在CcalculatorDlg类的构造函数中初始化成员变量m_pTipDlg。如果cpp文件中函数太多,我们可以在Class View上半个视图中找到CcalculatorDlg类,再在下半个视图中找到其构造函数双击,中间客户区域即可马上切换到构造函数的实现处。在构造函数中添加m_pTipDlg=NULL;。在任何指针变量使用前都初始化,可以避免因误访问重要内存地址而破坏此地址的数据。3.将上面添加模态对话框显示代码注释掉。修改CcalculatorDlg:OnBnClickedAddbutton()函数。void CcalculatorDlg:OnBnClickedAddbutton()/ TODO: 在此添加控件通知处理程序代码/*INT_PTR nRes; /用于保存DoModal函数的返回值CTipDlg tipDlg; /构造对话框类CTipDlg的实例nRes = tipDlg.DoModal(); /弹出对话框if(IDCANCEL = nRes) /判断对话框退出后返回值是否为IDCANCEL,如果是则return,否则继续return;*/if(NULL=m_pTipDlg)/创建非模态对话框实例m_pTipDlg = new CTipDlg();m_pTipDlg-Create(IDD_TIP_DIALOG,this);/显示非模态对话框m_pTipDlg-ShowWindow(SW_SHOW);/将各控件中的数据保存到相应的变量UpdateData(TRUE);m_editSum = m_editSummand + m_editAddend;UpdateData(FALSE);4.因为此非模态对话框实例是动态创建的,所以需要手动删除此动态对象来销毁对话框。我们在CcalculatorDlg类的析构函数中添加删除代码,但是MFC并没有自动给出析构函数,这时需要手动添加,在对话框对象析构时就会调用我们自定义的析构函数。在CcalculatorDlg.h文件中为CcalculatorDlg添加析构函数声明:CcalculatorDlg();然后在CcalculatorDlg.cpp文件中添加析构函数的实现。例程5.屏幕全屏显示/得到屏幕大小m_nMaxX = GetSystemMetrics(SM_CXSCREEN);m_nMaxY = GetSystemMetrics(SM_CYSCREEN);/全屏显示CRect rcTemp; rcTemp.BottomRight() =CPoint(m_nMaxX, m_nMaxY);rcTemp.TopLeft() = CPoint(0, 0); MoveWindow(&rcTemp);例程6.WINCE添加菜单栏到对话框中在对话框初始化程序中加入以下变量,其中IDR_MENU为菜单栏的ID。/将菜单与界面关联起来HINSTANCE hInst = AfxGetResourceHandle(); HWND hwndCB = CommandBar_Create(hInst,this-GetSafeHwnd(),1); if(hwndCB = NULL) TRACE0(Failed to create CommandBar/n); if(!CommandBar_InsertMenubar(hwndCB,hInst,IDR_MENU,3) ) TRACE0(Failed Insert Menu to CommandBar/n); 例程7.如何更改对话框的背景在对话框中添加全局变量m_brush,在构造对话框函数中创建画刷。在对话框中添加WM_CTRCOLOR事件。将函数的返回值该为m_brush即可。例程8.绘制坐标轴以及网格void CnewtableDlg:tablebk()CPaintDC dc(this);INT i(0); INT iXStart(0), iYStart(0), iXEnd(0), iYEnd(0); INT iChartWidth(0), iChartHeight(0); CPen extPenGrid; CPen intPenGrid;/ CPen* pOldPen; CRect rcGrid;CRect rcClient(10,10,m_nMaxX-10,m_nMaxY/3*2);CPen solidpen(PS_SOLID,1,RGB(0,0,0); CPen* oldpen = dc.SelectObject(&solidpen);dc.MoveTo(rcClient.left,rcClient.top);dc.LineTo(rcClient.left,rcClient.bottom);/dc.LineTo(rcClient.left,rcClient.top);/dc.LineTo(rcClient.right-1,rcClient.top);/dc.LineTo(rcClient.right-1,rcClient.bottom-1);dc.LineTo(rcClient.right,rcClient.bottom-1);dc.SelectObject(oldpen); float m_fYFirstValue = 0.0f;float m_fYEndValue = 500.0f; intm_iXWord = 10;int m_iYWord = 5;CPen pen(PS_DOT,1,RGB(255,0,0);CPen pens(PS_SOLID,1,RGB(0,0,0);/ CPen* odpen = dc.SelectObject(&solidpen);/ dc.MoveTo(rcClient.left,rcClient.Height()/2);/ dc.LineTo(rcClient.right,rcClient.Height()/2);/CPen pens(PS_SOLID,1,RGB(0,0,0);/绘制网格for (int i=0;i0)oldpen = dc.SelectObject(&pen);dc.MoveTo(rcClient.left+5,rcClient.bottom-(i*rcClient.Height()/m_iYWord);dc.LineTo(rcClient.right,rcClient.bottom-(i*rcClient.Height()/m_iYWord);dc.SelectObject(oldpen);for (int j=0;j5;j+)oldpen = dc.SelectObject(&pens);dc.MoveTo(rcClient.left,rcClient.bottom-(i*rcClient.Height()/m_iYWord-(j*rcClient.Height()/(m_iYWord*5);dc.LineTo(rcClient.left+5,rcClient.bottom-(i*rcClient.Height()/m_iYWord-(j*rcClient.Height()/(m_iYWord*5);dc.SelectObject(oldpen);oldpen = dc.SelectObject(&pens);dc.MoveTo(rcClient.left,rcClient.bottom-(i*rcClient.Height()/m_iYWord);dc.LineTo(rcClient.left+10,rcClient.bottom-(i*rcClient.Height()/m_iYWord);dc.SelectObject(oldpen);for(int i=0;i0)oldpen = dc.SelectObject(&pen);dc.MoveTo(rcClient.left+i*rcClient.Width()/m_iXWord,rcClient.bottom);dc.LineTo(rcClient.left+i*rcClient.Width()/m_iXWord,rcClient.top);dc.SelectObject(oldpen);for(int j=0;jSelectObject(&font);pDC-SetTextColor(RGB(255,255,0);pDC-SetBkMode(TRANSPARENT);pDC-ExtTextOutW(rcClient.right-10,rcClient.bottom-20,ETO_CLIPPED,NULL,_T(时间),NULL);例程10 .避免闪烁的方法(OnEraseBkgnd)在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造 成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用 BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪 烁。以上也就是双缓冲绘图的基本的思路。先按普通做图的方法进行编程。即在视类的OnDraw函数中添加绘图代码。在此我们绘制若干同心圆,代码如下:CBCDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);CPoint ptCenter;CRect rect,ellipseRect;GetClientRect(&rect);ptCenter = rect.CenterPoint();for(int i=20;i0;i-) ellipseRect.SetRect(ptCenter,ptCenter); ellipseRect.InflateRect(i*10,i*10); pDC-Ellipse(ellipseRect);编译运行程序,尝试改变窗口大小,可以发现闪烁现象。在双缓冲方法中,首先要做的是屏蔽背景刷新。背景刷新其实是在响应WM_ERASEBKGND消息。我们在视类中添加对这个消息的响应,可以看到缺省的代码如下:BOOL CMYView:OnEraseBkgnd(CDC* pDC) return CView:OnEraseBkgnd(pDC);是调用父类的OnEraseBkgnd函数,我们屏蔽此调用,只须直接return TRUE;即可。下面是内存缓冲作图的步骤.CBitmap bit;bit.LoadBitmapA(IDB_BITMAP1);BITMAP bm;bit.GetBitmap(&bm);CDC memDc;memDc.CreateCompatibleDC(pDC);CBitmap* pOldBitmap = memDc.SelectObject(&bit);CRect rect;GetClientRect(&rect);pDC-SetStretchBltMode(COLORONCOLOR);/这个模式不设置的话会导致图片严重失真pDC-StretchBlt(0,0,rect.Width() ,rect.Height(),&memDc,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);memDc.SelectObject(pOldBitmap);memDc.DeleteDC(); /删除DCbm.DeleteObject(); /删除位图由于复杂的画图操作转入后台,我们看到的是速度很快的复制操作,自然也就消除了闪烁现象。Q: OnEraseBkgnd函数中返回TRUE或FALSE有什么区别?A:WM_ERASEBKGNDReturn ValuesAn application should return nonzero if it erases the background; otherwise, it should return zero.A:true表示已处理背景刷新,false表示需要在OnPaint里处理Q:在OnEraseBkgnd中绘制对话框的背景图片和在OnPaint中绘制对话框的背景图片由什么区别,另外OnEraseBkgnd和CtlColor有什么区别?A:OnEraseBkgnd是在窗口大小发生改变等情况下发生的,它将绘制窗口背景;而OnCtlColor是当窗口的控件需要绘制时发生的,它将绘制窗口的控件。A:OnEraseBkgnd :在窗口背景需要重绘时调用.OnPaint : 此时OnEraseBkgnd已经调用过了,所以在此响应函数体内对背景进行的操作将覆盖OnEraseBkgnd中所做的操作.OnCtlColor : 有于在窗口将要被(第一次)绘制时响应,子窗口可以通过发关WM_CTLCOLOR请求父窗口传来一个HBRUSH.例程11 . MFC如何高效地绘图 显示图形如何避免闪烁,如何提高显示效率是问得比较多的问题。而且多数人认为MFC的绘图函数效率很低,总是想寻求其它的解决方案。MFC的绘图效率的确不高但也不差,而且它的绘图函数使用非常简单,只要使用方法得当,再加上一些技巧,用MFC可以得到效率很高的绘图程序。 我想就我长期(呵呵当然也只有2年多)使用MFC绘图的经验谈谈 我的一些观点。 1、显示的图形为什么会闪烁? 我们的绘图过程大多放在OnDraw或者OnPaint函数中,OnDraw在进行屏 幕显示时是由OnPaint进行调用的。当窗口由于任何原因需要重绘时,总是先用背景色将显示区清除,然后才调用OnPaint,而背景色往往与绘图内容反差很大,这样在短时间内背景色与显示图形的交替出现,使得显示窗口看起来在闪。如果将背景刷设置成NULL,这样无论怎样重绘图形都不会闪了。当然,这样做会使得窗口的显示乱成一团,因为重绘时没有背景色对原来 绘制的图形进行清除,而又叠加上了新的图形。 有的人会说,闪烁是因为绘图的速度太慢或者显示的图形太复杂造成的, 其实这样说并不对,绘图的显示速度对闪烁的影响不是根本性的。 例如在OnDraw(CDC *pDC)中这样写: pDC- MoveTo(0,0); pDC- LineTo(100,100); 这个绘图过程应该是非常简单、非常快了吧,但是拉动窗口变化时还是会看见 闪烁。其实从道理上讲,画图的过程越复杂越慢闪烁应该越少,因为绘图用的 时间与用背景清除屏幕所花的时间的比例越大人对闪烁的感觉会越不明显。 比如:清楚屏幕时间为1s绘图时间也是为1s,这样在10s内的连续重画中就要闪 烁5次;如果清楚屏幕时间为1s不变,而绘图时间为9s,这样10s内的连续重画 只会闪烁一次。这个也可以试验,在OnDraw(CDC *pDC)中这样写: for(int i=0;i MoveTo(0,i); pDC- LineTo(1000,i); 呵呵,程序有点变态,但是能说明问题。 说到这里可能又有人要说了,为什么一个简单图形看起来没有复杂图形那么 闪呢?这是因为复杂图形占的面积大,重画时造成的反差比较大,所以感觉上要 闪得厉害一些,但是闪烁频率要低。 那为什么动画的重画频率高,而看起来却不闪?这里,我就要再次强调了, 闪烁是什么?闪烁就是反差,反差越大,闪烁越厉害。因为动画的连续两个帧之间 的差异很小所以看起来不闪。如果不信,可以在动画的每一帧中间加一张纯白的帧, 不闪才怪呢。 2、如何避免闪烁 在知道图形显示闪烁的原因之后,对症下药就好办了。首先当然是去掉MFC 提供的背景绘制过程了。实现的方法很多, * 可以在窗口形成时给窗口的注册类的背景刷付NULL * 也可以在形成以后修改背景 static CBrush brush(RGB(255,0,0); SetClassLong(this- m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush); * 要简单也可以重载OnEraseBkgnd(CDC* pDC)直接返回TRUE 这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样, 变得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有 图形进行显示以外,在内存中也有图形在绘制。我们可以把要显示的图形先在内存中 绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去(这个 过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便用什么反差 大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为内存中最终的图形 与屏幕显示图形差别很小(如果没有运动,当然就没有差别),这样看起来就不会闪。 3、如何实现双缓冲 首先给出实现的程序,然后再解释,同样是在OnDraw(CDC *pDC)中: CDC MemDC; /首先定义一个显示设备对象 CBitmap MemBitmap;/定义一个位图对象 /随后建立与屏幕显示兼容的内存显示设备 MemDC.CreateCompatibleDC(NULL); /这时还不能绘图,因为没有地方画 _ /下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小 MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight); /将位图选入到内存显示设备中 /只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上 CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); /先用背景色将位图清除干净,这里我用的是白色作为背景 /你也可以用自己应该用的颜色 MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255); /绘图 MemDC.MoveTo(); MemDC.LineTo(); /将内存中的图拷贝到屏幕上进行显示 pDC- BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY); /绘图完成后的清理 MemBitmap.DeleteObject(); MemDC.DeleteDC(); 上面的注释应该很详尽了,废话就不多说了。 4、如何提高绘图的效率 我主要做的是电力系统的网络图形的CAD软件,在一个窗口中往往要显示成千上万个电力元件,而每个元件又是由点、线、圆等基本图形构成。如果真要在一次重绘过程重画这么多元件,可想而知这个过程是非常漫长的。如果加上了图形的浏览功能,鼠标拖动图形滚动时需要进行大量的重绘,速度会慢得让用户将无法忍受。怎么办?只有再研究研究MFC的绘图过程了。 实际上,在OnDraw(CDC *pDC)中绘制的图并不是所有都显示了的,例如:你 在OnDraw中画了两个矩形,在一次重绘中虽然两个矩形的绘制函数都有执行,但是很有可能只有一个显示了,这是因为MFC本身为了提高重绘的效率设置了裁剪区。裁剪区的作用就是:只有在这个区内的绘图过程才会真正有效,在区外的是无效的,即使在区外执行了绘图函数也是不会显示的。因为多数情况下窗口重绘的产生大多是因为窗口部分被遮挡或者窗口有滚动发生,改变的区域并不是整个图形而只有一小部分,这一部分需要改变的就是pDC中的裁剪区了。因为显示(往内存或者显存都叫显示)比绘图过程的计算要费时得多,有了裁剪区后显示的就只是应该显示的部分,大大提高了显示效率。但是这个裁剪区是MFC设置的,它已经为我们提高了显示效率,在进行复杂图形的绘制时如何进一步提高效率呢?那就只有去掉在裁剪区外的绘图过程了。可以先用pDC- GetClipBox()得到裁剪区,然后在绘图时判断你的图形是否在这个区内,如果在就画,不在就不画。 如果你的绘图过程不复杂,这样做可能对你的绘图效率不会有提高。例程12.如何一直点击按钮触发一个事件BOOL CalldownDlg:PreTranslateMessage(MSG* pMsg)/ TODO: 在此添加专用代码和/或调用基类if(pMsg-message = WM_LBUTTONDOWN|pMsg-message = WM_LBUTTONUP)CPoint pnt;GetCursorPo

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论