MFC的一点思考

12 篇文章 0 订阅

 


 

说明:

说明1:所有MFC框架下的代码在C:\ProgramFiles\Microsoft Visual Studio 9.0\VC\ce\atlmfc\src\mfc中

说明2:显示过程中的各个函数实际上是隐式过程中用到的函数的重写

说明3:窗口create函数完成后将产生WM_CREATE消息,该消息会触发oncreate函数的响应;类似的当客户区create函数完成后将产生WM_CREATE消息,该消息会触发oncreate函数的响应;这就是为什么对客户区初始化时要人为的产生WM_CREATE消息再对oncreate进行重写的原因了。

说明4:这里再说一下Cwingview类的ondraw函数了这个函数在窗口进行重绘时调用,那么什么时候进行重绘呢?

1)        文档类的数据发生变化

2)        其它类中认为的调用(view类的)invalidate函数或updateallviews函数

3)        更加全面的总结如下:

第一次创建一个窗口时

           改变窗口的大小时

把窗口从另一个窗口背后移出时

窗口显示数据变化时,应用程序引发重绘操作

通过CWnd::Invalidate、CWnd::InvalidateRect或CWnd::InvalidateRgn函数把指定区域加到窗口的Update Region中。

窗口的Update Region不为空时,系统会自动产生WM_PAINT消息

说明5:窗口的绘制工作总是在WM_PAINT消息处理中进行的,WM_PAINT的产生会触发onpaint函数,而该函数会调用ondraw函数,故我们经常对ondraw进行编辑
说明6当文档数据发生变化时,文档对象调用CDocument::UpdateAllView()通知所有视图,作为响应,视图的OnUpdate()成员被调用。所以,重载的OnUpdate()应该能够根据需要,将文档数据的变化反映在视图中。CView::OnUpdate()只是简单地使客户区无效,导致客户区重画。例如: 
void CView::OnUpdate(CView* pSender, LPARAM, CObject*) 
{ 
ASSERT(pSender != this); 
UNUSED(pSender); // unused in release builds 
Invalidate(TRUE); 
} 

说明7:从说明6中可以看出onupdate的实现是通过invalidate来实现的,故在不能自动重绘的地方我们可以人为的调用invalidate函数或updateallviews函数

说明8:在如OnDraw等函数中传递一个指向CDC 对象的指针

如OnDraw(CDC*pDC);

使用构造函数构建对象

一般不构造CDC对象

在CWnd类的OnPaint函数中,定义CPaintDC对象

CPaintDC dc(this);

在CWnd类的其它函数中,定义CClientDC和CWindowDC的对象

CClientDC dc(this);

CWindowDC dc(this);

说明9:

      当窗口的某个区域需要重绘时激发窗口重绘消息WM_PAINT,相应消息处理      函数CWnd::OnPaint将被调用。CPaintDC一般只用于OnPaint函数中,在处理完窗口重绘后, CPaintDC对象的析构函数把WM_PAINT消息从消息队列中清除,避免不断地重绘操作。坐标原点(0,0)是客户区的左上角。

      CClientDC用于特定窗口客户区(窗口中除边框、标题栏、菜单栏、状态栏外的中间部分)的输出,其构造函数中包含了GetDC,析构函数中包含了ReleaseDC,不需要显式释放DC资源。一般用于响应非重绘消息(如键盘和鼠标消息)的绘图操作。坐标原点(0,0)是客户区的左上角。

      CWindowDC整个应用程序窗口上画图,而CClientDC和CPaintDC只能在客户区绘制图形;除非要自己绘制窗口边框和按钮,否则一般不用它。坐标原点(0,0)是屏幕的左上角。

说明:10:颜色填充工具

      CPen类:GDI 画笔,用于画线。默认的画笔用于绘制与一个像素等宽的黑色实线。

      CBrush类:GDI 画刷,用来填充一个封闭图形对象(如矩形、圆形)的内部区域,默认的画刷颜色是白色。

      CFont类:GDI字体,用来绘制文本,可设置文字的大小、是否加粗、是否斜体、是否加下划线等。

      CBitmap类:GDI 位图,用于填充区域。

      CPalette类:GDI 调色板,包含系统可用的色彩信息,是应用程序和彩色输出设备环境(如显示器)的接口。

      CRgn类:GDI 区域,用于设备环境(通常是窗口)内的区域操作,通常和CDC类中与裁剪(clipping)有关的成员函数配合使用。

 

 

备注:

备注1:这个全局对象一产生,便执行其构造函数,因为并没有定义CwingApp构造函数,所以即执行CWinApp类的构造函数,该函数定义于APPCORE.CPP中,CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。

备注2:    // 注册应用程序的文档模板。文档模板

        // 将用作文档、框架窗口和视图之间的连接

CSingleDocTemplate*pDocTemplate;

        pDocTemplate = newCSingleDocTemplate(

       IDR_MAINFRAME,

       RUNTIME_CLASS(CeagleDoc),

       RUNTIME_CLASS(CMainFrame),       // 主SDI 框架窗口

RUNTIME_CLASS(CeagleView));//当一个文档对应多个视图时可再建立一个模板进行再绑定

        if(!pDocTemplate)

       return FALSE;

       AddDocTemplate(pDocTemplate);

备注3:MFC早已准备好并由链接器直接加到应用程序代码中了,原来她在APPMODUL.CPP里面,好,我们就认为当theApp配置完成后,程序就转到APPMODUL.CPP来了。那执行什么呢?看看下面从APPMODUL.CPP摘出来的代码:

     extern "C" int WINAPI

     _tWinMain(HINSTANCE hInstance, HINSTANCEhPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
     {
         // call shared/exportedWinMain
         return AfxWinMain(hInstance,hPrevInstance, lpCmdLine, nCmdShow);
     }

备注4:_tWinMain函数返回值是AfxWinMain函数的返回值,AfxWinMain函数定义于WINMAIN.CPP第21行,稍加整理,去芜存菁,就可以看到这个“程序进入点”主要做些什么事:

     int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCEhPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
     {
         int nReturnCode = -1;
         CWinApp* pApp = AfxGetApp(); //获得cwingdoc的指针

         AfxWinInit(hInstance,hPrevInstance, lpCmdLine, nCmdShow);

        pApp->InitApplication();
         pApp->InitInstance()
         nReturnCode = pApp->Run();

         AfxWinTerm();
         return nReturnCode;
     }

备注5:AfxGetApp()函数是取得CMyWinApp对象指针,故上面函数第6至8行相当于调用:

     CMyWinApp::InitApplication();
     CMyWinApp::InitInstance()
     CMyWinApp::Run();

     因而导致调用:
     CWinApp::InitApplication();   //因为 CMyWinApp 并没有改写InitApplication
     CMyWinApp::InitInstance()     //因为 CMyWinApp 改写了InitInstance
    CWinApp::Run();              //因为 CMyWinApp 并没有改写 Run

备注6:现在已经来到CWinApp::InitInstance了,该函数先new一个CMyFrameWnd对象,从而产生主窗口。在创建CMyFrameWnd对之前,要先执行构造函数CMyFrameWnd::CMyFrameWnd(),该函数用Create函数产生窗口:

         CMyFrameWnd::CMyFrameWnd()
         {
            Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault, NULL,"MainMenu");
         }

     其中Create是CFrameWnd的成员函数,它将产生一个窗口,用过SDK编程序的朋友都知道,要创建主窗口时要先注册一个窗口类,规定窗口的属性等,但,这里使用哪一个窗口类呢?Create函数第一个参数(其它参数请参考MSDN或《深出浅出MFC》详解)指定窗口类设为NULL又是什么意思啊?意思是要以MFC内建的空中类产生一个标准的外框窗口,但,我们的程序一般都没有注册任何窗口类呀!噢,Create函数在产生窗口之前会引发窗口类的注册操作。

     让我们先挖出Create函数都做了些什么操作,Create函数定义于WINFRM.CPP的第538行(在此我就不把代码Copy过来了,你自己打开出来看吧),函数在562行调用CreateEx函数,由于CreateEx是CWnd的成员函数,而CFrameWnd是从CWnd继而来,故将调用CWnd::CreateEx。此函数定义于WINCORE.CPP第665行,下面是部分代码:

     BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTRlpszClassName,

 

Reference:

                            http://zhidao.baidu.com/question/469539277.html

                            http://wenku.baidu.com/view/0787810c763231126edb1148.html

                            http://blog.csdn.net/sgs1018/article/details/8902648

                            http://zhidao.baidu.com/question/319088486.html

                            http://wenku.baidu.com/view/d8b77bd4b9f3f90f76c61bbd.html

                            http://zhidao.baidu.com/question/246011777.html

                            http://blog.csdn.net/sgs1018/article/details/8902648

                            

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值